mirror of
https://example.com
synced 2024-11-22 11:26:38 +09:00
fix (backend): improve URL check
13ea67bee4
da12d5b079
Co-authored-by: naskya <m@naskya.net>
This commit is contained in:
parent
e6e8aac224
commit
79533ceec9
4 changed files with 46 additions and 1 deletions
|
@ -8,10 +8,15 @@ import chalk from "chalk";
|
|||
import Logger from "@/services/logger.js";
|
||||
import IPCIDR from "ip-cidr";
|
||||
import PrivateIp from "private-ip";
|
||||
import { isValidUrl } from "./is-valid-url.js";
|
||||
|
||||
const pipeline = util.promisify(stream.pipeline);
|
||||
|
||||
export async function downloadUrl(url: string, path: string): Promise<void> {
|
||||
if (!isValidUrl(url)) {
|
||||
throw new StatusError("Invalid URL", 400);
|
||||
}
|
||||
|
||||
const logger = new Logger("download");
|
||||
|
||||
logger.info(`Downloading ${chalk.cyan(url)} ...`);
|
||||
|
@ -44,6 +49,12 @@ export async function downloadUrl(url: string, path: string): Promise<void> {
|
|||
limit: 0,
|
||||
},
|
||||
})
|
||||
.on("redirect", (res: Got.Response, opts: Got.NormalizedOptions) => {
|
||||
if (!isValidUrl(opts.url)) {
|
||||
logger.warn(`Invalid URL: ${opts.url}`);
|
||||
req.destroy();
|
||||
}
|
||||
})
|
||||
.on("response", (res: Got.Response) => {
|
||||
if (
|
||||
(process.env.NODE_ENV === "production" ||
|
||||
|
|
|
@ -5,6 +5,7 @@ import CacheableLookup from "cacheable-lookup";
|
|||
import fetch from "node-fetch";
|
||||
import { HttpProxyAgent, HttpsProxyAgent } from "hpagent";
|
||||
import config from "@/config/index.js";
|
||||
import { isValidUrl } from "./is-valid-url.js";
|
||||
|
||||
export async function getJson(
|
||||
url: string,
|
||||
|
@ -58,6 +59,10 @@ export async function getResponse(args: {
|
|||
timeout?: number;
|
||||
size?: number;
|
||||
}) {
|
||||
if (!isValidUrl(args.url)) {
|
||||
throw new StatusError("Invalid URL", 400);
|
||||
}
|
||||
|
||||
const timeout = args.timeout || 10 * 1000;
|
||||
|
||||
const controller = new AbortController();
|
||||
|
@ -83,6 +88,10 @@ export async function getResponse(args: {
|
|||
);
|
||||
}
|
||||
|
||||
if (res.redirected && !isValidUrl(res.url)) {
|
||||
throw new StatusError("Invalid URL", 400);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
20
packages/backend/src/misc/is-valid-url.ts
Normal file
20
packages/backend/src/misc/is-valid-url.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
export function isValidUrl(url: string | URL | undefined): boolean {
|
||||
if (process.env.NODE_ENV !== "production") return true;
|
||||
|
||||
try {
|
||||
if (url == null) return false;
|
||||
|
||||
const u = typeof url === "string" ? new URL(url) : url;
|
||||
if (!u.protocol.match(/^https?:$/) || u.hostname === "unix") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (u.port !== "" && !["80", "443"].includes(u.port)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
import config from "@/config/index.js";
|
||||
import { getUserKeypair } from "@/misc/keypair-store.js";
|
||||
import type { User, ILocalUser } from "@/models/entities/user.js";
|
||||
import { getResponse } from "@/misc/fetch.js";
|
||||
import { StatusError, getResponse } from "@/misc/fetch.js";
|
||||
import { createSignedPost, createSignedGet } from "./ap-request.js";
|
||||
import type { Response } from "node-fetch";
|
||||
import type { IObject } from "./type.js";
|
||||
import { isValidUrl } from "@/misc/is-valid-url.js";
|
||||
|
||||
export default async (user: { id: User["id"] }, url: string, object: any) => {
|
||||
const body = JSON.stringify(object);
|
||||
|
@ -37,6 +38,10 @@ export default async (user: { id: User["id"] }, url: string, object: any) => {
|
|||
* @param url URL to fetch
|
||||
*/
|
||||
export async function apGet(url: string, user?: ILocalUser): Promise<IObject> {
|
||||
if (!isValidUrl(url)) {
|
||||
throw new StatusError("Invalid URL", 400);
|
||||
}
|
||||
|
||||
let res: Response;
|
||||
|
||||
if (user != null) {
|
||||
|
|
Loading…
Reference in a new issue