This commit is contained in:
edideaur 2026-03-06 22:59:01 +00:00
parent a00c95555b
commit 2c5afc220d

View file

@ -1,6 +1,58 @@
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(key, date, region, service, stringToSign) {
const kDate = await hmac(new TextEncoder().encode('AWS4' + key), new TextEncoder().encode(date));
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) {
const now = new Date();
const amzDate = now
.toISOString()
.replace(/[:-]|\.\d{3}/g, '')
.slice(0, 8);
const date = amzDate;
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 = `${date}/${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(env.R2_SECRET_ACCESS_KEY, date, region, service, stringToSign);
return `AWS4-HMAC-SHA256 Credential=${env.R2_ACCESS_KEY_ID}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${sig}`;
}
export async function onRequest(context) {
const { request, env } = context;
@ -12,7 +64,7 @@ export async function onRequest(context) {
return jsonError('Method not allowed', 405);
}
const useR2 = env.R2_BUCKET;
const useR2 = env.R2_ENABLED === 'true';
try {
const contentType = request.headers.get('content-type') || '';
@ -47,9 +99,43 @@ export async function onRequest(context) {
let url;
if (useR2) {
const key = `${Date.now()}-${fileName}`;
await env.R2_BUCKET.put(key, file, { httpMetadata: { contentType: fileType } });
url = `${R2_PUBLIC_URL}/${key}`;
try {
const key = `${Date.now()}-${fileName}`;
const now = new Date();
const amzDate = 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);
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');