UNPKG

@julesl23/s5js

Version:

Enhanced TypeScript SDK for S5 decentralized storage with path-based API, media processing, and directory utilities

93 lines 3.98 kB
import { bytesToUtf8, utf8ToBytes } from "@noble/ciphers/utils"; import { decryptMutableBytes, encryptMutableBytes } from "../encryption/mutable.js"; import { BlobIdentifier } from "../identifier/blob.js"; import { createRegistryEntry } from "../registry/entry.js"; import { deriveHashInt, deriveHashString } from "../util/derive_hash.js"; const pathKeyDerivationTweak = 1; const writeKeyDerivationTweak = 2; const encryptionKeyDerivationTweak = 3; class HiddenDBProvider { } export class TrustedHiddenDBProvider extends HiddenDBProvider { hiddenRootKey; api; cidMap = new Map(); constructor(hiddenRootKey, api) { super(); this.hiddenRootKey = hiddenRootKey; this.api = api; } async getRawData(path) { const pathKey = this.derivePathKeyForPath(path); const res = await this.getHiddenRawDataImplementation(pathKey); if (res.cid) { this.cidMap.set(path, res.cid); } return res; } async setRawData(path, data, revision) { const pathKey = this.derivePathKeyForPath(path); const newCID = await this.setHiddenRawDataImplementation(pathKey, data, revision); if (this.cidMap.has(path)) { await this.api.unpinHash(this.cidMap.get(path).hash); } this.cidMap.set(path, newCID); } derivePathKeyForPath(path) { const pathSegments = path .split('/') .map(e => e.trim()) .filter(element => element.length > 0); const key = this.deriveKeyForPathSegments(pathSegments); return deriveHashInt(key, pathKeyDerivationTweak, this.api.crypto); } deriveKeyForPathSegments(pathSegments) { if (pathSegments.length === 0) { return this.hiddenRootKey; } const parentKey = this.deriveKeyForPathSegments(pathSegments.slice(0, pathSegments.length - 1)); return deriveHashString(parentKey, utf8ToBytes(pathSegments[pathSegments.length - 1]), this.api.crypto); } async getJSON(path) { const res = await this.getRawData(path); if (!res.data) { return { cid: res.cid, revision: res.revision }; } return { data: JSON.parse(bytesToUtf8(res.data)), revision: res.revision, cid: res.cid }; } async setJSON(path, data, revision) { return this.setRawData(path, utf8ToBytes(JSON.stringify(data)), revision); } async setHiddenRawDataImplementation(pathKey, data, revision) { const encryptionKey = deriveHashInt(pathKey, encryptionKeyDerivationTweak, this.api.crypto); const cipherText = await encryptMutableBytes(data, encryptionKey, this.api.crypto); const cid = await this.api.uploadBlob(new Blob([cipherText])); const writeKey = deriveHashInt(pathKey, writeKeyDerivationTweak, this.api.crypto); const keyPair = await this.api.crypto.newKeyPairEd25519(writeKey); const sre = await createRegistryEntry(keyPair, cid.hash, revision, this.api.crypto); await this.api.registrySet(sre); return cid; } async getHiddenRawDataImplementation(pathKey) { const encryptionKey = deriveHashInt(pathKey, encryptionKeyDerivationTweak, this.api.crypto); const writeKey = deriveHashInt(pathKey, writeKeyDerivationTweak, this.api.crypto); const keyPair = await this.api.crypto.newKeyPairEd25519(writeKey); const sre = await this.api.registryGet(keyPair.publicKey); if (sre === undefined) { return { revision: -1 }; } const hash = sre.data.subarray(0, 33); const bytes = await this.api.downloadBlobAsBytes(hash); const plaintext = await decryptMutableBytes(bytes, encryptionKey, this.api.crypto); return { data: plaintext, cid: new BlobIdentifier(hash, 0), revision: sre.revision, }; } } //# sourceMappingURL=hidden_db.js.map