mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2026-07-30 19:26:14 +00:00
blossom: optimize hash extraction from url.
This commit is contained in:
@@ -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()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -373,13 +373,26 @@ export function getServersFromServerListEvent(event: { tags: string[][] }): URL[
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getHashFromURL(url: string | URL): string | null {
|
export function getHashFromURL(url: string | URL): string | null {
|
||||||
try {
|
// strip fragment, then query string
|
||||||
if (typeof url === 'string') url = new URL(url)
|
const path = typeof url === 'string' ? url.split('#', 1)[0].split('?', 1)[0] : url.pathname
|
||||||
const hashes = Array.from(url.pathname.matchAll(/[0-9a-f]{64}/gi))
|
|
||||||
return hashes.length > 0 ? hashes[hashes.length - 1][0] : null
|
// get the last path segment
|
||||||
} catch (_err) {
|
const lastSlash = path.lastIndexOf('/')
|
||||||
return null
|
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 = {
|
export type UploadOptions = {
|
||||||
|
|||||||
Reference in New Issue
Block a user