UNPKG

@atproto/repo

Version:

atproto repo and MST implementation

185 lines 7.38 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.RepoVerificationError = exports.verifyRecords = exports.verifyProofs = exports.verifyDiff = exports.verifyDiffCar = exports.verifyRepo = exports.verifyRepoCar = void 0; const car_1 = require("../car"); const data_diff_1 = require("../data-diff"); const mst_1 = require("../mst"); const readable_repo_1 = require("../readable-repo"); const storage_1 = require("../storage"); const types_1 = require("../types"); const util = __importStar(require("../util")); const verifyRepoCar = async (carBytes, did, signingKey) => { const car = await (0, car_1.readCarWithRoot)(carBytes); return (0, exports.verifyRepo)(car.blocks, car.root, did, signingKey); }; exports.verifyRepoCar = verifyRepoCar; const verifyRepo = async (blocks, head, did, signingKey, opts) => { const diff = await (0, exports.verifyDiff)(null, blocks, head, did, signingKey, opts); const creates = util.ensureCreates(diff.writes); return { creates, commit: diff.commit, }; }; exports.verifyRepo = verifyRepo; const verifyDiffCar = async (repo, carBytes, did, signingKey, opts) => { const car = await (0, car_1.readCarWithRoot)(carBytes); return (0, exports.verifyDiff)(repo, car.blocks, car.root, did, signingKey, opts); }; exports.verifyDiffCar = verifyDiffCar; const verifyDiff = async (repo, updateBlocks, updateRoot, did, signingKey, opts) => { const { ensureLeaves = true } = opts ?? {}; const stagedStorage = new storage_1.MemoryBlockstore(updateBlocks); const updateStorage = repo ? new storage_1.SyncStorage(stagedStorage, repo.storage) : stagedStorage; const updated = await verifyRepoRoot(updateStorage, updateRoot, did, signingKey); const diff = await data_diff_1.DataDiff.of(updated.data, repo?.data ?? null); const writes = await util.diffToWriteDescripts(diff); const newBlocks = diff.newMstBlocks; const leaves = updateBlocks.getMany(diff.newLeafCids.toList()); if (leaves.missing.length > 0 && ensureLeaves) { throw new Error(`missing leaf blocks: ${leaves.missing}`); } newBlocks.addMap(leaves.blocks); const removedCids = diff.removedCids; const commitCid = await newBlocks.add(updated.commit); // ensure the commit cid actually changed if (repo) { if (commitCid.equals(repo.cid)) { newBlocks.delete(commitCid); } else { removedCids.add(repo.cid); } } return { writes, commit: { cid: updated.cid, rev: updated.commit.rev, prev: repo?.cid ?? null, since: repo?.commit.rev ?? null, newBlocks, relevantBlocks: newBlocks, removedCids, }, }; }; exports.verifyDiff = verifyDiff; // @NOTE only verifies the root, not the repo contents const verifyRepoRoot = async (storage, head, did, signingKey) => { const repo = await readable_repo_1.ReadableRepo.load(storage, head); if (did !== undefined && repo.did !== did) { throw new RepoVerificationError(`Invalid repo did: ${repo.did}`); } if (signingKey !== undefined) { const validSig = await util.verifyCommitSig(repo.commit, signingKey); if (!validSig) { throw new RepoVerificationError(`Invalid signature on commit: ${repo.cid.toString()}`); } } return repo; }; const verifyProofs = async (proofs, claims, did, didKey) => { const car = await (0, car_1.readCarWithRoot)(proofs); const blockstore = new storage_1.MemoryBlockstore(car.blocks); const commit = await blockstore.readObj(car.root, types_1.def.commit); if (commit.did !== did) { throw new RepoVerificationError(`Invalid repo did: ${commit.did}`); } const validSig = await util.verifyCommitSig(commit, didKey); if (!validSig) { throw new RepoVerificationError(`Invalid signature on commit: ${car.root.toString()}`); } const mst = mst_1.MST.load(blockstore, commit.data); const verified = []; const unverified = []; for (const claim of claims) { const found = await mst.get(util.formatDataKey(claim.collection, claim.rkey)); const record = found ? await blockstore.readObj(found, types_1.def.map) : null; if (claim.cid === null) { if (record === null) { verified.push(claim); } else { unverified.push(claim); } } else { if (claim.cid.equals(found)) { verified.push(claim); } else { unverified.push(claim); } } } return { verified, unverified }; }; exports.verifyProofs = verifyProofs; const verifyRecords = async (proofs, did, signingKey) => { const car = await (0, car_1.readCarWithRoot)(proofs); const blockstore = new storage_1.MemoryBlockstore(car.blocks); const commit = await blockstore.readObj(car.root, types_1.def.commit); if (commit.did !== did) { throw new RepoVerificationError(`Invalid repo did: ${commit.did}`); } const validSig = await util.verifyCommitSig(commit, signingKey); if (!validSig) { throw new RepoVerificationError(`Invalid signature on commit: ${car.root.toString()}`); } const mst = mst_1.MST.load(blockstore, commit.data); const records = []; const leaves = await mst.reachableLeaves(); for (const leaf of leaves) { const { collection, rkey } = util.parseDataKey(leaf.key); const record = await blockstore.attemptReadRecord(leaf.value); if (record) { records.push({ collection, rkey, record, }); } } return records; }; exports.verifyRecords = verifyRecords; class RepoVerificationError extends Error { } exports.RepoVerificationError = RepoVerificationError; //# sourceMappingURL=consumer.js.map