Delete functions/upload.js
This commit is contained in:
parent
535153d778
commit
a5a893c1ef
1 changed files with 0 additions and 195 deletions
|
|
@ -1,195 +0,0 @@
|
||||||
const API_URL = 'https://catbox.moe/user/api.php';
|
|
||||||
const R2_PUBLIC_URL = 'https://cucks.qzz.io';
|
|
||||||
|
|
||||||
const R2_ENDPOINT = 'https://faae2f5c0a232c7f3733ef597c55bd69.r2.cloudflarestorage.com';
|
|
||||||
const R2_BUCKET = 'monochrome-image-uploads';
|
|
||||||
|
|
||||||
async function hmac(key, data) {
|
|
||||||
const cryptoKey = await crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-1' }, false, ['sign']);
|
|
||||||
return new Uint8Array(await crypto.subtle.sign('HMAC', cryptoKey, data));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sha256(data) {
|
|
||||||
return new Uint8Array(await crypto.subtle.digest('SHA-256', data));
|
|
||||||
}
|
|
||||||
|
|
||||||
function buf2hex(buffer) {
|
|
||||||
return Array.from(buffer)
|
|
||||||
.map((b) => b.toString(16).padStart(2, '0'))
|
|
||||||
.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function signature(secretKey, dateStamp, region, service, stringToSign) {
|
|
||||||
const kDate = await hmac(new TextEncoder().encode('AWS4' + secretKey), new TextEncoder().encode(dateStamp));
|
|
||||||
const kRegion = await hmac(kDate, new TextEncoder().encode(region));
|
|
||||||
const kService = await hmac(kRegion, new TextEncoder().encode(service));
|
|
||||||
const kSigning = await hmac(kService, new TextEncoder().encode('aws4_request'));
|
|
||||||
const sig = await hmac(kSigning, new TextEncoder().encode(stringToSign));
|
|
||||||
return buf2hex(sig);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createSignature(method, path, headers, payloadHash, accessKeyId, secretAccessKey, amzDate, dateStamp) {
|
|
||||||
const region = 'auto';
|
|
||||||
const service = 's3';
|
|
||||||
|
|
||||||
const signedHeaders = Object.keys(headers).sort().join(';');
|
|
||||||
const canonicalHeaders =
|
|
||||||
Object.entries(headers)
|
|
||||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
||||||
.map(([k, v]) => `${k.toLowerCase()}:${v}`)
|
|
||||||
.join('\n') + '\n';
|
|
||||||
|
|
||||||
const canonicalRequest = `${method}\n${path}\n\n${canonicalHeaders}\n${signedHeaders}\n${payloadHash}`;
|
|
||||||
const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`;
|
|
||||||
const stringToSign = `AWS4-HMAC-SHA256\n${amzDate}\n${credentialScope}\n${buf2hex(await sha256(new TextEncoder().encode(canonicalRequest)))}`;
|
|
||||||
|
|
||||||
const sig = await signature(secretAccessKey, dateStamp, region, service, stringToSign);
|
|
||||||
return `AWS4-HMAC-SHA256 Credential=${accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${sig}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function onRequest(context) {
|
|
||||||
const { request, env } = context;
|
|
||||||
|
|
||||||
if (request.method === 'OPTIONS') {
|
|
||||||
return new Response(null, { status: 204, headers: corsHeaders() });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.method !== 'POST') {
|
|
||||||
return jsonError('Method not allowed', 405);
|
|
||||||
}
|
|
||||||
|
|
||||||
const useR2 = env.R2_ENABLED === 'true';
|
|
||||||
|
|
||||||
try {
|
|
||||||
const contentType = request.headers.get('content-type') || '';
|
|
||||||
let file;
|
|
||||||
let fileName;
|
|
||||||
let fileType;
|
|
||||||
|
|
||||||
if (contentType.includes('application/json')) {
|
|
||||||
const body = await request.json();
|
|
||||||
if (!body.fileUrl) return jsonError('No fileUrl provided', 400);
|
|
||||||
|
|
||||||
const res = await fetch(body.fileUrl);
|
|
||||||
if (!res.ok) throw new Error('Failed to fetch remote file');
|
|
||||||
|
|
||||||
file = await res.arrayBuffer();
|
|
||||||
fileName = body.fileName || body.fileUrl.split('/').pop();
|
|
||||||
fileType = res.headers.get('content-type') || 'application/octet-stream';
|
|
||||||
} else {
|
|
||||||
const form = await request.formData();
|
|
||||||
const uploaded = form.get('file');
|
|
||||||
if (!uploaded) return jsonError('No file provided', 400);
|
|
||||||
|
|
||||||
if (uploaded.size > 10 * 1024 * 1024) {
|
|
||||||
return jsonError('File exceeds 10MB', 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
file = await uploaded.arrayBuffer();
|
|
||||||
fileName = uploaded.name;
|
|
||||||
fileType = uploaded.type || 'application/octet-stream';
|
|
||||||
}
|
|
||||||
|
|
||||||
let url;
|
|
||||||
|
|
||||||
if (useR2) {
|
|
||||||
try {
|
|
||||||
const key = `${Date.now()}-${fileName}`;
|
|
||||||
const now = new Date();
|
|
||||||
const amzDate =
|
|
||||||
now
|
|
||||||
.toISOString()
|
|
||||||
.replace(/[:-]|\.\d{3}/g, '')
|
|
||||||
.slice(0, 15) + 'Z';
|
|
||||||
const dateStamp = now
|
|
||||||
.toISOString()
|
|
||||||
.replace(/[:-]|\.\d{3}/g, '')
|
|
||||||
.slice(0, 8);
|
|
||||||
const payloadHash = buf2hex(await sha256(file));
|
|
||||||
|
|
||||||
const host = new URL(R2_ENDPOINT).host;
|
|
||||||
const headers = {
|
|
||||||
'Content-Type': fileType,
|
|
||||||
'Content-Length': file.byteLength,
|
|
||||||
'x-amz-date': amzDate,
|
|
||||||
'x-amz-content-sha256': payloadHash,
|
|
||||||
Host: host,
|
|
||||||
};
|
|
||||||
|
|
||||||
const auth = await createSignature(
|
|
||||||
'PUT',
|
|
||||||
`/${R2_BUCKET}/${key}`,
|
|
||||||
headers,
|
|
||||||
payloadHash,
|
|
||||||
env.R2_ACCESS_KEY_ID,
|
|
||||||
env.R2_SECRET_ACCESS_KEY,
|
|
||||||
amzDate,
|
|
||||||
dateStamp
|
|
||||||
);
|
|
||||||
headers['Authorization'] = auth;
|
|
||||||
|
|
||||||
const res = await fetch(`${R2_ENDPOINT}/${R2_BUCKET}/${key}`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers,
|
|
||||||
body: new Uint8Array(file),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
const err = await res.text();
|
|
||||||
throw new Error(`R2 error: ${res.status} - ${err}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
url = `${R2_PUBLIC_URL}/${key}`;
|
|
||||||
} catch (r2Err) {
|
|
||||||
console.error('R2 upload error:', r2Err);
|
|
||||||
return jsonError(`R2 upload failed: ${r2Err.message}`, 500);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('reqtype', 'fileupload');
|
|
||||||
formData.append('fileToUpload', new Blob([file], { type: fileType }), fileName);
|
|
||||||
|
|
||||||
const response = await fetch(API_URL, {
|
|
||||||
method: 'POST',
|
|
||||||
body: formData,
|
|
||||||
});
|
|
||||||
|
|
||||||
const responseText = await response.text();
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`Upload failed: ${responseText}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
url = responseText.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsonResponse({
|
|
||||||
success: true,
|
|
||||||
url: url,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
return jsonError(err.message, 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function jsonResponse(obj, status = 200) {
|
|
||||||
return new Response(JSON.stringify(obj), {
|
|
||||||
status,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
...corsHeaders(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function jsonError(message, status) {
|
|
||||||
return jsonResponse({ success: false, error: message }, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
function corsHeaders() {
|
|
||||||
return {
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
||||||
'Access-Control-Allow-Headers': '*',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue