blossom: optimize hash extraction from url.

This commit is contained in:
fiatjaf
2026-07-16 20:22:02 -03:00
parent cbb1b9688d
commit 585258516b
2 changed files with 86 additions and 6 deletions

67
nipb0.test.ts Normal file
View File

@@ -0,0 +1,67 @@
import { describe, expect, it } from 'bun:test'
import { getHashFromURL } from './nipb0.ts'
const VALID_HASH = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
describe('getHashFromURL', () => {
it('extracts hash from plain URL string', () => {
expect(getHashFromURL(`https://example.com/${VALID_HASH}`)).toBe(VALID_HASH)
})
it('extracts hash from URL with extension', () => {
expect(getHashFromURL(`https://example.com/${VALID_HASH}.jpg`)).toBe(VALID_HASH)
})
it('extracts hash from URL with query string', () => {
expect(getHashFromURL(`https://example.com/${VALID_HASH}?foo=bar`)).toBe(VALID_HASH)
})
it('extracts hash from URL with fragment', () => {
expect(getHashFromURL(`https://example.com/${VALID_HASH}#section`)).toBe(VALID_HASH)
})
it('extracts hash from URL with query and fragment', () => {
expect(getHashFromURL(`https://example.com/${VALID_HASH}?foo=bar#section`)).toBe(VALID_HASH)
})
it('extracts hash from URL object', () => {
expect(getHashFromURL(new URL(`https://example.com/${VALID_HASH}`))).toBe(VALID_HASH)
})
it('extracts hash from URL object with pathname', () => {
const url = new URL(`https://example.com/${VALID_HASH}.png`)
expect(getHashFromURL(url)).toBe(VALID_HASH)
})
it('returns null when segment is too short', () => {
expect(getHashFromURL('https://example.com/abc')).toBeNull()
})
it('returns null when segment has non-hex characters', () => {
expect(getHashFromURL(`https://example.com/${VALID_HASH.slice(0, 63)}x`)).toBeNull()
})
it('returns null when extension is not at position 64', () => {
expect(getHashFromURL('https://example.com/short.jpg')).toBeNull()
})
it('returns null when uppercase hex chars are used', () => {
expect(getHashFromURL(`https://example.com/${VALID_HASH.toUpperCase()}`)).toBeNull()
})
it('returns null for URL without hash in path', () => {
expect(getHashFromURL('https://example.com/')).toBeNull()
})
it('handles localhost URL with hash', () => {
expect(getHashFromURL(`http://localhost:3000/${VALID_HASH}`)).toBe(VALID_HASH)
})
it('returns hash from nested path', () => {
expect(getHashFromURL(`https://example.com/files/${VALID_HASH}.jpg`)).toBe(VALID_HASH)
})
it('returns null for plain string without slash', () => {
expect(getHashFromURL('not-a-url')).toBeNull()
})
})

View File

@@ -373,13 +373,26 @@ export function getServersFromServerListEvent(event: { tags: string[][] }): URL[
}
export function getHashFromURL(url: string | URL): string | null {
try {
if (typeof url === 'string') url = new URL(url)
const hashes = Array.from(url.pathname.matchAll(/[0-9a-f]{64}/gi))
return hashes.length > 0 ? hashes[hashes.length - 1][0] : null
} catch (_err) {
return null
// strip fragment, then query string
const path = typeof url === 'string' ? url.split('#', 1)[0].split('?', 1)[0] : url.pathname
// get the last path segment
const lastSlash = path.lastIndexOf('/')
let segment = lastSlash === -1 ? path : path.slice(lastSlash + 1)
// if there is an extension it should start at exactly the 64th character
const dotIndex = segment.indexOf('.')
if (dotIndex !== -1 && dotIndex !== 64) return null
// the first 64 characters must be all lowercase hex
for (let i = 0; i < 64; i++) {
const c = segment.charCodeAt(i)
const isDigit = c >= 48 && c <= 57 // '0'-'9'
const isLowerHex = c >= 97 && c <= 102 // 'a'-'f'
if (!isDigit && !isLowerHex) return null
}
return segment.slice(0, 64)
}
export type UploadOptions = {