mock.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { CID } from "multiformats/cid";
  2. import { sha256 } from "multiformats/hashes/sha2";
  3. import { fromString, toString } from "uint8arrays";
  4. import {
  5. Name,
  6. NameAccumulator,
  7. PrivateDirectory,
  8. PrivateForest,
  9. AccessKey,
  10. PublicDirectory,
  11. } from "../dist/bundler/wnfs_wasm";
  12. /** A mock CID. */
  13. const sampleCID = CID.parse(
  14. "bagaaierasords4njcts6vs7qvdjfcvgnume4hqohf65zsfguprqphs3icwea"
  15. ).bytes;
  16. /**
  17. * An in-memory block store to simulate IPFS.
  18. *
  19. * IPFS is basically a glorified HashMap.
  20. */
  21. class MemoryBlockStore {
  22. private store: Map<string, Uint8Array>;
  23. /** Creates a new in-memory block store. */
  24. constructor() {
  25. this.store = new Map();
  26. }
  27. /** Stores an array of bytes in the block store. */
  28. async getBlock(cid: Uint8Array): Promise<Uint8Array | undefined> {
  29. const decodedCid = CID.decode(cid);
  30. return this.store.get(decodedCid.toString());
  31. }
  32. /** Retrieves an array of bytes from the block store with given CID. */
  33. async putBlockKeyed(cid: Uint8Array, bytes: Uint8Array): Promise<void> {
  34. const decodedCid = CID.decode(cid);
  35. this.store.set(decodedCid.toString(), bytes);
  36. }
  37. /** Finds out whether a block is retrievable from this blockstore */
  38. async hasBlock(cid: Uint8Array): Promise<boolean> {
  39. const decodedCid = CID.decode(cid);
  40. return this.store.has(decodedCid.toString());
  41. }
  42. }
  43. /** A pseudo-random number generator */
  44. class Rng {
  45. /** Returns random bytes of specified length */
  46. randomBytes(count: number): Uint8Array {
  47. const array = new Uint8Array(count);
  48. self.crypto.getRandomValues(array);
  49. return array;
  50. }
  51. }
  52. /** A mock exchange key. */
  53. class ExchangeKey {
  54. key: CryptoKey;
  55. constructor(key: CryptoKey) {
  56. this.key = key;
  57. }
  58. static async fromModulus(modulus: Uint8Array): Promise<ExchangeKey> {
  59. var keyData = {
  60. kty: "RSA",
  61. n: toString(modulus, "base64url"),
  62. e: toString(new Uint8Array([0x01, 0x00, 0x01]), "base64url"),
  63. alg: "RSA-OAEP-256",
  64. ext: true,
  65. };
  66. const key = await crypto.subtle.importKey(
  67. "jwk",
  68. keyData,
  69. {
  70. name: "RSA-OAEP",
  71. hash: { name: "SHA-256" },
  72. },
  73. false,
  74. ["encrypt"]
  75. );
  76. return new ExchangeKey(key);
  77. }
  78. async encrypt(data: Uint8Array): Promise<Uint8Array> {
  79. const encryptedData = await window.crypto.subtle.encrypt(
  80. {
  81. name: "RSA-OAEP",
  82. },
  83. this.key,
  84. data
  85. );
  86. return new Uint8Array(encryptedData);
  87. }
  88. async getPublicKeyModulus(): Promise<Uint8Array> {
  89. const key = await crypto.subtle.exportKey("jwk", this.key);
  90. return fromString(key.n as string, "base64url");
  91. }
  92. }
  93. /** A mock private key. */
  94. class PrivateKey {
  95. key: CryptoKeyPair;
  96. constructor(key: CryptoKeyPair) {
  97. this.key = key;
  98. }
  99. static async generate(): Promise<PrivateKey> {
  100. const keyPair = await crypto.subtle.generateKey(
  101. {
  102. name: "RSA-OAEP",
  103. modulusLength: 2048,
  104. publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
  105. hash: { name: "SHA-256" },
  106. },
  107. true,
  108. ["decrypt"]
  109. );
  110. return new PrivateKey(keyPair);
  111. }
  112. async decrypt(data: Uint8Array): Promise<Uint8Array> {
  113. const decryptedData = await window.crypto.subtle.decrypt(
  114. {
  115. name: "RSA-OAEP",
  116. },
  117. this.key.privateKey,
  118. data
  119. );
  120. return new Uint8Array(decryptedData);
  121. }
  122. getPublicKey(): ExchangeKey {
  123. return new ExchangeKey(this.key.publicKey);
  124. }
  125. }
  126. const createSharerDir = async (
  127. initialForest: PrivateForest,
  128. store: MemoryBlockStore,
  129. rng: Rng
  130. ): Promise<{ rootDir: PrivateDirectory; forest: PrivateForest }> => {
  131. var { rootDir, forest } = await PrivateDirectory.newAndStore(
  132. initialForest.emptyName(),
  133. new Date(),
  134. initialForest,
  135. store,
  136. rng
  137. );
  138. return await rootDir.write(
  139. ["text.txt"],
  140. true,
  141. new Uint8Array([1, 2, 3, 4, 5]),
  142. new Date(),
  143. forest,
  144. store,
  145. rng
  146. );
  147. };
  148. const createRecipientExchangeRoot = async (
  149. store: MemoryBlockStore
  150. ): Promise<[PrivateKey, PublicDirectory]> => {
  151. const key = await PrivateKey.generate();
  152. const exchangeKey = await key.getPublicKey().getPublicKeyModulus();
  153. const { rootDir } = await new PublicDirectory(new Date()).write(
  154. ["device1", "v1.exchange_key"],
  155. exchangeKey,
  156. new Date(),
  157. store
  158. );
  159. return [key, rootDir];
  160. };
  161. class Sha256BlockStore {
  162. private store: Map<string, Uint8Array>;
  163. constructor() {
  164. this.store = new Map();
  165. }
  166. async getBlock(cid: Uint8Array): Promise<Uint8Array | undefined> {
  167. const decodedCid = CID.decode(cid);
  168. return this.store.get(decodedCid.toString());
  169. }
  170. async putBlockKeyed(cid: Uint8Array, bytes: Uint8Array): Promise<void> {
  171. const decodedCid = CID.decode(cid);
  172. this.store.set(decodedCid.toString(), bytes);
  173. }
  174. async hasBlock(cid: Uint8Array): Promise<boolean> {
  175. const decodedCid = CID.decode(cid);
  176. return this.store.has(decodedCid.toString());
  177. }
  178. // We overwrite the putBlock method
  179. async putBlock(bytes: Uint8Array, codec: number): Promise<Uint8Array> {
  180. const hash = await sha256.digest(bytes);
  181. const cid = CID.create(1, codec, hash);
  182. this.store.set(cid.toString(), bytes);
  183. return cid.bytes;
  184. }
  185. }
  186. export {
  187. sampleCID,
  188. CID,
  189. MemoryBlockStore,
  190. Sha256BlockStore,
  191. Rng,
  192. createSharerDir,
  193. createRecipientExchangeRoot,
  194. PrivateKey,
  195. ExchangeKey,
  196. AccessKey,
  197. };