feat(ext/sw): upload_attachment + download_attachment router handlers
Both popup-only. upload_attachment encrypts via WASM, putBlobs via GitHost (Git Data API fallback for >900 KB), persists the AttachmentRef on the item + manifest summaries. Duplicate uploads (same content = same id from sha256) return the existing ref without a re-upload. download_attachment reads + decrypts and returns plaintext bytes for the popup to wrap in a Blob. 4 new router tests (accept × 2, reject × 2). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -732,3 +732,49 @@ describe('get_vault_settings / update_vault_settings', () => {
|
||||
expect(res).toEqual({ ok: false, error: 'unauthorized_sender' });
|
||||
});
|
||||
});
|
||||
|
||||
// --- upload_attachment / download_attachment (γ₁ Task 6) ---
|
||||
|
||||
describe('upload_attachment / download_attachment', () => {
|
||||
it('upload_attachment accepted from popup', async () => {
|
||||
const state = makeState();
|
||||
const result = await route(
|
||||
{ type: 'upload_attachment', itemId: 'abc', filename: 'f.pdf', mimeType: 'application/pdf', bytes: new ArrayBuffer(10) },
|
||||
state,
|
||||
makePopupSender(),
|
||||
);
|
||||
// The handler may return ok: false (vault_locked) since session is not primed,
|
||||
// but the router MUST reach the handler — i.e. not return unauthorized_sender.
|
||||
expect(result).not.toEqual({ ok: false, error: 'unauthorized_sender' });
|
||||
});
|
||||
|
||||
it('upload_attachment rejected from content script', async () => {
|
||||
const state = makeState();
|
||||
const result = await route(
|
||||
{ type: 'upload_attachment', itemId: 'abc', filename: 'f.pdf', mimeType: 'application/pdf', bytes: new ArrayBuffer(10) },
|
||||
state,
|
||||
makeContentSender(),
|
||||
);
|
||||
expect(result).toEqual({ ok: false, error: 'unauthorized_sender' });
|
||||
});
|
||||
|
||||
it('download_attachment accepted from popup', async () => {
|
||||
const state = makeState();
|
||||
const result = await route(
|
||||
{ type: 'download_attachment', itemId: 'abc', attachmentId: 'aid' },
|
||||
state,
|
||||
makePopupSender(),
|
||||
);
|
||||
expect(result).not.toEqual({ ok: false, error: 'unauthorized_sender' });
|
||||
});
|
||||
|
||||
it('download_attachment rejected from content script', async () => {
|
||||
const state = makeState();
|
||||
const result = await route(
|
||||
{ type: 'download_attachment', itemId: 'abc', attachmentId: 'aid' },
|
||||
state,
|
||||
makeContentSender(),
|
||||
);
|
||||
expect(result).toEqual({ ok: false, error: 'unauthorized_sender' });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user