Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions apps/OpenSignServer/cloud/parsefunction/getSignedUrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,21 +125,46 @@ export async function getSignedUrl(request) {
}
}

export function normalizeLocalFileUrl(fileUrl) {
if (!fileUrl) return fileUrl;

try {
const parsedFileUrl = new URL(fileUrl);
if (!parsedFileUrl.pathname.includes('/files/')) {
return fileUrl;
}

const configuredServerUrl = process.env.SERVER_URL;
if (!configuredServerUrl) {
return fileUrl;
}

const parsedServerUrl = new URL(configuredServerUrl);
parsedFileUrl.protocol = parsedServerUrl.protocol;
parsedFileUrl.host = parsedServerUrl.host;

return parsedFileUrl.toString();
} catch (err) {
return fileUrl;
}
}

// Function to generate a signed URL with JWT
export function getSignedLocalUrl(fileUrl, expirationTimeInSeconds) {
const secretKey = process.env.MASTER_KEY;
const exp = expirationTimeInSeconds || 200;
try {
const normalizedFileUrl = normalizeLocalFileUrl(fileUrl);
// Create the payload with the file URL and expiration time
const payload = {
fileUrl,
fileUrl: normalizedFileUrl,
exp: Math.floor(Date.now() / 1000) + exp, // Expiry time in seconds
};

// Generate the JWT token
const token = jwt.sign(payload, secretKey);
// Return the signed URL containing the token
return `${fileUrl}?token=${token}`;
return `${normalizedFileUrl}?token=${token}`;
} catch (err) {
console.log('Err while siging local url', err);
throw new Error('Invalid or expired token.');
Expand All @@ -148,7 +173,7 @@ export function getSignedLocalUrl(fileUrl, expirationTimeInSeconds) {

export function presignedlocalUrl(signedUrl, expirationTimeInSeconds) {
if (signedUrl?.includes('files')) {
const fileUrl = signedUrl.split('?')?.[0];
const fileUrl = normalizeLocalFileUrl(signedUrl.split('?')?.[0]);
const secretKey = process.env.MASTER_KEY;
const exp = expirationTimeInSeconds || 200;
try {
Expand Down
53 changes: 53 additions & 0 deletions apps/OpenSignServer/spec/Tests.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import axios from 'axios';
import {
getSignedLocalUrl,
normalizeLocalFileUrl,
presignedlocalUrl,
} from '../cloud/parsefunction/getSignedUrl.js';

describe('Parse Server example', () => {
Parse.User.enableUnsafeCurrentUser();
it('call function', async () => {
Expand Down Expand Up @@ -31,3 +37,50 @@ describe('Parse Server example', () => {
expect(data).toContain('<title>Parse Server Example</title>');
});
});

describe('local file URL signing', () => {
const originalServerUrl = process.env.SERVER_URL;
const originalMasterKey = process.env.MASTER_KEY;

beforeEach(() => {
process.env.SERVER_URL = 'https://opensign.example.com:8443/api/app';
process.env.MASTER_KEY = 'test-master-key';
});

afterAll(() => {
process.env.SERVER_URL = originalServerUrl;
process.env.MASTER_KEY = originalMasterKey;
});

it('normalizes local file URLs to the configured server origin', () => {
const normalizedUrl = normalizeLocalFileUrl(
'https://opensign.example.com/api/app/files/opensign/sample.pdf'
);

expect(normalizedUrl).toBe(
'https://opensign.example.com:8443/api/app/files/opensign/sample.pdf'
);
});

it('preserves the configured port when signing local file URLs', () => {
const signedUrl = getSignedLocalUrl(
'https://opensign.example.com/api/app/files/opensign/sample.pdf',
200
);

expect(signedUrl).toContain(
'https://opensign.example.com:8443/api/app/files/opensign/sample.pdf?token='
);
});

it('re-signs existing local URLs with the configured port', () => {
const signedUrl = presignedlocalUrl(
'https://opensign.example.com/api/app/files/opensign/sample.pdf?token=old-token',
200
);

expect(signedUrl).toContain(
'https://opensign.example.com:8443/api/app/files/opensign/sample.pdf?token='
);
});
});