Files
timmy-talking-turd/tests/image-ingress.test.js
T
timmy ba9afe0a1d feat(ingress): decide photo validity from bytes, budget, and header before any provider work (#16)
The declared data-URL MIME was a claim the boundary believed. Every image decision now comes from
the bytes: the container is sniffed, walked to its own end marker, refused when metadata segments
remain, and refused above a 4096px edge or 16MP. The request path adds a per-caller sliding-window
budget (429 + Retry-After) and a body deadline (408), so a flood, a stalled body, or a decode bomb
fails before a provider call.

Log hygiene is part of the contract: refusal copy is fixed prose, the bucket key is a salted hash
kept in memory only, and the acceptance test asserts no image bytes reach the process log.
2026-10-20 08:21:20 +00:00

176 lines
6.4 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { IngressError, inspectImageBytes, MAX_EDGE, MAX_PIXELS } from '../src/image-ingress.js';
// Every fixture built here is synthetic container bytes assembled in code. No photograph of any
// person or specimen is used, and nothing is fetched.
const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
function pngChunk(type, data = Buffer.alloc(0)) {
const length = Buffer.alloc(4);
length.writeUInt32BE(data.length);
const body = Buffer.concat([Buffer.from(type, 'ascii'), data]);
// The parser walks chunk lengths to find the end of the container; the CRC is not read, so a
// synthetic zero CRC is enough to be structurally complete.
return Buffer.concat([length, body, Buffer.alloc(4)]);
}
function png({ width = 1200, height = 900, extraChunks = [], tail = Buffer.alloc(0) } = {}) {
const ihdr = Buffer.alloc(13);
ihdr.writeUInt32BE(width, 0);
ihdr.writeUInt32BE(height, 4);
ihdr[8] = 8; // bit depth
ihdr[9] = 2; // truecolour
return Buffer.concat([
PNG_SIGNATURE,
pngChunk('IHDR', ihdr),
...extraChunks,
pngChunk('IDAT', Buffer.from([0x78, 0x9c, 0x01])),
pngChunk('IEND'),
tail,
]);
}
function jpeg({ width = 1200, height = 900, segments = [], tail = Buffer.alloc(0) } = {}) {
const sof = Buffer.alloc(17);
sof.writeUInt16BE(0xffc0, 0);
sof.writeUInt16BE(15, 2); // payload length
sof[4] = 8; // precision
sof.writeUInt16BE(height, 5);
sof.writeUInt16BE(width, 7);
sof[9] = 3; // component count
for (let i = 0; i < 3; i += 1) {
sof[10 + i * 3] = i + 1;
sof[11 + i * 3] = 0x11;
sof[12 + i * 3] = 0;
}
return Buffer.concat([
Buffer.from([0xff, 0xd8]),
...segments,
sof,
Buffer.from([0xff, 0xd9]),
tail,
]);
}
function exifSegment() {
const payload = Buffer.concat([
Buffer.from('Exif', 'ascii'),
Buffer.from([0x00, 0x00]),
Buffer.from('GPSLatitude=0.000', 'ascii'),
]);
const header = Buffer.alloc(4);
header.writeUInt16BE(0xffe1, 0);
header.writeUInt16BE(payload.length + 2, 2);
return Buffer.concat([header, payload]);
}
function webp({ width = 1200, height = 900 } = {}) {
// VP8X canvas payload: flags(1) + reserved(3) + width-1(3, LE) + height-1(3, LE).
const payload = Buffer.alloc(10);
payload[0] = 0;
payload.writeUIntLE(width - 1, 4, 3);
payload.writeUIntLE(height - 1, 7, 3);
const chunk = Buffer.alloc(8);
chunk.write('VP8X', 0, 'ascii');
chunk.writeUInt32LE(payload.length, 4);
const body = Buffer.concat([Buffer.from('WEBP', 'ascii'), chunk, payload]);
const riff = Buffer.alloc(8);
riff.write('RIFF', 0, 'ascii');
riff.writeUInt32LE(body.length, 4);
return Buffer.concat([riff, body]);
}
const expectRefusal = (bytes, declaredMime, pattern) => {
assert.throws(
() => inspectImageBytes(bytes, { declaredMime }),
error => {
assert.ok(error instanceof IngressError, `expected an IngressError, got ${error?.name}`);
assert.match(error.message, pattern);
return true;
},
);
};
test('refuses a file whose bytes are not a JPEG, PNG, or WebP', () => {
expectRefusal(Buffer.from('<html><script>alert(1)</script></html>', 'utf8'), 'image/jpeg', /not a JPEG, PNG, or WebP photo/i);
});
test('refuses a PNG that claims to be a JPEG', () => {
expectRefusal(png(), 'image/jpeg', /not the format it claims/i);
});
test('refuses a JPEG that claims to be a PNG', () => {
expectRefusal(jpeg(), 'image/png', /not the format it claims/i);
});
test('refuses a truncated container instead of forwarding a partial image', () => {
expectRefusal(PNG_SIGNATURE.subarray(0, 8), 'image/png', /incomplete or damaged/i);
expectRefusal(Buffer.from([0xff, 0xd8, 0xff, 0xe0]), 'image/jpeg', /incomplete or damaged/i);
});
test('refuses a PNG with bytes appended after its end marker', () => {
expectRefusal(png({ tail: Buffer.from('PK\u0003\u0004zip-appended', 'binary') }), 'image/png', /extra data after the image/i);
});
test('refuses a JPEG with bytes appended after its end marker', () => {
expectRefusal(jpeg({ tail: Buffer.from('<script>alert(1)</script>', 'utf8') }), 'image/jpeg', /extra data after the image/i);
});
test('refuses a JPEG that still carries an EXIF segment', () => {
expectRefusal(jpeg({ segments: [exifSegment()] }), 'image/jpeg', /embedded metadata/i);
});
test('refuses a PNG that carries an eXIf chunk', () => {
const exifChunk = pngChunk('eXIf', Buffer.from('MM\u0000*metadata', 'binary'));
expectRefusal(png({ extraChunks: [exifChunk] }), 'image/png', /embedded metadata/i);
});
test('accepts a clean JPEG and reports its real dimensions', () => {
const intake = inspectImageBytes(jpeg({ width: 1200, height: 900 }), { declaredMime: 'image/jpeg' });
assert.equal(intake.mime, 'image/jpeg');
assert.equal(intake.width, 1200);
assert.equal(intake.height, 900);
assert.equal(intake.bytes, jpeg({ width: 1200, height: 900 }).length);
});
test('accepts a clean PNG and reports its real dimensions', () => {
const intake = inspectImageBytes(png({ width: 800, height: 600 }), { declaredMime: 'image/png' });
assert.equal(intake.mime, 'image/png');
assert.equal(intake.width, 800);
assert.equal(intake.height, 600);
});
test('accepts a clean WebP and reports its canvas dimensions', () => {
const intake = inspectImageBytes(webp({ width: 640, height: 480 }), { declaredMime: 'image/webp' });
assert.equal(intake.mime, 'image/webp');
assert.equal(intake.width, 640);
assert.equal(intake.height, 480);
});
test(`refuses an edge longer than ${MAX_EDGE} pixels even when the file is small`, () => {
expectRefusal(png({ width: MAX_EDGE + 1, height: 200 }), 'image/png', /too large in pixels/i);
});
test(`refuses an image above ${MAX_PIXELS} pixels when each edge fits`, () => {
const edge = 4096;
expectRefusal(jpeg({ width: edge, height: Math.ceil(MAX_PIXELS / edge) + 1 }), 'image/jpeg', /too large in pixels/i);
});
test('never repeats image bytes back to the caller in a refusal message', () => {
const marker = 'SECRETPIXELMARKER';
try {
inspectImageBytes(Buffer.from(`not an image ${marker}`, 'utf8'), { declaredMime: 'image/jpeg' });
assert.fail('expected a refusal');
} catch (error) {
assert.ok(error instanceof IngressError);
assert.doesNotMatch(error.message, new RegExp(marker));
assert.doesNotMatch(error.message, /[A-Za-z0-9+/=]{40,}/);
}
});
test('refuses an empty body with a bounded message', () => {
expectRefusal(Buffer.alloc(0), 'image/jpeg', /empty/i);
});