~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
74 lines · 1.9 KB Raw History
/**
 * OCI digest and blob CID conversion. Both name the same SHA-256 hash: a
 * digest as `sha256:<hex>`, a blob CID as CIDv1 + raw codec + sha256
 * multihash. Converting between them is re-encoding, not a lookup.
 */

import { blobCidFromDigest, cidToBytes, cidToString } from '@pdsjs/core/repo';

const DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/;

/**
 * @param {string} digest
 * @returns {boolean}
 */
export function isValidDigest(digest) {
  return DIGEST_PATTERN.test(digest);
}

/**
 * @param {string} hex - 64 lowercase hex characters
 * @returns {Uint8Array}
 */
function hexToBytes(hex) {
  const bytes = new Uint8Array(hex.length / 2);
  for (let i = 0; i < bytes.length; i++) {
    bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
  }
  return bytes;
}

/**
 * @param {Uint8Array} bytes
 * @returns {string}
 */
export function bytesToHex(bytes) {
  let hex = '';
  for (const byte of bytes) {
    hex += byte.toString(16).padStart(2, '0');
  }
  return hex;
}

/**
 * @param {string} digest - `sha256:<hex>`
 * @returns {string} base32lower blob CID string
 */
export function digestToCid(digest) {
  if (!isValidDigest(digest)) {
    throw new Error(`unsupported digest: ${digest}`);
  }
  return cidToString(blobCidFromDigest(hexToBytes(digest.slice(7))));
}

/**
 * @param {string} cid - base32lower blob CID string
 * @returns {string} `sha256:<hex>`
 */
export function cidToDigest(cid) {
  const bytes = cidToBytes(cid);
  // CIDv1 + codec + multihash prefix take the first four bytes; the sha256
  // digest is the 32 that follow.
  if (bytes.length !== 36 || bytes[2] !== 0x12 || bytes[3] !== 0x20) {
    throw new Error(`not a sha256 CID: ${cid}`);
  }
  return `sha256:${bytesToHex(bytes.subarray(4))}`;
}

/**
 * @param {Uint8Array} hashBytes - 32-byte SHA-256 digest
 * @returns {string} `sha256:<hex>`
 */
export function digestFromHashBytes(hashBytes) {
  return `sha256:${bytesToHex(hashBytes)}`;
}