feat(core): Add support for signed URLs for binary data (#14492)

Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
Dana
2025-04-14 19:59:40 +02:00
committed by GitHub
parent 23f25cefbf
commit 7723a138a1
22 changed files with 537 additions and 122 deletions

View File

@@ -0,0 +1,85 @@
import { BinaryDataQueryDto } from '../binary-data-query.dto';
describe('BinaryDataQueryDto', () => {
describe('Valid requests', () => {
test.each([
{
name: 'filesystem mode with view action',
request: {
id: 'filesystem:some-id',
action: 'view',
},
},
{
name: 'filesystem-v2 mode with download action',
request: {
id: 'filesystem-v2:some-id',
action: 'download',
},
},
{
name: 's3 mode with view action and optional fields',
request: {
id: 's3:some-id',
action: 'view',
fileName: 'test.pdf',
mimeType: 'application/pdf',
},
},
])('should validate $name', ({ request }) => {
const result = BinaryDataQueryDto.safeParse(request);
expect(result.success).toBe(true);
});
});
describe('Invalid requests', () => {
test.each([
{
name: 'missing mode separator',
request: {
id: 'filesystemsome-id',
action: 'view',
},
expectedErrorPath: ['id'],
},
{
name: 'invalid mode',
request: {
id: 'invalid:some-id',
action: 'view',
},
expectedErrorPath: ['id'],
},
{
name: 'invalid action',
request: {
id: 'filesystem:some-id',
action: 'invalid',
},
expectedErrorPath: ['action'],
},
{
name: 'missing id',
request: {
action: 'view',
},
expectedErrorPath: ['id'],
},
{
name: 'missing action',
request: {
id: 'filesystem:some-id',
},
expectedErrorPath: ['action'],
},
])('should fail validation for $name', ({ request, expectedErrorPath }) => {
const result = BinaryDataQueryDto.safeParse(request);
expect(result.success).toBe(false);
if (expectedErrorPath) {
expect(result.error?.issues[0].path).toEqual(expectedErrorPath);
}
});
});
});

View File

@@ -0,0 +1,71 @@
import { BinaryDataSignedQueryDto } from '../binary-data-signed-query.dto';
describe('BinaryDataSignedQueryDto', () => {
describe('Valid requests', () => {
test.each([
{
name: 'valid JWT token',
request: {
token:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
},
},
])('should validate $name', ({ request }) => {
const result = BinaryDataSignedQueryDto.safeParse(request);
expect(result.success).toBe(true);
});
});
describe('Invalid requests', () => {
test.each([
{
name: 'missing token',
request: {},
expectedErrorPath: ['token'],
},
{
name: 'empty token',
request: {
token: '',
},
expectedErrorPath: ['token'],
},
{
name: 'non-string token',
request: {
token: 123,
},
expectedErrorPath: ['token'],
},
{
name: 'token without three segments',
request: {
token: 'header.payload',
},
expectedErrorPath: ['token'],
},
{
name: 'token with invalid characters',
request: {
token: 'header.payload.sign@ture',
},
expectedErrorPath: ['token'],
},
{
name: 'token with too many segments',
request: {
token: 'header.payload.signature.extra',
},
expectedErrorPath: ['token'],
},
])('should fail validation for $name', ({ request, expectedErrorPath }) => {
const result = BinaryDataSignedQueryDto.safeParse(request);
expect(result.success).toBe(false);
if (expectedErrorPath) {
expect(result.error?.issues[0].path).toEqual(expectedErrorPath);
}
});
});
});

View File

@@ -0,0 +1,22 @@
import { z } from 'zod';
import { Z } from 'zod-class';
export class BinaryDataQueryDto extends Z.class({
id: z
.string()
.refine((id) => id.includes(':'), {
message: 'Missing binary data mode',
})
.refine(
(id) => {
const [mode] = id.split(':');
return ['filesystem', 'filesystem-v2', 's3'].includes(mode);
},
{
message: 'Invalid binary data mode',
},
),
action: z.enum(['view', 'download']),
fileName: z.string().optional(),
mimeType: z.string().optional(),
}) {}

View File

@@ -0,0 +1,8 @@
import { z } from 'zod';
import { Z } from 'zod-class';
export class BinaryDataSignedQueryDto extends Z.class({
token: z.string().regex(/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/, {
message: 'Token must be a valid JWT format',
}),
}) {}

View File

@@ -3,6 +3,9 @@ export { AiChatRequestDto } from './ai/ai-chat-request.dto';
export { AiApplySuggestionRequestDto } from './ai/ai-apply-suggestion-request.dto';
export { AiFreeCreditsRequestDto } from './ai/ai-free-credits-request.dto';
export { BinaryDataQueryDto } from './binary-data/binary-data-query.dto';
export { BinaryDataSignedQueryDto } from './binary-data/binary-data-signed-query.dto';
export { LoginRequestDto } from './auth/login-request.dto';
export { ResolveSignupTokenQueryDto } from './auth/resolve-signup-token-query.dto';