mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2026-07-22 07:48:27 +00:00
blossom: optimize hash extraction from url.
This commit is contained in:
67
nipb0.test.ts
Normal file
67
nipb0.test.ts
Normal 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()
|
||||
})
|
||||
})
|
||||
25
nipb0.ts
25
nipb0.ts
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user