import assert from 'node:assert/strict' import { describe, it } from 'node:test' import { IMAGE_LIMITS, RADIAL_IMAGE_SCHEME, imageBlobUrl, imageLocator, imageLocatorsIn, imageMarkdownSpansIn, isImageMimeType, isImageUri, parseImageLocator, } from '../dist/image.js' // A locator is the one thing a body says about a picture, and every reader — this tab, another // member's tab, an agent reading a brief — has to agree on what it names. So the round trip is // pinned, and so is the much longer list of things that LOOK like one and must not resolve: a // locator is an instruction to go and fetch something, and the only safe reading of an ambiguous one // is no reading at all. const IMAGE = 'at://did:plc:hbonvqr5ysrscg5wdyb5klie/com.disnetdev.radial.image/3mrvxfdae4l2m' describe('image record limits', () => { it('reads the allowlist and the ceiling off the lexicon rather than restating them', () => { // Written down in exactly one place — the lexicon a PDS validates against. A second copy here // would be the copy the upload form checks while the record is refused by the first. assert.deepEqual([...IMAGE_LIMITS.mimeTypes].sort(), [ 'image/gif', 'image/jpeg', 'image/png', 'image/webp', ]) assert.equal(IMAGE_LIMITS.maxBytes, 10_000_000) }) it('accepts the four raster formats, with parameters, and refuses SVG', () => { assert.equal(isImageMimeType('image/png'), true) assert.equal(isImageMimeType('IMAGE/JPEG'), true) assert.equal(isImageMimeType('image/webp; charset=binary'), true) // Inert through `` in most respects and still a document: script, external references, and // an unbounded decode. Not a paste target. assert.equal(isImageMimeType('image/svg+xml'), false) assert.equal(isImageMimeType('text/html'), false) assert.equal(isImageMimeType(''), false) }) }) describe('image locators', () => { it('round trips an image record URI', () => { const locator = imageLocator(IMAGE) assert.equal(locator, `${RADIAL_IMAGE_SCHEME}${IMAGE}`) assert.deepEqual(parseImageLocator(locator), { uri: IMAGE, did: 'did:plc:hbonvqr5ysrscg5wdyb5klie', rkey: '3mrvxfdae4l2m', }) // Whitespace around a markdown destination is the tokenizer's, not the author's. assert.deepEqual(parseImageLocator(` ${locator} `)?.uri, IMAGE) }) it('refuses to mint one for anything that is not an image record', () => { assert.equal(imageLocator('at://did:plc:abc/com.disnetdev.radial.artifact/plan-1'), undefined) assert.equal(imageLocator('https://example.test/cat.png'), undefined) assert.equal(imageLocator('at://did:plc:abc/com.disnetdev.radial.image/'), undefined) }) it('resolves nothing it was not handed exactly', () => { const refused = [ // Another collection wearing the scheme: the resolver would read a record that is not an image. `${RADIAL_IMAGE_SCHEME}at://did:plc:abc/com.disnetdev.radial.artifact/plan-1`, `${RADIAL_IMAGE_SCHEME}at://did:plc:abc/app.bsky.feed.post/1`, // Query and fragment: a resolver that ignored them would fetch a different thing from the one // the body appears to name, and one that honoured them would take instructions from prose. `${RADIAL_IMAGE_SCHEME}at://did:plc:abc/com.disnetdev.radial.image/rk?did=did:plc:evil&cid=x`, `${RADIAL_IMAGE_SCHEME}at://did:plc:abc/com.disnetdev.radial.image/rk#cid`, // Credentials in the authority, and an authority that is not a DID at all. `${RADIAL_IMAGE_SCHEME}at://user:pass@did:plc:abc/com.disnetdev.radial.image/rk`, `${RADIAL_IMAGE_SCHEME}at://evil.test/com.disnetdev.radial.image/rk`, // A second path segment: the URI names a record, and a record has one key. `${RADIAL_IMAGE_SCHEME}at://did:plc:abc/com.disnetdev.radial.image/rk/extra`, // Other schemes, including the two the prose renderer has always refused. 'https://pds.test/xrpc/com.atproto.sync.getBlob?did=did:plc:abc&cid=x', 'javascript:alert(1)', 'data:image/png;base64,AAAA', '/relative.png', // A malformed escape decodes to nothing anybody can defend. `${RADIAL_IMAGE_SCHEME}at://did:plc:abc/com.disnetdev.radial.image/%E0%A4%A`, '', ] for (const href of refused) assert.equal(parseImageLocator(href), null, href) }) it('is case sensitive about the URI and forgiving only about its own scheme', () => { assert.equal(parseImageLocator(`RADIAL-IMAGE:${IMAGE}`)?.uri, IMAGE) assert.equal(parseImageLocator(`${RADIAL_IMAGE_SCHEME}AT://did:plc:abc/com.disnetdev.radial.image/rk`), null) }) it('recognises an image record URI on its own', () => { assert.equal(isImageUri(IMAGE), true) assert.equal(isImageUri('at://did:plc:abc/com.disnetdev.radial.goal/g'), false) }) }) describe('the images a run of prose refers to', () => { const other = 'at://did:plc:human/com.disnetdev.radial.image/second' it('finds each one once, in the order it is first mentioned', () => { const body = [ `Before: ![the pane bar](${RADIAL_IMAGE_SCHEME}${IMAGE})`, `And again, differently labelled: ![again](${RADIAL_IMAGE_SCHEME}${IMAGE})`, `A second: ![two](${RADIAL_IMAGE_SCHEME}${other})`, ].join('\n\n') assert.deepEqual( imageLocatorsIn(body).map((image) => image.uri), [IMAGE, other], ) }) it('is not fooled by prose that merely mentions the scheme', () => { const body = [ 'A locator looks like radial-image:at://…, which is not one.', `${RADIAL_IMAGE_SCHEME}at://did:plc:abc/com.disnetdev.radial.artifact/plan-1`, `${RADIAL_IMAGE_SCHEME}https://evil.test/cat.png`, 'https://example.test/radial-image:at://did:plc:abc/com.disnetdev.radial.image/rk', ].join('\n') // The last line is the interesting one: it CONTAINS a well-formed locator, and this scan is a // catalogue rather than a fetch, so listing it is the same claim the prose already made. assert.deepEqual( imageLocatorsIn(body).map((image) => image.rkey), ['rk'], ) assert.deepEqual(imageLocatorsIn('no pictures here at all'), []) }) }) describe('Radial image Markdown spans', () => { it('finds complete images using the same strict locator parser', () => { const first = `![one](${RADIAL_IMAGE_SCHEME}${IMAGE})` const mixed = `![two](RADIAL-IMAGE:${IMAGE})` const body = `before ${first} middle ${mixed} after` assert.deepEqual(imageMarkdownSpansIn(body), [ { from: 7, to: 7 + first.length }, { from: 15 + first.length, to: 15 + first.length + mixed.length }, ]) assert.deepEqual( imageMarkdownSpansIn('![no](radial-image:https://example.test/not-a-record)'), [], ) }) }) describe('the blob URL a locator resolves to', () => { it('is getBlob on the author current PDS, with both parameters encoded', () => { assert.equal( imageBlobUrl('https://pds.test', 'did:plc:abc', 'bafkreiblob'), 'https://pds.test/xrpc/com.atproto.sync.getBlob?did=did%3Aplc%3Aabc&cid=bafkreiblob', ) // A `did:web` carries a percent-encoded port, which is exactly the value that breaks a URL built // by string concatenation. assert.match( imageBlobUrl(new URL('https://pds.test/anything'), 'did:web:example.test%3A8443', 'bafkreiblob'), /did=did%3Aweb%3Aexample\.test%253A8443/, ) }) })