mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 13:00:39 +00:00
feat: enhance send file download token with JTI for improved validation
This commit is contained in:
@@ -1195,11 +1195,19 @@ export async function handleDownloadSendFile(
|
|||||||
return errorResponse('Token mismatch', 401);
|
return errorResponse('Token mismatch', 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const storage = new StorageService(env.DB);
|
||||||
const object = await env.ATTACHMENTS.get(getSendFilePath(sendId, fileId));
|
const object = await env.ATTACHMENTS.get(getSendFilePath(sendId, fileId));
|
||||||
if (!object) {
|
if (!object) {
|
||||||
return errorResponse('Send file not found', 404);
|
return errorResponse('Send file not found', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reuse the existing one-time token store used by attachment downloads.
|
||||||
|
// Prefix avoids accidental cross-domain JTI collisions.
|
||||||
|
const firstUse = await storage.consumeAttachmentDownloadToken(`send:${claims.jti}`, claims.exp);
|
||||||
|
if (!firstUse) {
|
||||||
|
return errorResponse('Invalid or expired token', 401);
|
||||||
|
}
|
||||||
|
|
||||||
return new Response(object.body, {
|
return new Response(object.body, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/octet-stream',
|
'Content-Type': 'application/octet-stream',
|
||||||
@@ -1287,4 +1295,3 @@ export async function issueSendAccessToken(
|
|||||||
const token = await createSendAccessToken(send.id, jwt.secret);
|
const token = await createSendAccessToken(send.id, jwt.secret);
|
||||||
return { token };
|
return { token };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ export async function verifyFileDownloadToken(
|
|||||||
export interface SendFileDownloadClaims {
|
export interface SendFileDownloadClaims {
|
||||||
sendId: string;
|
sendId: string;
|
||||||
fileId: string;
|
fileId: string;
|
||||||
|
jti: string;
|
||||||
exp: number;
|
exp: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,6 +195,7 @@ export async function createSendFileDownloadToken(
|
|||||||
const payload: SendFileDownloadClaims = {
|
const payload: SendFileDownloadClaims = {
|
||||||
sendId,
|
sendId,
|
||||||
fileId,
|
fileId,
|
||||||
|
jti: createRefreshToken(),
|
||||||
exp: now + LIMITS.auth.fileDownloadTokenTtlSeconds,
|
exp: now + LIMITS.auth.fileDownloadTokenTtlSeconds,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -240,6 +242,15 @@ export async function verifySendFileDownloadToken(
|
|||||||
if (!valid) return null;
|
if (!valid) return null;
|
||||||
|
|
||||||
const payload: SendFileDownloadClaims = JSON.parse(new TextDecoder().decode(base64UrlDecode(payloadB64)));
|
const payload: SendFileDownloadClaims = JSON.parse(new TextDecoder().decode(base64UrlDecode(payloadB64)));
|
||||||
|
if (
|
||||||
|
typeof payload.sendId !== 'string' ||
|
||||||
|
typeof payload.fileId !== 'string' ||
|
||||||
|
typeof payload.jti !== 'string' ||
|
||||||
|
!payload.jti ||
|
||||||
|
typeof payload.exp !== 'number'
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const now = Math.floor(Date.now() / 1000);
|
const now = Math.floor(Date.now() / 1000);
|
||||||
if (payload.exp < now) return null;
|
if (payload.exp < now) return null;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user