UNPKG

@helia/verified-fetch

Version:

A fetch-like API for obtaining verified & trustless IPFS content on the web

67 lines 3.6 kB
import { Record as DHTRecord } from '@libp2p/kad-dht'; import { Key } from 'interface-datastore'; import { concat as uint8ArrayConcat } from 'uint8arrays/concat'; import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'; import { toString as uint8ArrayToString } from 'uint8arrays/to-string'; import { getPeerIdFromString } from '../utils/get-peer-id-from-string.js'; import { badRequestResponse, okRangeResponse } from '../utils/responses.js'; import { PluginFatalError } from './errors.js'; import { BasePlugin } from './plugin-base.js'; /** * Accepts an `ipns://...`, `https?://<ipnsname>.ipns.<domain>`, or `https?://<domain>/ipns/...` URL as a string and * returns a `Response` containing a raw IPNS record. */ export class IpnsRecordPlugin extends BasePlugin { id = 'ipns-record-plugin'; codes = []; canHandle({ cid, accept, query, byteRangeContext }) { this.log('checking if we can handle %c with accept %s', cid, accept); if (byteRangeContext == null) { return false; } return accept === 'application/vnd.ipfs.ipns-record' || query.format === 'ipns-record'; } async handle(context) { const { resource, path, options } = context; const { helia } = this.pluginOptions; context.reqFormat = 'ipns-record'; if (path !== '' || !(resource.startsWith('ipns://') || resource.includes('.ipns.') || resource.includes('/ipns/'))) { this.log.error('invalid request for IPNS name "%s" and path "%s"', resource, path); throw new PluginFatalError('ERR_INVALID_IPNS_NAME', 'Invalid IPNS name', { response: badRequestResponse(resource, new Error('Invalid IPNS name')) }); } let peerId; try { let peerIdString; if (resource.startsWith('ipns://')) { peerIdString = resource.replace('ipns://', ''); } else if (resource.includes('/ipns/')) { peerIdString = resource.split('/ipns/')[1].split('/')[0].split('?')[0]; } else { peerIdString = resource.split('.ipns.')[0].split('://')[1]; } this.log.trace('trying to parse peer id from "%s"', peerIdString); peerId = getPeerIdFromString(peerIdString); } catch (err) { this.log.error('could not parse peer id from IPNS url %s', resource, err); throw new PluginFatalError('ERR_NO_PEER_ID_FOUND', 'could not parse peer id from url', { response: badRequestResponse(resource, err) }); } // since this call happens after parseResource, we've already resolved the // IPNS name so a local copy should be in the helia datastore, so we can // just read it out.. const routingKey = uint8ArrayConcat([ uint8ArrayFromString('/ipns/'), peerId.toMultihash().bytes ]); const datastoreKey = new Key('/dht/record/' + uint8ArrayToString(routingKey, 'base32'), false); const buf = await helia.datastore.get(datastoreKey, options); const record = DHTRecord.deserialize(buf); context.byteRangeContext.setBody(record.value); const response = okRangeResponse(resource, context.byteRangeContext.getBody('application/vnd.ipfs.ipns-record'), { byteRangeContext: context.byteRangeContext, log: this.log }); response.headers.set('content-type', context.byteRangeContext.getContentType() ?? 'application/vnd.ipfs.ipns-record'); return response; } } //# sourceMappingURL=plugin-handle-ipns-record.js.map