mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-08-05 06:50:10 +00:00
Revert redirect guard in backup uploader
This commit is contained in:
@@ -241,37 +241,18 @@ function webDavFullPath(config: WebDavBackupDestination, relativePath: string):
|
|||||||
return buildJoinedPath(config.remotePath, normalizeRelativePath(relativePath));
|
return buildJoinedPath(config.remotePath, normalizeRelativePath(relativePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchBackupEndpoint(
|
|
||||||
input: string | URL,
|
|
||||||
init: RequestInit,
|
|
||||||
label: string
|
|
||||||
): Promise<Response> {
|
|
||||||
const url = normalizeBackupEndpointUrl(input.toString(), label);
|
|
||||||
const response = await fetch(url, {
|
|
||||||
...init,
|
|
||||||
redirect: 'manual',
|
|
||||||
});
|
|
||||||
if (response.status >= 300 && response.status < 400) {
|
|
||||||
throw new Error(`${label} must not redirect`);
|
|
||||||
}
|
|
||||||
if (response.redirected) {
|
|
||||||
throw new Error(`${label} must not redirect`);
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function ensureWebDavDirectory(baseUrl: string, directoryPath: string, authHeader: string): Promise<void> {
|
async function ensureWebDavDirectory(baseUrl: string, directoryPath: string, authHeader: string): Promise<void> {
|
||||||
const segments = trimSlashes(directoryPath).split('/').filter(Boolean);
|
const segments = trimSlashes(directoryPath).split('/').filter(Boolean);
|
||||||
let current = '';
|
let current = '';
|
||||||
for (const segment of segments) {
|
for (const segment of segments) {
|
||||||
current = buildJoinedPath(current, segment);
|
current = buildJoinedPath(current, segment);
|
||||||
const url = buildWebDavUrl(baseUrl, current);
|
const url = buildWebDavUrl(baseUrl, current);
|
||||||
const response = await fetchBackupEndpoint(url, {
|
const response = await fetch(url, {
|
||||||
method: 'MKCOL',
|
method: 'MKCOL',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: authHeader,
|
Authorization: authHeader,
|
||||||
},
|
},
|
||||||
}, 'WebDAV directory URL');
|
});
|
||||||
if ([200, 201, 204, 405].includes(response.status)) continue;
|
if ([200, 201, 204, 405].includes(response.status)) continue;
|
||||||
throw new Error(`WebDAV directory creation failed: ${response.status}`);
|
throw new Error(`WebDAV directory creation failed: ${response.status}`);
|
||||||
}
|
}
|
||||||
@@ -289,12 +270,12 @@ async function ensureWebDavDirectoryCached(
|
|||||||
current = buildJoinedPath(current, segment);
|
current = buildJoinedPath(current, segment);
|
||||||
if (ensuredDirectories.has(current)) continue;
|
if (ensuredDirectories.has(current)) continue;
|
||||||
const url = buildWebDavUrl(baseUrl, current);
|
const url = buildWebDavUrl(baseUrl, current);
|
||||||
const response = await fetchBackupEndpoint(url, {
|
const response = await fetch(url, {
|
||||||
method: 'MKCOL',
|
method: 'MKCOL',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: authHeader,
|
Authorization: authHeader,
|
||||||
},
|
},
|
||||||
}, 'WebDAV directory URL');
|
});
|
||||||
if ([200, 201, 204, 405].includes(response.status)) {
|
if ([200, 201, 204, 405].includes(response.status)) {
|
||||||
ensuredDirectories.add(current);
|
ensuredDirectories.add(current);
|
||||||
continue;
|
continue;
|
||||||
@@ -322,7 +303,7 @@ async function putToWebDav(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetchBackupEndpoint(buildWebDavUrl(config.baseUrl, remoteFilePath), {
|
const response = await fetch(buildWebDavUrl(config.baseUrl, remoteFilePath), {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: authHeader,
|
Authorization: authHeader,
|
||||||
@@ -330,7 +311,7 @@ async function putToWebDav(
|
|||||||
'Content-Length': String(bytes.byteLength),
|
'Content-Length': String(bytes.byteLength),
|
||||||
},
|
},
|
||||||
body: bytes,
|
body: bytes,
|
||||||
}, 'WebDAV upload URL');
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`WebDAV upload failed: ${response.status}`);
|
throw new Error(`WebDAV upload failed: ${response.status}`);
|
||||||
@@ -359,7 +340,7 @@ async function listWebDavEntries(config: WebDavBackupDestination, relativePath:
|
|||||||
const currentPath = normalizeRelativePath(relativePath);
|
const currentPath = normalizeRelativePath(relativePath);
|
||||||
const targetFullPath = webDavFullPath(config, currentPath);
|
const targetFullPath = webDavFullPath(config, currentPath);
|
||||||
const authHeader = toBasicAuthHeader(config.username, config.password);
|
const authHeader = toBasicAuthHeader(config.username, config.password);
|
||||||
const response = await fetchBackupEndpoint(buildWebDavUrl(config.baseUrl, targetFullPath), {
|
const response = await fetch(buildWebDavUrl(config.baseUrl, targetFullPath), {
|
||||||
method: 'PROPFIND',
|
method: 'PROPFIND',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: authHeader,
|
Authorization: authHeader,
|
||||||
@@ -367,7 +348,7 @@ async function listWebDavEntries(config: WebDavBackupDestination, relativePath:
|
|||||||
'Content-Type': 'application/xml; charset=utf-8',
|
'Content-Type': 'application/xml; charset=utf-8',
|
||||||
},
|
},
|
||||||
body: `<?xml version="1.0" encoding="utf-8"?><propfind xmlns="DAV:"><prop><resourcetype/><getcontentlength/><getlastmodified/></prop></propfind>`,
|
body: `<?xml version="1.0" encoding="utf-8"?><propfind xmlns="DAV:"><prop><resourcetype/><getcontentlength/><getlastmodified/></prop></propfind>`,
|
||||||
}, 'WebDAV listing URL');
|
});
|
||||||
if (response.status === 404) {
|
if (response.status === 404) {
|
||||||
return {
|
return {
|
||||||
provider: 'webdav',
|
provider: 'webdav',
|
||||||
@@ -427,12 +408,12 @@ async function downloadFromWebDav(config: WebDavBackupDestination, relativePath:
|
|||||||
}
|
}
|
||||||
const authHeader = toBasicAuthHeader(config.username, config.password);
|
const authHeader = toBasicAuthHeader(config.username, config.password);
|
||||||
const remotePath = webDavFullPath(config, normalized);
|
const remotePath = webDavFullPath(config, normalized);
|
||||||
const response = await fetchBackupEndpoint(buildWebDavUrl(config.baseUrl, remotePath), {
|
const response = await fetch(buildWebDavUrl(config.baseUrl, remotePath), {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: authHeader,
|
Authorization: authHeader,
|
||||||
},
|
},
|
||||||
}, 'WebDAV download URL');
|
});
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`WebDAV download failed: ${response.status}`);
|
throw new Error(`WebDAV download failed: ${response.status}`);
|
||||||
}
|
}
|
||||||
@@ -448,12 +429,12 @@ async function downloadFromWebDav(config: WebDavBackupDestination, relativePath:
|
|||||||
async function deleteFromWebDav(config: WebDavBackupDestination, relativePath: string): Promise<void> {
|
async function deleteFromWebDav(config: WebDavBackupDestination, relativePath: string): Promise<void> {
|
||||||
const authHeader = toBasicAuthHeader(config.username, config.password);
|
const authHeader = toBasicAuthHeader(config.username, config.password);
|
||||||
const remotePath = webDavFullPath(config, relativePath);
|
const remotePath = webDavFullPath(config, relativePath);
|
||||||
const response = await fetchBackupEndpoint(buildWebDavUrl(config.baseUrl, remotePath), {
|
const response = await fetch(buildWebDavUrl(config.baseUrl, remotePath), {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: authHeader,
|
Authorization: authHeader,
|
||||||
},
|
},
|
||||||
}, 'WebDAV delete URL');
|
});
|
||||||
if (!response.ok && response.status !== 404) {
|
if (!response.ok && response.status !== 404) {
|
||||||
throw new Error(`WebDAV delete failed: ${response.status}`);
|
throw new Error(`WebDAV delete failed: ${response.status}`);
|
||||||
}
|
}
|
||||||
@@ -466,12 +447,12 @@ async function existsInWebDav(config: WebDavBackupDestination, relativePath: str
|
|||||||
async function statWebDavFile(config: WebDavBackupDestination, relativePath: string): Promise<RemoteBackupFileStat | null> {
|
async function statWebDavFile(config: WebDavBackupDestination, relativePath: string): Promise<RemoteBackupFileStat | null> {
|
||||||
const authHeader = toBasicAuthHeader(config.username, config.password);
|
const authHeader = toBasicAuthHeader(config.username, config.password);
|
||||||
const remotePath = webDavFullPath(config, relativePath);
|
const remotePath = webDavFullPath(config, relativePath);
|
||||||
const response = await fetchBackupEndpoint(buildWebDavUrl(config.baseUrl, remotePath), {
|
const response = await fetch(buildWebDavUrl(config.baseUrl, remotePath), {
|
||||||
method: 'HEAD',
|
method: 'HEAD',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: authHeader,
|
Authorization: authHeader,
|
||||||
},
|
},
|
||||||
}, 'WebDAV stat URL');
|
});
|
||||||
if (response.status === 404) return null;
|
if (response.status === 404) return null;
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`WebDAV existence check failed: ${response.status}`);
|
throw new Error(`WebDAV existence check failed: ${response.status}`);
|
||||||
@@ -538,7 +519,7 @@ async function signedS3Request(
|
|||||||
config.region || 'auto'
|
config.region || 'auto'
|
||||||
);
|
);
|
||||||
|
|
||||||
return fetchBackupEndpoint(url, {
|
return fetch(url, {
|
||||||
method,
|
method,
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: authorization,
|
Authorization: authorization,
|
||||||
@@ -547,7 +528,7 @@ async function signedS3Request(
|
|||||||
...(method === 'PUT' ? { 'Content-Type': headers['content-type'] } : {}),
|
...(method === 'PUT' ? { 'Content-Type': headers['content-type'] } : {}),
|
||||||
},
|
},
|
||||||
body,
|
body,
|
||||||
}, 'S3 endpoint URL');
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function putToS3(
|
async function putToS3(
|
||||||
|
|||||||
Reference in New Issue
Block a user