62 lines
2.3 KiB
JavaScript
62 lines
2.3 KiB
JavaScript
import { randomUUID } from 'node:crypto';
|
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
import { db } from '../src/db/knex.js';
|
|
import { getApplication, listApplications } from '../src/services/admin.js';
|
|
import { decryptField, encryptField, maskSecret, panLookup } from '../src/services/fieldCrypto.js';
|
|
import { readPngDataUrl } from '../src/services/png.js';
|
|
import { truncateTables } from './truncate.js';
|
|
|
|
const ONE_PIXEL =
|
|
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==';
|
|
|
|
describe('field protection', () => {
|
|
afterEach(async () => {
|
|
await truncateTables();
|
|
});
|
|
|
|
it('encrypts and masks PAN and account number', async () => {
|
|
const pan = encryptField('ABCDE1234F');
|
|
const account = encryptField('123456789012');
|
|
expect(pan.startsWith('enc:v1:')).toBe(true);
|
|
expect(decryptField(pan)).toBe('ABCDE1234F');
|
|
expect(maskSecret('ABCDE1234F')).toBe('******234F');
|
|
expect(panLookup('abcde1234f')).toBe(panLookup('ABCDE1234F'));
|
|
|
|
const [id] = await db('applications').insert({
|
|
public_id: randomUUID(),
|
|
email: 'mask@example.com',
|
|
status: 'SUBMITTED',
|
|
full_name: 'Asha Rao',
|
|
pan,
|
|
pan_lookup: panLookup('ABCDE1234F'),
|
|
account_number: account,
|
|
});
|
|
|
|
const list = await listApplications({});
|
|
expect(list.items.find((item) => item.email === 'mask@example.com')).toMatchObject({
|
|
pan: '******234F',
|
|
account_number: '******9012',
|
|
});
|
|
const detail = await getApplication(id);
|
|
expect(detail.pan).toBe('ABCDE1234F');
|
|
expect(detail.account_number).toBe('123456789012');
|
|
|
|
const found = await listApplications({ q: 'ABCDE1234F' });
|
|
expect(found.total).toBe(1);
|
|
});
|
|
|
|
it('rejects a PNG that is too large in pixels', () => {
|
|
const header = Buffer.alloc(24);
|
|
header[0] = 0x89;
|
|
header[1] = 0x50;
|
|
header[2] = 0x4e;
|
|
header[3] = 0x47;
|
|
header.write('IHDR', 12, 'ascii');
|
|
header.writeUInt32BE(2001, 16);
|
|
header.writeUInt32BE(1, 20);
|
|
const image = `data:image/png;base64,${header.toString('base64')}`;
|
|
expect(() => readPngDataUrl(image, 500 * 1024, 'too big')).toThrow(/2000 pixels/);
|
|
expect(readPngDataUrl(ONE_PIXEL, 500 * 1024, 'too big').length).toBeGreaterThan(8);
|
|
});
|
|
});
|