From 038fa3b301794050ec7e59325aa00f25b3ce3257 Mon Sep 17 00:00:00 2001 From: Fred Date: Thu, 14 Mar 2024 00:33:26 +0800 Subject: [PATCH] fix: add webdav request filter --- app/api/webdav/[...path]/route.ts | 103 ++++++++++++++++++++++++++++++ app/utils/cloud/upstash.ts | 2 +- app/utils/cloud/webdav.ts | 12 ++-- 3 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 app/api/webdav/[...path]/route.ts diff --git a/app/api/webdav/[...path]/route.ts b/app/api/webdav/[...path]/route.ts new file mode 100644 index 000000000..1ddd37761 --- /dev/null +++ b/app/api/webdav/[...path]/route.ts @@ -0,0 +1,103 @@ +import { NextRequest, NextResponse } from "next/server"; +import { STORAGE_KEY } from "../../../constant"; +async function handle( + req: NextRequest, + { params }: { params: { path: string[] } }, +) { + if (req.method === "OPTIONS") { + return NextResponse.json({ body: "OK" }, { status: 200 }); + } + const folder = STORAGE_KEY; + const fileName = `${folder}/backup.json`; + + const requestUrl = new URL(req.url); + const endpoint = requestUrl.searchParams.get("endpoint"); + + const [protocol, ...subpath] = params.path; + + const endpointPath = subpath.join("/"); + + // only allow MKCOL, GET, PUT + if (req.method !== "MKCOL" && req.method !== "GET" && req.method !== "PUT") { + return NextResponse.json( + { + error: true, + msg: "you are not allowed to request " + params.path.join("/"), + }, + { + status: 403, + }, + ); + } + + // for MKCOL request, only allow request ${folder} + if (req.method == "MKCOL" && !endpointPath.endsWith(folder)) { + return NextResponse.json( + { + error: true, + msg: "you are not allowed to request " + params.path.join("/"), + }, + { + status: 403, + }, + ); + } + + // for GET request, only allow request ending with fileName + if (req.method == "GET" && !endpointPath.endsWith(fileName)) { + return NextResponse.json( + { + error: true, + msg: "you are not allowed to request " + params.path.join("/"), + }, + { + status: 403, + }, + ); + } + + // for PUT request, only allow request ending with fileName + if (req.method == "PUT" && !endpointPath.endsWith(fileName)) { + return NextResponse.json( + { + error: true, + msg: "you are not allowed to request " + params.path.join("/"), + }, + { + status: 403, + }, + ); + } + + const targetUrl = `${protocol}://${endpoint + endpointPath}`; + + const method = req.headers.get("method") ?? undefined; + const shouldNotHaveBody = ["get", "head"].includes( + method?.toLowerCase() ?? "", + ); + + const fetchOptions: RequestInit = { + headers: { + authorization: req.headers.get("authorization") ?? "", + }, + body: shouldNotHaveBody ? null : req.body, + method, + // @ts-ignore + duplex: "half", + }; + + const fetchResult = await fetch(targetUrl, fetchOptions); + + console.log("[Any Proxy]", targetUrl, { + status: fetchResult.status, + statusText: fetchResult.statusText, + }); + + return fetchResult; +} + +export const POST = handle; +export const GET = handle; +export const OPTIONS = handle; + +export const runtime = "edge"; diff --git a/app/utils/cloud/upstash.ts b/app/utils/cloud/upstash.ts index 1739b5a05..02af76633 100644 --- a/app/utils/cloud/upstash.ts +++ b/app/utils/cloud/upstash.ts @@ -94,7 +94,7 @@ export function createUpstashClient(store: SyncStore) { path = path.slice(1); } - let url = new URL("/api/" + path); + let url = new URL("/api/upstash/" + path); // add query params url.searchParams.append("endpoint", config.endpoint); diff --git a/app/utils/cloud/webdav.ts b/app/utils/cloud/webdav.ts index 3a1553c10..9efa80c69 100644 --- a/app/utils/cloud/webdav.ts +++ b/app/utils/cloud/webdav.ts @@ -60,16 +60,18 @@ export function createWebDavClient(store: SyncStore) { }; }, path(path: string) { - let url = config.endpoint; - - if (!url.endsWith("/")) { - url += "/"; + if (!path.endsWith("/")) { + path += "/"; } - if (path.startsWith("/")) { path = path.slice(1); } + let url = new URL("/api/webdav/" + path); + + // add query params + url.searchParams.append("endpoint", config.endpoint); + return url + path; }, };