Add GET /i/:id/:secret hotlink image decrypt stream.
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { AES_GCM_KEY_BYTE_LENGTH } from '../consts/crypto/aesGcmKeyByteLength';
|
||||
import { fromBase64Url } from './fromBase64Url';
|
||||
|
||||
const toBase64UrlLikeClient = (bytes: Buffer): string => {
|
||||
let base64 = bytes.toString('base64').split('+').join('-').split('/').join('_');
|
||||
|
||||
while (base64.endsWith('=')) {
|
||||
base64 = base64.slice(0, -1);
|
||||
}
|
||||
|
||||
return base64;
|
||||
};
|
||||
|
||||
describe('fromBase64Url', () => {
|
||||
it('decodes unpadded base64url utf8 payloads', () => {
|
||||
expect(fromBase64Url('aGVsbG8')).toEqual(Buffer.from('hello', 'utf8'));
|
||||
});
|
||||
|
||||
it('decodes empty string to an empty buffer', () => {
|
||||
expect(fromBase64Url('')).toEqual(Buffer.alloc(0));
|
||||
});
|
||||
|
||||
it('decodes base64url with - and _ instead of + and /', () => {
|
||||
const bytes = Buffer.from([0xfb, 0xff, 0xfe]);
|
||||
const url = bytes.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
||||
|
||||
expect(fromBase64Url(url)).toEqual(bytes);
|
||||
});
|
||||
|
||||
it('restores padding when the input omits trailing equals', () => {
|
||||
expect(fromBase64Url('AQIDBA')).toEqual(Buffer.from([0x01, 0x02, 0x03, 0x04]));
|
||||
});
|
||||
|
||||
it('decodes when padding characters are already present', () => {
|
||||
expect(fromBase64Url('YQ==')).toEqual(Buffer.from('a', 'utf8'));
|
||||
expect(fromBase64Url('YWI=')).toEqual(Buffer.from('ab', 'utf8'));
|
||||
});
|
||||
|
||||
it('matches Node base64url decoding for random 32-byte keys', () => {
|
||||
const dek = randomBytes(AES_GCM_KEY_BYTE_LENGTH);
|
||||
const secret = dek.toString('base64url');
|
||||
|
||||
expect(fromBase64Url(secret)).toEqual(dek);
|
||||
expect(fromBase64Url(secret)).toEqual(Buffer.from(secret, 'base64url'));
|
||||
});
|
||||
|
||||
describe('round-trip with client-style encoding', () => {
|
||||
it.each([0, 1, 2, 3, 4, 12, 16, 32, 64])('decodes %i-byte payloads', length => {
|
||||
const bytes = randomBytes(length);
|
||||
const encoded = toBase64UrlLikeClient(bytes);
|
||||
|
||||
expect(fromBase64Url(encoded)).toEqual(bytes);
|
||||
});
|
||||
|
||||
it('decodes fixed-byte patterns used in crypto tests', () => {
|
||||
const iv = Buffer.alloc(12, 0x11);
|
||||
const dek = Buffer.alloc(32, 0x42);
|
||||
|
||||
expect(fromBase64Url(toBase64UrlLikeClient(iv))).toEqual(iv);
|
||||
expect(fromBase64Url(toBase64UrlLikeClient(dek))).toEqual(dek);
|
||||
});
|
||||
});
|
||||
|
||||
describe('agrees with Buffer.from(..., "base64url")', () => {
|
||||
const samples = [
|
||||
'aGVsbG8',
|
||||
toBase64UrlLikeClient(Buffer.from([0xff, 0xfe, 0xfd])),
|
||||
randomBytes(48).toString('base64url')
|
||||
];
|
||||
|
||||
it.each(samples)('matches for encoded sample', encoded => {
|
||||
expect(fromBase64Url(encoded)).toEqual(Buffer.from(encoded, 'base64url'));
|
||||
});
|
||||
});
|
||||
|
||||
it('decodes standard base64 alphabet when plus and slash are passed through', () => {
|
||||
const standard = Buffer.from('binary+/', 'utf8').toString('base64');
|
||||
|
||||
expect(fromBase64Url(standard)).toEqual(Buffer.from('binary+/', 'utf8'));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user