Skip to content

Commit ef3f1c9

Browse files
authored
Complete the Jest DI with crypto (#234)
* Use ipfs-core instead of ipfs for a lighter dependency * Make yarn node --version be 15.x in nix-shell * Implement the complete crypto DI for node * Fix cbor encode/decode errors on node Switch to using Uint8Arrays instead of node Buffers. This is something the js-ipfs folks apparently have gone through, too: ipfs/js-ipfs#3220 * ESLint fixes * Fix eslint errors in index.ts * Revert "Fix cbor encode/decode errors on node" This reverts commit dbc3b3d. * Fix type * Test cbor en/decoding * Implement helper for totally in-memory ipfs * Add integration test & fix filesystem running in node * Remove logging * Use types added to the workaround repo * Fix CBOR decoding errors of encrypted data in node * Switch back to borc * Update jest & puppeteer & base58-universal * Add jest puppeteer types * Make it possible to run multiple ipfs in-memory If I didn't disable swarm addresses, then multiple instances of ipfs would request socket access and block each other. * Actually switch back from cborg to borc * Remove unneeded Buffer.from call * Make jest properly exit after all tests * wtfnode * Revert "wtfnode" This reverts commit 5cbfd03. * Force jest to exit, even if ipfs holds resources * Revert "Make jest properly exit after all tests" This reverts commit eab6bc8.
1 parent be38e88 commit ef3f1c9

15 files changed

+1525
-2404
lines changed

package.json

+10-6
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"prebuild": "rimraf dist && node scripts/gen-version.js",
3737
"build": "tsc && rollup -c rollup.config.ts",
3838
"start": "tsc -w",
39-
"test": "jest",
39+
"test": "jest --forceExit",
4040
"test:watch": "jest --watch",
4141
"test:prod": "yarn run build && yarn run lint && yarn run test -- --no-cache",
4242
"test:types": "cp -RT tests/types/ dist/ && yarn run tsd",
@@ -61,12 +61,14 @@
6161
"@babel/core": "^7.12.10",
6262
"@babel/preset-env": "^7.12.7",
6363
"@babel/preset-typescript": "^7.12.7",
64+
"@ipld/car": "https://github.com/matheus23/ipld-car-jest-fix#28fa48a8d0e701ddaf6e4785d0d9f08735b67bc8",
6465
"@rollup/plugin-babel": "^5.2.2",
6566
"@rollup/plugin-commonjs": "^17.0.0",
6667
"@rollup/plugin-inject": "^4.0.2",
6768
"@rollup/plugin-json": "^4.1.0",
6869
"@rollup/plugin-node-resolve": "^11.1.0",
6970
"@types/jest": "^26.0.20",
71+
"@types/jest-environment-puppeteer": "^4.4.1",
7072
"@types/node": "^13.7.4",
7173
"@types/throttle-debounce": "^2.1.0",
7274
"@typescript-eslint/eslint-plugin": "^4.24.0",
@@ -75,15 +77,16 @@
7577
"braces": "^3.0.2",
7678
"eslint": "^7.26.0",
7779
"fast-check": "^2.14.0",
78-
"ipfs": "^0.54.4",
80+
"interface-datastore": "^4.0.1",
81+
"ipfs-repo": "^9.1.6",
7982
"jest": "^26.6.3",
8083
"jest-config": "^26.6.3",
81-
"jest-puppeteer": "^4.4.0",
84+
"jest-puppeteer": "^5.0.3",
8285
"lint-staged": "^10.5.3",
8386
"multihashing-async": "^2.1.2",
8487
"prettier": "^1.19.1",
8588
"prompt": "^1.1.0",
86-
"puppeteer": "^5.5.0",
89+
"puppeteer": "^9.1.1",
8790
"replace-in-file": "^5.0.2",
8891
"rimraf": "^3.0.2",
8992
"rollup": "^2.37.1",
@@ -99,11 +102,12 @@
99102
"yarn": "^1.22.4"
100103
},
101104
"dependencies": {
102-
"base58-universal": "^1.0.0",
103-
"borc": "^2.1.1",
105+
"base58-universal": "https://github.com/digitalbazaar/base58-universal#de970560f005de0f7054723c35ef6e0ff4b328b7",
106+
"borc": "^3.0.0",
104107
"buffer": "^6.0.3",
105108
"cids": "^1.1.5",
106109
"fission-bloom-filters": "1.6.0",
110+
"ipfs-core": "^0.6.1",
107111
"ipfs-message-port-client": "https://ipfs.runfission.com/ipfs/bafybeigx6q4aezve7my76s5vvfuiinbxtepapqvmjf2jbgrozrut6cjape/p/ipfs-message-port-client.tar.gz",
108112
"ipfs-message-port-protocol": "https://ipfs.runfission.com/ipfs/bafybeigx6q4aezve7my76s5vvfuiinbxtepapqvmjf2jbgrozrut6cjape/p/ipfs-message-port-protocol.tar.gz",
109113
"ipld-dag-pb": "^0.20.0",

shell.nix

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ in
66

77
pkgs.mkShell {
88
buildInputs = [
9-
unstable.yarn
9+
# https://github.com/NixOS/nixpkgs/issues/53820#issuecomment-617973476
10+
(unstable.yarn.override { nodejs = null; })
1011
unstable.nodejs-15_x
1112
unstable.niv
1213
];

src/@types/index.d.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
declare module 'base58-universal/main.js'
2-
declare module 'borc'
1+
declare module 'base58-universal' {
2+
export function encode(input: Uint8Array, maxline?: number): string
3+
export function decode(input: string): Uint8Array
4+
}
35
declare module 'ipld-dag-pb'
6+
declare module 'borc'

src/did/transformers.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import * as base58 from 'base58-universal/main.js'
2-
1+
import * as base58 from 'base58-universal'
32
import * as utils from 'keystore-idb/utils'
43

54
import { BASE58_DID_PREFIX, magicBytes, parseMagicBytes } from './util'

src/fs/filesystem.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ type MutationOptions = {
5656
export class FileSystem {
5757

5858
root: RootTree
59-
localOnly: boolean
59+
readonly localOnly: boolean
6060

6161
appPath: AppPath | undefined
6262
proofs: { [_: string]: string }
@@ -115,11 +115,13 @@ export class FileSystem {
115115
this.publishHooks.push(logCid)
116116
this.publishHooks.push(updateDataRootWhenOnline)
117117

118-
// Publish when coming back online
119-
globalThis.addEventListener('online', this._whenOnline)
120-
121-
// Show an alert when leaving the page while updating the data root
122-
globalThis.addEventListener('beforeunload', this._beforeLeaving)
118+
if (!this.localOnly) {
119+
// Publish when coming back online
120+
globalThis.addEventListener('online', this._whenOnline)
121+
122+
// Show an alert when leaving the page while updating the data root
123+
globalThis.addEventListener('beforeunload', this._beforeLeaving)
124+
}
123125
}
124126

125127

@@ -170,6 +172,7 @@ export class FileSystem {
170172
* The only function of this is to stop listing to online/offline events.
171173
*/
172174
deactivate(): void {
175+
if (this.localOnly) return
173176
const globe = (globalThis as any)
174177
globe.filesystems = globe.filesystems.filter((a: FileSystem) => a !== this)
175178
globe.removeEventListener('online', this._whenOnline)

src/fs/protocol/private/mmpt.test.ts

+18-15
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import crypto from "crypto"
2-
import Ipfs, { IPFS } from "ipfs"
2+
import { IPFS } from "ipfs-core"
33

44
import MMPT from "./mmpt"
55
import * as ipfsConfig from "../../../ipfs/config"
6+
import { createInMemoryIPFS } from "../../../../tests/helpers/in-memory-ipfs"
67

78
function sha256Str(str: string): string {
89
return crypto.createHash('sha256').update(str).digest('hex')
@@ -12,7 +13,20 @@ function encode(str: string): Uint8Array {
1213
return (new TextEncoder()).encode(str)
1314
}
1415

15-
let ipfs: IPFS;
16+
17+
let ipfs: IPFS | null = null
18+
19+
beforeAll(async done => {
20+
ipfs = await createInMemoryIPFS()
21+
ipfsConfig.set(ipfs)
22+
done()
23+
})
24+
25+
afterAll(async done => {
26+
if (ipfs == null) return
27+
await ipfs.stop()
28+
done()
29+
})
1630

1731
/*
1832
Generates lots of entries for insertion into the MMPT.
@@ -22,8 +36,8 @@ The MMPT is a glorified key-value store.
2236
This returns an array of key-values sorted by the key,
2337
so that key collisions are more likely to be tested.
2438
*/
25-
async function generateExampleEntries(amount: number): Promise<{ name: string, cid: string }[]> {
26-
let entries: { name: string, cid: string }[] = []
39+
async function generateExampleEntries(amount: number): Promise<{ name: string; cid: string }[]> {
40+
const entries: { name: string; cid: string }[] = []
2741

2842
for (const i of Array(amount).keys()) {
2943
const hash = sha256Str(`${i}`)
@@ -39,17 +53,6 @@ async function generateExampleEntries(amount: number): Promise<{ name: string, c
3953

4054

4155

42-
beforeAll(async done => {
43-
ipfs = await Ipfs.create({ offline: true, silent: true })
44-
ipfsConfig.set(ipfs)
45-
done()
46-
})
47-
48-
afterAll(async done => {
49-
await ipfs.stop()
50-
done()
51-
})
52-
5356
describe("the mmpt", () => {
5457
it("can handle concurrent adds", async () => {
5558
const mmpt = MMPT.create()

src/index.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export type Continuation = {
7272
permissions: Maybe<Permissions>
7373

7474
authenticated: true
75-
newUser: false,
75+
newUser: false
7676
throughLobby: false
7777
username: string
7878

@@ -172,7 +172,7 @@ export async function initialise(
172172
)
173173

174174
} else if (cancellation) {
175-
const c = (_ => {
175+
const c = (() => {
176176
switch (cancellation) {
177177
case "DENIED": return "User denied authorisation"
178178
default: return "Unknown reason"
@@ -256,6 +256,7 @@ export * as ipfs from './ipfs'
256256
export * as keystore from './keystore'
257257
export * as machinery from './common'
258258
export * as crypto from './crypto'
259+
export * as cbor from 'borc'
259260

260261

261262

@@ -345,7 +346,7 @@ async function importClassifiedInfo(
345346
const secretsStr = await crypto.aes.decryptGCM(info.secrets, rawSessionKey, info.iv)
346347
const secrets = JSON.parse(secretsStr)
347348

348-
const fsSecrets: Record<string, { key: string, bareNameFilter: string }> = secrets.fs
349+
const fsSecrets: Record<string, { key: string; bareNameFilter: string }> = secrets.fs
349350
const ucans = secrets.ucans
350351

351352
// Import read keys and bare name filters
@@ -365,7 +366,7 @@ async function importClassifiedInfo(
365366
}
366367

367368
async function getClassifiedViaPostMessage(): Promise<string> {
368-
const iframe: HTMLIFrameElement = await new Promise((resolve, reject) => {
369+
const iframe: HTMLIFrameElement = await new Promise(resolve => {
369370
const iframe = document.createElement("iframe")
370371
iframe.id = "webnative-secret-exchange"
371372
iframe.style.width = "0"

src/ipfs/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export type IPFS = {
2-
add(data: FileContent, options?: unknown): UnixFSFile
2+
add(data: FileContent, options?: unknown): Promise<UnixFSFile>
33
cat(cid: CID): AsyncIterable<FileContentRaw>
44
ls(cid: CID): AsyncIterable<UnixFSFile>
55
dns(domain: string): Promise<CID>

0 commit comments

Comments
 (0)