feat: implement direct file upload for sends with JWT token validation

- Added `processSendFileUpload` function to handle file uploads for sends.
- Integrated JWT token creation and verification for secure file uploads.
- Updated `handleCreateFileSendV2` and `handleGetSendFileUpload` to use new upload URL generation.
- Refactored upload handling in `handleUploadSendFile` and `handlePublicUploadSendFile` to utilize the new upload process.
- Introduced `uploadDirectEncryptedPayload` for handling direct uploads with progress tracking.
- Enhanced API routes to support both POST and PUT methods for attachment uploads.
- Added localization strings for upload progress messages.
- Created utility functions for direct upload URL building and payload parsing.
This commit is contained in:
shuaiplus
2026-03-18 02:26:10 +08:00
parent 3204eeb9ab
commit bb3fe41330
17 changed files with 666 additions and 127 deletions
+11 -7
View File
@@ -12,6 +12,7 @@ import {
chunkArray,
parseErrorMessage,
parseJson,
uploadDirectEncryptedPayload,
type AuthedFetch,
} from './shared';
import { readResponseBytesWithProgress } from '../download';
@@ -199,7 +200,8 @@ export async function uploadCipherAttachment(
session: SessionState,
cipherId: string,
file: File,
cipherForKey?: Cipher | null
cipherForKey?: Cipher | null,
onProgress?: (percent: number | null) => void
): Promise<void> {
if (!session.symEncKey || !session.symMacKey) throw new Error('Vault key unavailable');
const id = String(cipherId || '').trim();
@@ -233,6 +235,7 @@ export async function uploadCipherAttachment(
(await parseJson<{
attachmentId?: string;
url?: string;
fileUploadType?: number;
}>(metaResp)) || {};
const attachmentId = String(meta.attachmentId || '').trim();
const uploadUrl = String(meta.url || '').trim();
@@ -240,12 +243,13 @@ export async function uploadCipherAttachment(
const payload = new ArrayBuffer(encryptedBytes.byteLength);
new Uint8Array(payload).set(encryptedBytes);
const formData = new FormData();
formData.set('data', new Blob([payload], { type: 'application/octet-stream' }), encryptedFileName);
const uploadResp = await authedFetch(uploadUrl, {
method: 'POST',
body: formData,
const uploadResp = await uploadDirectEncryptedPayload({
accessToken: session.accessToken,
uploadUrl,
payload,
fileUploadType: meta.fileUploadType,
unsupportedMessage: 'Unsupported attachment upload type',
onProgress,
});
if (!uploadResp.ok) {
try {