import { CID } from "multiformats/cid"; import { sha256 } from "multiformats/hashes/sha2"; import { fromString, toString } from "uint8arrays"; import { Name, NameAccumulator, PrivateDirectory, PrivateForest, AccessKey, PublicDirectory, } from "../dist/bundler/wnfs_wasm"; /** A mock CID. */ const sampleCID = CID.parse( "bagaaierasords4njcts6vs7qvdjfcvgnume4hqohf65zsfguprqphs3icwea" ).bytes; /** * An in-memory block store to simulate IPFS. * * IPFS is basically a glorified HashMap. */ class MemoryBlockStore { private store: Map; /** Creates a new in-memory block store. */ constructor() { this.store = new Map(); } /** Stores an array of bytes in the block store. */ async getBlock(cid: Uint8Array): Promise { const decodedCid = CID.decode(cid); return this.store.get(decodedCid.toString()); } /** Retrieves an array of bytes from the block store with given CID. */ async putBlockKeyed(cid: Uint8Array, bytes: Uint8Array): Promise { const decodedCid = CID.decode(cid); this.store.set(decodedCid.toString(), bytes); } /** Finds out whether a block is retrievable from this blockstore */ async hasBlock(cid: Uint8Array): Promise { const decodedCid = CID.decode(cid); return this.store.has(decodedCid.toString()); } } /** A pseudo-random number generator */ class Rng { /** Returns random bytes of specified length */ randomBytes(count: number): Uint8Array { const array = new Uint8Array(count); self.crypto.getRandomValues(array); return array; } } /** A mock exchange key. */ class ExchangeKey { key: CryptoKey; constructor(key: CryptoKey) { this.key = key; } static async fromModulus(modulus: Uint8Array): Promise { var keyData = { kty: "RSA", n: toString(modulus, "base64url"), e: toString(new Uint8Array([0x01, 0x00, 0x01]), "base64url"), alg: "RSA-OAEP-256", ext: true, }; const key = await crypto.subtle.importKey( "jwk", keyData, { name: "RSA-OAEP", hash: { name: "SHA-256" }, }, false, ["encrypt"] ); return new ExchangeKey(key); } async encrypt(data: Uint8Array): Promise { const encryptedData = await window.crypto.subtle.encrypt( { name: "RSA-OAEP", }, this.key, data ); return new Uint8Array(encryptedData); } async getPublicKeyModulus(): Promise { const key = await crypto.subtle.exportKey("jwk", this.key); return fromString(key.n as string, "base64url"); } } /** A mock private key. */ class PrivateKey { key: CryptoKeyPair; constructor(key: CryptoKeyPair) { this.key = key; } static async generate(): Promise { const keyPair = await crypto.subtle.generateKey( { name: "RSA-OAEP", modulusLength: 2048, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: "SHA-256" }, }, true, ["decrypt"] ); return new PrivateKey(keyPair); } async decrypt(data: Uint8Array): Promise { const decryptedData = await window.crypto.subtle.decrypt( { name: "RSA-OAEP", }, this.key.privateKey, data ); return new Uint8Array(decryptedData); } getPublicKey(): ExchangeKey { return new ExchangeKey(this.key.publicKey); } } const createSharerDir = async ( initialForest: PrivateForest, store: MemoryBlockStore, rng: Rng ): Promise<{ rootDir: PrivateDirectory; forest: PrivateForest }> => { var { rootDir, forest } = await PrivateDirectory.newAndStore( initialForest.emptyName(), new Date(), initialForest, store, rng ); return await rootDir.write( ["text.txt"], true, new Uint8Array([1, 2, 3, 4, 5]), new Date(), forest, store, rng ); }; const createRecipientExchangeRoot = async ( store: MemoryBlockStore ): Promise<[PrivateKey, PublicDirectory]> => { const key = await PrivateKey.generate(); const exchangeKey = await key.getPublicKey().getPublicKeyModulus(); const { rootDir } = await new PublicDirectory(new Date()).write( ["device1", "v1.exchange_key"], exchangeKey, new Date(), store ); return [key, rootDir]; }; class Sha256BlockStore { private store: Map; constructor() { this.store = new Map(); } async getBlock(cid: Uint8Array): Promise { const decodedCid = CID.decode(cid); return this.store.get(decodedCid.toString()); } async putBlockKeyed(cid: Uint8Array, bytes: Uint8Array): Promise { const decodedCid = CID.decode(cid); this.store.set(decodedCid.toString(), bytes); } async hasBlock(cid: Uint8Array): Promise { const decodedCid = CID.decode(cid); return this.store.has(decodedCid.toString()); } // We overwrite the putBlock method async putBlock(bytes: Uint8Array, codec: number): Promise { const hash = await sha256.digest(bytes); const cid = CID.create(1, codec, hash); this.store.set(cid.toString(), bytes); return cid.bytes; } } export { sampleCID, CID, MemoryBlockStore, Sha256BlockStore, Rng, createSharerDir, createRecipientExchangeRoot, PrivateKey, ExchangeKey, AccessKey, };