mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
feat(core): Add support for signed URLs for binary data (#14492)
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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(),
|
||||
}) {}
|
||||
@@ -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',
|
||||
}),
|
||||
}) {}
|
||||
@@ -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';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user