This commit is contained in:
goro 2026-05-05 18:43:40 +03:00
parent cffcb36b2a
commit bc7b0e6773
5 changed files with 3103 additions and 2 deletions

View File

@ -4,13 +4,16 @@
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "wrangler dev", "dev": "wrangler dev",
"deploy": "wrangler deploy" "deploy": "wrangler deploy",
"test": "vitest run"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.600.0", "@aws-sdk/client-s3": "^3.600.0",
"@aws-sdk/s3-request-presigner": "^3.600.0" "@aws-sdk/s3-request-presigner": "^3.600.0"
}, },
"devDependencies": { "devDependencies": {
"dotenv": "^16.4.0",
"vitest": "^2.0.0",
"wrangler": "^3.60.0" "wrangler": "^3.60.0"
} }
} }

3022
cloudflare-worker/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -55,6 +55,8 @@ export default {
accessKeyId: env.R2_ACCESS_KEY_ID, accessKeyId: env.R2_ACCESS_KEY_ID,
secretAccessKey: env.R2_SECRET_ACCESS_KEY, secretAccessKey: env.R2_SECRET_ACCESS_KEY,
}, },
requestChecksumCalculation: 'WHEN_REQUIRED',
responseChecksumValidation: 'WHEN_REQUIRED',
}); });
try { try {
@ -63,7 +65,10 @@ export default {
Key: key, Key: key,
}); });
const presignedUrl = await getSignedUrl(client, command, { expiresIn: 3600 }); const presignedUrl = await getSignedUrl(client, command, {
expiresIn: 3600,
unhoistableHeaders: new Set(['x-amz-content-sha256']),
});
return json({ url: presignedUrl, key }, 200, cors); return json({ url: presignedUrl, key }, 200, cors);
} catch (err) { } catch (err) {

View File

@ -0,0 +1,64 @@
import { describe, it, expect } from 'vitest';
import { readFileSync } from 'fs';
import { resolve } from 'path';
import { config } from 'dotenv';
config({ path: resolve(__dirname, '../../.env') });
const WORKER_URL = process.env.PUBLIC_WORKER_URL;
const UPLOAD_SECRET = process.env.PUBLIC_UPLOAD_SECRET;
const IMAGE = readFileSync(resolve(__dirname, '../../pictures/image2.png'));
describe('Worker auth', () => {
it('rejects request with no auth header', async () => {
const res = await fetch(`${WORKER_URL}/presign?filename=image2.png`);
expect(res.status).toBe(401);
});
it('rejects request with wrong secret', async () => {
const res = await fetch(`${WORKER_URL}/presign?filename=image2.png`, {
headers: { Authorization: 'Bearer wrong-secret' },
});
expect(res.status).toBe(401);
});
});
describe('Presign endpoint', () => {
it('returns 400 when filename is missing', async () => {
const res = await fetch(`${WORKER_URL}/presign`, {
headers: { Authorization: `Bearer ${UPLOAD_SECRET}` },
});
expect(res.status).toBe(400);
});
it('returns a presigned URL and key', async () => {
const res = await fetch(`${WORKER_URL}/presign?filename=image2.png`, {
headers: { Authorization: `Bearer ${UPLOAD_SECRET}` },
});
expect(res.status).toBe(200);
const body = await res.json();
expect(body.url).toMatch(/^https:\/\/.+r2\.cloudflarestorage\.com/);
expect(body.key).toMatch(/^videos\/.+image2\.png$/);
});
});
describe('R2 upload', () => {
it('uploads image2.png successfully', async () => {
const presignRes = await fetch(`${WORKER_URL}/presign?filename=image2.png`, {
headers: { Authorization: `Bearer ${UPLOAD_SECRET}` },
});
const { url } = await presignRes.json();
const uploadRes = await fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'image/png',
'x-amz-content-sha256': 'UNSIGNED-PAYLOAD',
},
body: IMAGE,
});
expect(uploadRes.status).toBe(200);
});
});

View File

@ -0,0 +1,7 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
testTimeout: 30000,
},
});