@fireproof/core 0.19.8-dev-global → 0.19.8-dev-series-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/chunk-7EWIAXTM.js +7 -0
- package/chunk-7EWIAXTM.js.map +1 -0
- package/chunk-OFGPKRCM.js +290 -0
- package/chunk-OFGPKRCM.js.map +1 -0
- package/chunk-PB4BKL4O.js +7 -0
- package/chunk-PB4BKL4O.js.map +1 -0
- package/chunk-WS3YRPIA.js +75 -0
- package/chunk-WS3YRPIA.js.map +1 -0
- package/deno.json +22 -0
- package/gateway-5FCWPX5W.js +144 -0
- package/gateway-5FCWPX5W.js.map +1 -0
- package/{store-indexdb-WLRSICCB.js → gateway-H7UD6TNB.js} +49 -82
- package/gateway-H7UD6TNB.js.map +1 -0
- package/index.cjs +2365 -1875
- package/index.cjs.map +1 -1
- package/index.d.cts +663 -535
- package/index.d.ts +663 -535
- package/index.global.js +26742 -20717
- package/index.global.js.map +1 -1
- package/index.js +1691 -1094
- package/index.js.map +1 -1
- package/key-bag-file-WADZBHYG.js +54 -0
- package/key-bag-file-WADZBHYG.js.map +1 -0
- package/key-bag-indexdb-PGVAI3FJ.js +50 -0
- package/key-bag-indexdb-PGVAI3FJ.js.map +1 -0
- package/mem-filesystem-YPPJV7Q2.js +41 -0
- package/mem-filesystem-YPPJV7Q2.js.map +1 -0
- package/metafile-cjs.json +1 -1
- package/metafile-esm.json +1 -1
- package/metafile-iife.json +1 -1
- package/node-filesystem-INX4ZTHE.js +45 -0
- package/node-filesystem-INX4ZTHE.js.map +1 -0
- package/package.json +14 -8
- package/tests/blockstore/fragment-gateway.test.ts +107 -0
- package/tests/blockstore/keyed-crypto.test.ts +332 -0
- package/tests/blockstore/loader.test.ts +24 -19
- package/tests/blockstore/store.test.ts +51 -40
- package/tests/blockstore/transaction.test.ts +19 -15
- package/tests/fireproof/all-gateway.test.ts +394 -0
- package/tests/fireproof/cars/bafkreidxwt2nhvbl4fnqfw3ctlt6zbrir4kqwmjo5im6rf4q5si27kgo2i.car +0 -0
- package/tests/fireproof/cars/bafkreidxwt2nhvbl4fnqfw3ctlt6zbrir4kqwmjo5im6rf4q5si27kgo2i.ts +316 -0
- package/tests/fireproof/config.test.ts +94 -78
- package/tests/fireproof/crdt.test.ts +34 -28
- package/tests/fireproof/database.test.ts +22 -14
- package/tests/fireproof/fireproof.test.fixture.ts +133 -0
- package/tests/fireproof/fireproof.test.ts +331 -219
- package/tests/fireproof/hello.test.ts +34 -18
- package/tests/fireproof/indexer.test.ts +34 -27
- package/tests/fireproof/utils.test.ts +84 -0
- package/tests/helpers.ts +28 -57
- package/tests/www/todo-local.html +1 -1
- package/tests/www/todo.html +12 -15
- package/utils-QO2HIWGI.js +14 -0
- package/utils-QO2HIWGI.js.map +1 -0
- package/chunk-BNL4PVBF.js +0 -314
- package/chunk-BNL4PVBF.js.map +0 -1
- package/chunk-JW2QT6BF.js +0 -184
- package/chunk-JW2QT6BF.js.map +0 -1
- package/node-sys-container-MIEX6ELJ.js +0 -29
- package/node-sys-container-MIEX6ELJ.js.map +0 -1
- package/store-file-VJ6BI4II.js +0 -191
- package/store-file-VJ6BI4II.js.map +0 -1
- package/store-indexdb-WLRSICCB.js.map +0 -1
@@ -0,0 +1,45 @@
|
|
1
|
+
import {
|
2
|
+
toArrayBuffer
|
3
|
+
} from "./chunk-WS3YRPIA.js";
|
4
|
+
import "./chunk-OFGPKRCM.js";
|
5
|
+
|
6
|
+
// src/runtime/gateways/file/node-filesystem.ts
|
7
|
+
import { runtimeFn } from "@adviser/cement";
|
8
|
+
var NodeFileSystem = class {
|
9
|
+
async start() {
|
10
|
+
this.fs = await import("node:fs/promises");
|
11
|
+
return this;
|
12
|
+
}
|
13
|
+
async mkdir(path, options) {
|
14
|
+
return this.fs?.mkdir(path, options);
|
15
|
+
}
|
16
|
+
async readdir(path, options) {
|
17
|
+
return this.fs?.readdir(path, options);
|
18
|
+
}
|
19
|
+
async rm(path, options) {
|
20
|
+
return this.fs?.rm(path, options);
|
21
|
+
}
|
22
|
+
async copyFile(source, destination) {
|
23
|
+
return this.fs?.copyFile(source, destination);
|
24
|
+
}
|
25
|
+
async readfile(path, options) {
|
26
|
+
const ret = await this.fs?.readFile(path, options);
|
27
|
+
return toArrayBuffer(ret);
|
28
|
+
}
|
29
|
+
stat(path) {
|
30
|
+
return this.fs?.stat(path);
|
31
|
+
}
|
32
|
+
async unlink(path) {
|
33
|
+
return this.fs?.unlink(path);
|
34
|
+
}
|
35
|
+
async writefile(path, data) {
|
36
|
+
if (runtimeFn().isDeno) {
|
37
|
+
return this.fs?.writeFile(path, data);
|
38
|
+
}
|
39
|
+
return this.fs?.writeFile(path, Buffer.from(data));
|
40
|
+
}
|
41
|
+
};
|
42
|
+
export {
|
43
|
+
NodeFileSystem
|
44
|
+
};
|
45
|
+
//# sourceMappingURL=node-filesystem-INX4ZTHE.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/gateways/file/node-filesystem.ts"],"sourcesContent":["import type { PathLike, MakeDirectoryOptions, Stats, ObjectEncodingOptions } from \"node:fs\";\nimport type { mkdir, readdir, rm, copyFile, readFile, stat, unlink, writeFile } from \"node:fs/promises\";\nimport { toArrayBuffer } from \"./utils.js\";\nimport { SysFileSystem } from \"../../../types.js\";\nimport { runtimeFn } from \"@adviser/cement\";\n\nexport class NodeFileSystem implements SysFileSystem {\n fs?: {\n mkdir: typeof mkdir;\n readdir: typeof readdir;\n rm: typeof rm;\n copyFile: typeof copyFile;\n readFile: typeof readFile;\n stat: typeof stat;\n unlink: typeof unlink;\n writeFile: typeof writeFile;\n };\n\n async start(): Promise<SysFileSystem> {\n this.fs = await import(\"node:fs/promises\");\n return this;\n }\n async mkdir(path: PathLike, options?: { recursive: boolean }): Promise<string | undefined> {\n return this.fs?.mkdir(path, options);\n }\n async readdir(path: PathLike, options?: ObjectEncodingOptions): Promise<string[]> {\n return this.fs?.readdir(path, options) as Promise<string[]>;\n }\n async rm(path: PathLike, options?: MakeDirectoryOptions & { recursive: boolean }): Promise<void> {\n return this.fs?.rm(path, options);\n }\n async copyFile(source: PathLike, destination: PathLike): Promise<void> {\n return this.fs?.copyFile(source, destination);\n }\n async readfile(path: PathLike, options?: { encoding: BufferEncoding; flag?: string }): Promise<Uint8Array> {\n const ret = (await this.fs?.readFile(path, options)) as Buffer;\n return toArrayBuffer(ret);\n }\n stat(path: PathLike): Promise<Stats> {\n return this.fs?.stat(path) as Promise<Stats>;\n }\n async unlink(path: PathLike): Promise<void> {\n return this.fs?.unlink(path);\n }\n async writefile(path: PathLike, data: Uint8Array | string): Promise<void> {\n if (runtimeFn().isDeno) {\n return this.fs?.writeFile(path, data);\n }\n return this.fs?.writeFile(path, Buffer.from(data));\n }\n}\n\n// import { type NodeMap, join } from \"../../sys-container.js\";\n// import type { ObjectEncodingOptions, PathLike } from \"fs\";\n// import * as fs from \"fs/promises\";\n// import * as path from \"path\";\n// import * as os from \"os\";\n// import * as url from \"url\";\n// import { toArrayBuffer } from \"./utils.js\";\n\n// export async function createNodeSysContainer(): Promise<NodeMap> {\n// // const nodePath = \"node:path\";\n// // const nodeOS = \"node:os\";\n// // const nodeURL = \"node:url\";\n// // const nodeFS = \"node:fs\";\n// // const fs = (await import(\"node:fs\")).promises;\n// // const assert = \"assert\";\n// // const path = await import(\"node:path\");\n// return {\n// state: \"node\",\n// ...path,\n// // ...(await import(\"node:os\")),\n// // ...(await import(\"node:url\")),\n// ...os,\n// ...url,\n// ...fs,\n// join,\n// stat: fs.stat as NodeMap[\"stat\"],\n// readdir: fs.readdir as NodeMap[\"readdir\"],\n// readfile: async (path: PathLike, options?: ObjectEncodingOptions): Promise<Uint8Array> => {\n// const rs = await fs.readFile(path, options);\n// return toArrayBuffer(rs);\n// },\n// writefile: fs.writeFile as NodeMap[\"writefile\"],\n// };\n// }\n"],"mappings":";;;;;;AAIA,SAAS,iBAAiB;AAEnB,IAAM,iBAAN,MAA8C;AAAA,EAYnD,MAAM,QAAgC;AACpC,SAAK,KAAK,MAAM,OAAO,kBAAkB;AACzC,WAAO;AAAA,EACT;AAAA,EACA,MAAM,MAAM,MAAgB,SAA+D;AACzF,WAAO,KAAK,IAAI,MAAM,MAAM,OAAO;AAAA,EACrC;AAAA,EACA,MAAM,QAAQ,MAAgB,SAAoD;AAChF,WAAO,KAAK,IAAI,QAAQ,MAAM,OAAO;AAAA,EACvC;AAAA,EACA,MAAM,GAAG,MAAgB,SAAwE;AAC/F,WAAO,KAAK,IAAI,GAAG,MAAM,OAAO;AAAA,EAClC;AAAA,EACA,MAAM,SAAS,QAAkB,aAAsC;AACrE,WAAO,KAAK,IAAI,SAAS,QAAQ,WAAW;AAAA,EAC9C;AAAA,EACA,MAAM,SAAS,MAAgB,SAA4E;AACzG,UAAM,MAAO,MAAM,KAAK,IAAI,SAAS,MAAM,OAAO;AAClD,WAAO,cAAc,GAAG;AAAA,EAC1B;AAAA,EACA,KAAK,MAAgC;AACnC,WAAO,KAAK,IAAI,KAAK,IAAI;AAAA,EAC3B;AAAA,EACA,MAAM,OAAO,MAA+B;AAC1C,WAAO,KAAK,IAAI,OAAO,IAAI;AAAA,EAC7B;AAAA,EACA,MAAM,UAAU,MAAgB,MAA0C;AACxE,QAAI,UAAU,EAAE,QAAQ;AACtB,aAAO,KAAK,IAAI,UAAU,MAAM,IAAI;AAAA,IACtC;AACA,WAAO,KAAK,IAAI,UAAU,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,EACnD;AACF;","names":[]}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@fireproof/core",
|
3
|
-
"version": "0.19.8-dev-
|
3
|
+
"version": "0.19.8-dev-series-2",
|
4
4
|
"description": "Live database for the web.",
|
5
5
|
"type": "module",
|
6
6
|
"module": "./index.js",
|
@@ -46,17 +46,23 @@
|
|
46
46
|
"react": ">=18.0.0"
|
47
47
|
},
|
48
48
|
"dependencies": {
|
49
|
-
"
|
50
|
-
"
|
49
|
+
"@adviser/cement": "^0.2.31",
|
50
|
+
"multiformats": "^13.3.0",
|
51
|
+
"@ipld/unixfs": "^3.0.0",
|
52
|
+
"@ipld/car": "^5.3.2",
|
53
|
+
"@ipld/dag-json": "^10.2.2",
|
54
|
+
"@ipld/dag-cbor": "^9.2.1",
|
55
|
+
"@web3-storage/pail": "^0.6.0",
|
56
|
+
"cborg": "^4.2.4",
|
51
57
|
"charwise": "^3.0.1",
|
52
58
|
"prolly-trees": "^1.0.4",
|
53
59
|
"idb": "^8.0.0",
|
54
|
-
"ipfs-unixfs-exporter": "^13.
|
55
|
-
"
|
60
|
+
"ipfs-unixfs-exporter": "^13.6.1",
|
61
|
+
"memfs": "^4.12.0",
|
56
62
|
"p-limit": "^6.1.0",
|
57
|
-
"
|
58
|
-
"
|
59
|
-
"
|
63
|
+
"react": "^18.3.1",
|
64
|
+
"p-map": "^7.0.2",
|
65
|
+
"p-retry": "^6.2.0"
|
60
66
|
},
|
61
67
|
"scripts": {}
|
62
68
|
}
|
@@ -0,0 +1,107 @@
|
|
1
|
+
import { Result, URI } from "@adviser/cement";
|
2
|
+
import { mockSuperThis } from "../helpers";
|
3
|
+
import { bs } from "@fireproof/core";
|
4
|
+
|
5
|
+
class TraceGateway implements bs.Gateway {
|
6
|
+
readonly buildUrlFn = vitest.fn();
|
7
|
+
|
8
|
+
readonly fragSize: number;
|
9
|
+
constructor(fragSize = 0) {
|
10
|
+
this.fragSize = fragSize;
|
11
|
+
}
|
12
|
+
|
13
|
+
buildUrl(baseUrl: URI, key: string): Promise<Result<URI>> {
|
14
|
+
this.buildUrlFn(baseUrl, key);
|
15
|
+
return Promise.resolve(Result.Ok(baseUrl.build().setParam("key", key).URI()));
|
16
|
+
}
|
17
|
+
readonly startFn = vitest.fn();
|
18
|
+
start(baseUrl: URI): Promise<Result<URI>> {
|
19
|
+
this.startFn(baseUrl);
|
20
|
+
const burl = baseUrl.build();
|
21
|
+
if (this.fragSize) {
|
22
|
+
burl.setParam("fragSize", this.fragSize.toString());
|
23
|
+
}
|
24
|
+
return Promise.resolve(Result.Ok(burl.URI()));
|
25
|
+
}
|
26
|
+
readonly closeFn = vitest.fn();
|
27
|
+
close(baseUrl: URI): Promise<bs.VoidResult> {
|
28
|
+
this.closeFn(baseUrl);
|
29
|
+
return Promise.resolve(Result.Ok(undefined));
|
30
|
+
}
|
31
|
+
readonly destroyFn = vitest.fn();
|
32
|
+
destroy(baseUrl: URI): Promise<bs.VoidResult> {
|
33
|
+
this.destroyFn(baseUrl);
|
34
|
+
return Promise.resolve(Result.Ok(undefined));
|
35
|
+
}
|
36
|
+
readonly getFn = vitest.fn();
|
37
|
+
putCalls = 0;
|
38
|
+
async get(url: URI): Promise<Result<Uint8Array>> {
|
39
|
+
const idx = this.putCalls++;
|
40
|
+
this.getFn(url);
|
41
|
+
return Result.Ok(this.putFn.mock.calls[idx][1]);
|
42
|
+
}
|
43
|
+
readonly putFn = vitest.fn();
|
44
|
+
async put(url: URI, data: Uint8Array): Promise<Result<void>> {
|
45
|
+
this.putFn(url, data);
|
46
|
+
return Result.Ok(undefined);
|
47
|
+
}
|
48
|
+
readonly deleteFn = vitest.fn();
|
49
|
+
async delete(url: URI): Promise<Result<void>> {
|
50
|
+
this.deleteFn(url);
|
51
|
+
return Result.Ok(undefined);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
describe("FragmentGateway", () => {
|
56
|
+
const sthis = mockSuperThis();
|
57
|
+
it("passthrough", async () => {
|
58
|
+
const innerGW = new TraceGateway();
|
59
|
+
const fgw = new bs.FragmentGateway(sthis, innerGW);
|
60
|
+
const url = URI.from("http://example.com?key=3333");
|
61
|
+
|
62
|
+
expect(await fgw.put(url, new Uint8Array([1, 2, 3, 4]))).toEqual(Result.Ok(undefined));
|
63
|
+
expect(innerGW.putFn).toHaveBeenCalledWith(url, new Uint8Array([1, 2, 3, 4]));
|
64
|
+
|
65
|
+
expect(await fgw.get(url)).toEqual(Result.Ok(new Uint8Array([1, 2, 3, 4])));
|
66
|
+
expect(innerGW.getFn).toHaveBeenCalledWith(url);
|
67
|
+
});
|
68
|
+
|
69
|
+
function slice(total: number, headerSize: number, fragSize: number): { len?: string; ofs: string }[] {
|
70
|
+
const res = [];
|
71
|
+
for (let ofs = 0; ofs < total; ofs += fragSize - headerSize) {
|
72
|
+
res.push({ len: total.toString(), ofs: ofs.toString() });
|
73
|
+
}
|
74
|
+
return res;
|
75
|
+
}
|
76
|
+
|
77
|
+
it("enable frag", async () => {
|
78
|
+
const innerGW = new TraceGateway(128);
|
79
|
+
const fgw = new bs.FragmentGateway(sthis, innerGW);
|
80
|
+
const url = (await fgw.start(URI.from("http://example.com?key=3333"))).Ok();
|
81
|
+
const buf = new Uint8Array(1024).fill(1).map((_, i) => i);
|
82
|
+
|
83
|
+
expect(await fgw.put(url, buf)).toEqual(Result.Ok(undefined));
|
84
|
+
|
85
|
+
const ref = slice(1024, fgw.headerSize, 128);
|
86
|
+
|
87
|
+
expect(
|
88
|
+
innerGW.putFn.mock.calls.map((i) => {
|
89
|
+
return {
|
90
|
+
len: i[0].getParam("len"),
|
91
|
+
ofs: i[0].getParam("ofs"),
|
92
|
+
};
|
93
|
+
}),
|
94
|
+
).toEqual(ref);
|
95
|
+
|
96
|
+
expect((await fgw.get(url)).Ok()).toEqual(buf);
|
97
|
+
ref[0].len = undefined;
|
98
|
+
expect(
|
99
|
+
innerGW.getFn.mock.calls.map((i) => {
|
100
|
+
return {
|
101
|
+
len: i[0].getParam("len"),
|
102
|
+
ofs: i[0].getParam("ofs"),
|
103
|
+
};
|
104
|
+
}),
|
105
|
+
).toEqual(ref);
|
106
|
+
});
|
107
|
+
});
|
@@ -0,0 +1,332 @@
|
|
1
|
+
import { bs, rt } from "@fireproof/core";
|
2
|
+
import { BuildURI, Logger, MockLogger, runtimeFn, toCryptoRuntime, URI } from "@adviser/cement";
|
3
|
+
import { base58btc } from "multiformats/bases/base58";
|
4
|
+
import { sha256 as hasher } from "multiformats/hashes/sha2";
|
5
|
+
import * as dagCodec from "@ipld/dag-cbor";
|
6
|
+
import { MockSuperThis, mockSuperThis } from "../helpers";
|
7
|
+
|
8
|
+
describe("KeyBag", () => {
|
9
|
+
let url: URI;
|
10
|
+
let sthis: MockSuperThis;
|
11
|
+
|
12
|
+
beforeEach(async () => {
|
13
|
+
sthis = mockSuperThis();
|
14
|
+
await sthis.start();
|
15
|
+
if (runtimeFn().isBrowser) {
|
16
|
+
url = URI.from("indexdb://fp-keybag");
|
17
|
+
} else {
|
18
|
+
url = URI.merge(`file://./dist/tests/key.bag`, sthis.env.get("FP_KEYBAG_URL"));
|
19
|
+
}
|
20
|
+
});
|
21
|
+
it("default-path", async () => {
|
22
|
+
const old = sthis.env.get("FP_KEYBAG_URL");
|
23
|
+
sthis.env.delete("FP_KEYBAG_URL");
|
24
|
+
const kb = await rt.kb.getKeyBag(sthis);
|
25
|
+
if (runtimeFn().isBrowser) {
|
26
|
+
expect(kb.rt.url.toString()).toBe(`indexdb://fp-keybag`);
|
27
|
+
} else {
|
28
|
+
expect(kb.rt.url.toString()).toBe(`file://${sthis.env.get("HOME")}/.fireproof/keybag`);
|
29
|
+
}
|
30
|
+
sthis.env.set("FP_KEYBAG_URL", old);
|
31
|
+
});
|
32
|
+
it("from env", async () => {
|
33
|
+
const old = sthis.env.get("FP_KEYBAG_URL");
|
34
|
+
sthis.env.set("FP_KEYBAG_URL", url.toString());
|
35
|
+
const kb = await rt.kb.getKeyBag(sthis);
|
36
|
+
expect(kb.rt.url.toString()).toBe(url.toString());
|
37
|
+
sthis.env.set("FP_KEYBAG_URL", old);
|
38
|
+
});
|
39
|
+
|
40
|
+
it("extract keyMaterial", async () => {
|
41
|
+
const dkb = await rt.kb.getKeyBag(sthis);
|
42
|
+
const old = sthis.env.get("FP_KEYBAG_URL");
|
43
|
+
sthis.env.set("FP_KEYBAG_URL", BuildURI.from(dkb.rt.url).setParam("extractKey", "_deprecated_internal_api").toString());
|
44
|
+
const kb = await rt.kb.getKeyBag(sthis);
|
45
|
+
const key = kb.rt.crypto.randomBytes(kb.rt.keyLength);
|
46
|
+
const keyStr = base58btc.encode(key);
|
47
|
+
const res = await kb.setNamedKey("extract.test", keyStr);
|
48
|
+
expect(res.isOk()).toBeTruthy();
|
49
|
+
const gkb = await kb.getNamedExtractableKey("extract.test", true);
|
50
|
+
expect(gkb.isOk()).toBeTruthy();
|
51
|
+
expect(await gkb.Ok().extract()).toEqual({
|
52
|
+
key,
|
53
|
+
keyStr,
|
54
|
+
});
|
55
|
+
sthis.env.set("FP_KEYBAG_URL", old);
|
56
|
+
await sthis.logger.Flush();
|
57
|
+
expect(sthis.logCollector.Logs()).toEqual([
|
58
|
+
{
|
59
|
+
level: "warn",
|
60
|
+
module: "KeyBag",
|
61
|
+
msg: "extractKey is enabled via _deprecated_internal_api --- handle keys safely!!!",
|
62
|
+
},
|
63
|
+
]);
|
64
|
+
});
|
65
|
+
|
66
|
+
it("simple add", async () => {
|
67
|
+
const kb = await rt.kb.getKeyBag(sthis, {
|
68
|
+
url: url.toString(),
|
69
|
+
crypto: toCryptoRuntime({
|
70
|
+
randomBytes: (size) => new Uint8Array(size).map((_, i) => i),
|
71
|
+
}),
|
72
|
+
});
|
73
|
+
const name = "setkey" + Math.random();
|
74
|
+
expect((await kb.getNamedKey(name, true)).isErr()).toBeTruthy();
|
75
|
+
|
76
|
+
const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
|
77
|
+
const res = await kb.setNamedKey(name, key);
|
78
|
+
expect(res.isOk()).toBeTruthy();
|
79
|
+
expect((await kb.getNamedKey(name, true)).Ok()).toEqual(res.Ok());
|
80
|
+
|
81
|
+
const name2 = "implicit";
|
82
|
+
const created = await kb.getNamedKey(name2);
|
83
|
+
expect(created.isOk()).toBeTruthy();
|
84
|
+
|
85
|
+
expect((await kb.getNamedKey(name2)).Ok()).toEqual(created.Ok());
|
86
|
+
|
87
|
+
let diskBag: rt.kb.KeyItem;
|
88
|
+
let diskBag2: rt.kb.KeyItem;
|
89
|
+
const provider = await kb.rt.getBag();
|
90
|
+
if (runtimeFn().isBrowser) {
|
91
|
+
const p = provider as rt.kb.KeyBagProviderIndexDB;
|
92
|
+
diskBag = await p._prepare().then((db) => db.get("bag", name));
|
93
|
+
diskBag2 = await p._prepare().then((db) => db.get("bag", name2));
|
94
|
+
} else {
|
95
|
+
const p = provider as rt.kb.KeyBagProviderFile;
|
96
|
+
const { sysFS } = await p._prepare(name);
|
97
|
+
|
98
|
+
diskBag = await sysFS.readfile((await p._prepare(name)).fName).then((data) => {
|
99
|
+
return JSON.parse(new TextDecoder().decode(data)) as rt.kb.KeyItem;
|
100
|
+
});
|
101
|
+
diskBag2 = await sysFS.readfile((await p._prepare(name2)).fName).then((data) => {
|
102
|
+
return JSON.parse(new TextDecoder().decode(data)) as rt.kb.KeyItem;
|
103
|
+
});
|
104
|
+
}
|
105
|
+
expect(await kb.toKeyWithFingerPrint(diskBag.key)).toEqual(res);
|
106
|
+
expect(await kb.toKeyWithFingerPrint(diskBag2.key)).toEqual(created);
|
107
|
+
const algo = {
|
108
|
+
name: "AES-GCM",
|
109
|
+
iv: kb.rt.crypto.randomBytes(12),
|
110
|
+
tagLength: 128,
|
111
|
+
};
|
112
|
+
const data = kb.rt.crypto.randomBytes(122);
|
113
|
+
expect(await kb.rt.crypto.encrypt(algo, res.Ok().key, data)).toEqual(await kb.rt.crypto.encrypt(algo, created.Ok().key, data));
|
114
|
+
expect(await kb.rt.crypto.encrypt(algo, await kb.subtleKey(diskBag.key), data)).toEqual(
|
115
|
+
await kb.rt.crypto.encrypt(algo, created.Ok().key, data),
|
116
|
+
);
|
117
|
+
expect(await kb.rt.crypto.encrypt(algo, await kb.subtleKey(diskBag2.key), data)).toEqual(
|
118
|
+
await kb.rt.crypto.encrypt(algo, created.Ok().key, data),
|
119
|
+
);
|
120
|
+
});
|
121
|
+
});
|
122
|
+
|
123
|
+
describe("KeyedCryptoStore", () => {
|
124
|
+
let kb: rt.kb.KeyBag;
|
125
|
+
let logger: Logger;
|
126
|
+
let baseUrl: URI;
|
127
|
+
const sthis = mockSuperThis();
|
128
|
+
beforeEach(async () => {
|
129
|
+
await sthis.start();
|
130
|
+
logger = MockLogger().logger;
|
131
|
+
let kbUrl: URI;
|
132
|
+
if (runtimeFn().isBrowser) {
|
133
|
+
kbUrl = URI.from("indexdb://fp-keybag");
|
134
|
+
baseUrl = URI.from("indexdb://fp-keyed-crypto-store");
|
135
|
+
} else {
|
136
|
+
kbUrl = URI.merge(`file://./dist/tests/key.bag`, sthis.env.get("FP_KEYBAG_URL"));
|
137
|
+
// baseUrl = URI.merge("file://./dist/tests/keyed-crypto-store", sthis.env.get("FP_STORAGE_URL"));
|
138
|
+
baseUrl = URI.from(sthis.env.get("FP_STORAGE_URL"));
|
139
|
+
}
|
140
|
+
kb = await rt.kb.getKeyBag(sthis, {
|
141
|
+
url: kbUrl,
|
142
|
+
});
|
143
|
+
});
|
144
|
+
it("no crypto", async () => {
|
145
|
+
const loader = {
|
146
|
+
sthis,
|
147
|
+
name: "test",
|
148
|
+
ebOpts: {
|
149
|
+
keyBag: {
|
150
|
+
keyRuntime: kb.rt,
|
151
|
+
},
|
152
|
+
store: {
|
153
|
+
stores: {
|
154
|
+
base: baseUrl.build().setParam("storekey", "insecure"),
|
155
|
+
},
|
156
|
+
},
|
157
|
+
},
|
158
|
+
} as unknown as bs.Loadable;
|
159
|
+
const strt = bs.toStoreRuntime({}, sthis);
|
160
|
+
|
161
|
+
for (const pstore of [strt.makeDataStore(loader), strt.makeMetaStore(loader), strt.makeWALStore(loader)]) {
|
162
|
+
const store = await pstore;
|
163
|
+
// await store.start();
|
164
|
+
const kc = await store.keyedCrypto();
|
165
|
+
expect(kc.constructor.name).toBe("noCrypto");
|
166
|
+
// expect(kc.isEncrypting).toBe(false);
|
167
|
+
}
|
168
|
+
});
|
169
|
+
|
170
|
+
it("create key", async () => {
|
171
|
+
const loader = {
|
172
|
+
sthis,
|
173
|
+
name: "test",
|
174
|
+
ebOpts: {
|
175
|
+
keyBag: {
|
176
|
+
keyRuntime: kb.rt,
|
177
|
+
},
|
178
|
+
store: {
|
179
|
+
stores: {
|
180
|
+
base: baseUrl,
|
181
|
+
},
|
182
|
+
},
|
183
|
+
},
|
184
|
+
} as unknown as bs.Loadable;
|
185
|
+
const strt = bs.toStoreRuntime({}, sthis);
|
186
|
+
for (const pstore of [strt.makeDataStore(loader), strt.makeMetaStore(loader), strt.makeWALStore(loader)]) {
|
187
|
+
const store = await bs.ensureStart(await pstore, logger);
|
188
|
+
const kc = await store.keyedCrypto();
|
189
|
+
expect(kc.constructor.name).toBe("keyedCrypto");
|
190
|
+
// expect(kc.isEncrypting).toBe(true);
|
191
|
+
expect(store.url().getParam("storekey")).toBe(`@test:${store.url().getParam("store")}@`);
|
192
|
+
}
|
193
|
+
});
|
194
|
+
|
195
|
+
it("key ref keybag", async () => {
|
196
|
+
const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
|
197
|
+
const genKey = await kb.setNamedKey("@heute@", key);
|
198
|
+
const loader = {
|
199
|
+
sthis,
|
200
|
+
name: "test",
|
201
|
+
ebOpts: {
|
202
|
+
keyBag: {
|
203
|
+
keyRuntime: kb.rt,
|
204
|
+
},
|
205
|
+
store: {
|
206
|
+
stores: {
|
207
|
+
base: baseUrl.build().setParam("storekey", "@heute@").URI(),
|
208
|
+
},
|
209
|
+
},
|
210
|
+
},
|
211
|
+
} as unknown as bs.Loadable;
|
212
|
+
const strt = bs.toStoreRuntime({}, sthis);
|
213
|
+
for (const pstore of [strt.makeDataStore(loader), strt.makeMetaStore(loader), strt.makeWALStore(loader)]) {
|
214
|
+
const store = await pstore;
|
215
|
+
// await store.start();
|
216
|
+
expect(store.url().getParam("storekey")).toBe(`@heute@`);
|
217
|
+
const kc = await store.keyedCrypto();
|
218
|
+
expect(kc.constructor.name).toBe("keyedCrypto");
|
219
|
+
const testData = kb.rt.crypto.randomBytes(1024);
|
220
|
+
const iv = kb.rt.crypto.randomBytes(12);
|
221
|
+
const blk = await kc._encrypt({ bytes: testData, iv });
|
222
|
+
expect(blk).not.toEqual(testData);
|
223
|
+
const fpkey = genKey.Ok();
|
224
|
+
expect(fpkey.fingerPrint).toEqual(await kc.fingerPrint());
|
225
|
+
const dec = new Uint8Array(await kc.crypto.decrypt(kc.algo(iv), fpkey.key, blk));
|
226
|
+
expect(dec).toEqual(testData);
|
227
|
+
}
|
228
|
+
});
|
229
|
+
|
230
|
+
it("key", async () => {
|
231
|
+
const key = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
|
232
|
+
const loader = {
|
233
|
+
sthis,
|
234
|
+
name: "test",
|
235
|
+
ebOpts: {
|
236
|
+
keyBag: {
|
237
|
+
keyRuntime: kb.rt,
|
238
|
+
},
|
239
|
+
store: {
|
240
|
+
stores: {
|
241
|
+
base: BuildURI.from(baseUrl).setParam("storekey", key),
|
242
|
+
},
|
243
|
+
},
|
244
|
+
},
|
245
|
+
} as unknown as bs.Loadable;
|
246
|
+
const strt = bs.toStoreRuntime({}, sthis);
|
247
|
+
for (const pstore of [strt.makeDataStore(loader), strt.makeMetaStore(loader), strt.makeWALStore(loader)]) {
|
248
|
+
const store = await pstore;
|
249
|
+
// await store.start();
|
250
|
+
expect(store.url().getParam("storekey")).toBe(key);
|
251
|
+
const kc = await store.keyedCrypto();
|
252
|
+
expect(kc.constructor.name).toBe("keyedCrypto");
|
253
|
+
const testData = kb.rt.crypto.randomBytes(1024);
|
254
|
+
const iv = kb.rt.crypto.randomBytes(12);
|
255
|
+
const blk = await kc._encrypt({ bytes: testData, iv });
|
256
|
+
expect(blk).not.toEqual(testData);
|
257
|
+
const dec = await kc._decrypt({ bytes: blk, iv });
|
258
|
+
expect(dec).toEqual(testData);
|
259
|
+
}
|
260
|
+
});
|
261
|
+
});
|
262
|
+
|
263
|
+
describe("KeyedCrypto", () => {
|
264
|
+
let kb: rt.kb.KeyBag;
|
265
|
+
let kycr: bs.KeyedCrypto;
|
266
|
+
let keyStr: string;
|
267
|
+
const sthis = mockSuperThis();
|
268
|
+
beforeEach(async () => {
|
269
|
+
let url: URI;
|
270
|
+
if (runtimeFn().isBrowser) {
|
271
|
+
url = URI.from("indexdb://fp-keybag");
|
272
|
+
} else {
|
273
|
+
url = URI.merge(`file://./dist/tests/key.bag`, sthis.env.get("FP_KEYBAG_URL"));
|
274
|
+
}
|
275
|
+
kb = await rt.kb.getKeyBag(sthis, {
|
276
|
+
url,
|
277
|
+
});
|
278
|
+
keyStr = base58btc.encode(kb.rt.crypto.randomBytes(kb.rt.keyLength));
|
279
|
+
kycr = await rt.kc.keyedCryptoFactory(URI.from(`test://bla?storekey=${keyStr}`), kb, sthis);
|
280
|
+
});
|
281
|
+
it("codec explict iv", async () => {
|
282
|
+
const testData = kb.rt.crypto.randomBytes(1024);
|
283
|
+
const iv = kb.rt.crypto.randomBytes(12);
|
284
|
+
const codec = kycr.codec(iv, { noIVVerify: true });
|
285
|
+
const blk = (await codec.encode(testData)) as Uint8Array;
|
286
|
+
const myDec = await rt.mf.block.decode<bs.IvKeyIdData, number, number>({ bytes: blk, hasher, codec: dagCodec });
|
287
|
+
expect(myDec.value.iv).toEqual(iv);
|
288
|
+
expect(base58btc.encode(myDec.value.keyId)).toEqual(await kycr.fingerPrint());
|
289
|
+
const dec = await codec.decode(blk);
|
290
|
+
expect(dec).toEqual(testData);
|
291
|
+
});
|
292
|
+
|
293
|
+
it("codec implict iv", async () => {
|
294
|
+
const testData = kb.rt.crypto.randomBytes(1024);
|
295
|
+
const codec = kycr.codec();
|
296
|
+
const blk = await codec.encode(testData);
|
297
|
+
expect(blk.length).toBeGreaterThanOrEqual(12 + testData.length);
|
298
|
+
const dec = await codec.decode(blk);
|
299
|
+
expect(dec).toEqual(testData);
|
300
|
+
});
|
301
|
+
|
302
|
+
it("codec implict iv same for multiple clients", async () => {
|
303
|
+
const testData = kb.rt.crypto.randomBytes(1024);
|
304
|
+
const codec = kycr.codec();
|
305
|
+
const blk = await codec.encode(testData);
|
306
|
+
const blk2 = await codec.encode(testData);
|
307
|
+
expect(blk).toEqual(blk2);
|
308
|
+
});
|
309
|
+
});
|
310
|
+
|
311
|
+
// describe("KeyedCryptoStore RunLength", () => {
|
312
|
+
// const logger = MockLogger().logger;
|
313
|
+
// it("de/encode", () => {
|
314
|
+
// for (const data of [
|
315
|
+
// new Uint8Array(),
|
316
|
+
// new Uint8Array(10).fill(10),
|
317
|
+
// new Uint8Array(127).fill(127),
|
318
|
+
// new Uint8Array(128).fill(128),
|
319
|
+
// new Uint8Array(1024).fill(17),
|
320
|
+
// ]) {
|
321
|
+
// const res = rt.kc.encodeRunLength(data, logger);
|
322
|
+
// expect(res.length).toBeLessThanOrEqual(data.length + (data.length > 127 ? 4 : 1));
|
323
|
+
// for (let ofs = 0; ofs < 1024; ofs += 61) {
|
324
|
+
// const ofsRes = new Uint8Array([...new Uint8Array(ofs).fill(23), ...res]);
|
325
|
+
// const dec = rt.kc.decodeRunLength(ofsRes, ofs, logger);
|
326
|
+
// expect(dec.data).toEqual(data);
|
327
|
+
// expect(dec.data.length).toBe(data.length);
|
328
|
+
// expect(dec.next).toBe(ofs + data.length + (data.length > 127 ? 4 : 1));
|
329
|
+
// }
|
330
|
+
// }
|
331
|
+
// });
|
332
|
+
// });
|
@@ -1,18 +1,20 @@
|
|
1
1
|
import * as codec from "@ipld/dag-cbor";
|
2
2
|
import { sha256 as hasher } from "multiformats/hashes/sha2";
|
3
3
|
import { BlockView } from "multiformats";
|
4
|
-
import { encode } from "multiformats/block";
|
5
4
|
import { CID } from "multiformats/cid";
|
6
5
|
import { MemoryBlockstore } from "@web3-storage/pail/block";
|
7
|
-
import { CRDTMeta, IndexTransactionMeta, bs, rt } from "@fireproof/core";
|
6
|
+
import { CRDTMeta, IndexTransactionMeta, SuperThis, bs, rt } from "@fireproof/core";
|
7
|
+
import { mockSuperThis } from "../helpers";
|
8
8
|
|
9
9
|
class MyMemoryBlockStore extends bs.EncryptedBlockstore {
|
10
10
|
readonly memblock = new MemoryBlockstore();
|
11
|
-
|
11
|
+
loader: bs.Loader;
|
12
|
+
constructor(sthis: SuperThis) {
|
12
13
|
const ebOpts = {
|
13
14
|
name: "MyMemoryBlockStore",
|
14
15
|
};
|
15
|
-
super(ebOpts);
|
16
|
+
super(sthis, ebOpts);
|
17
|
+
this.loader = new bs.Loader("MyMemoryBlockStore", {}, sthis);
|
16
18
|
}
|
17
19
|
ready(): Promise<void> {
|
18
20
|
return Promise.resolve();
|
@@ -20,7 +22,6 @@ class MyMemoryBlockStore extends bs.EncryptedBlockstore {
|
|
20
22
|
close(): Promise<void> {
|
21
23
|
return this.loader.close();
|
22
24
|
}
|
23
|
-
loader = new bs.Loader("MyMemoryBlockStore", {});
|
24
25
|
readonly transactions = new Set<bs.CarTransaction>();
|
25
26
|
// readonly lastTxMeta?: TransactionMeta;
|
26
27
|
readonly compacting: boolean = false;
|
@@ -50,6 +51,7 @@ describe("basic Loader simple", function () {
|
|
50
51
|
let loader: bs.Loader;
|
51
52
|
let block: BlockView;
|
52
53
|
let t: bs.CarTransaction;
|
54
|
+
const sthis = mockSuperThis();
|
53
55
|
|
54
56
|
afterEach(async function () {
|
55
57
|
await loader.close();
|
@@ -58,12 +60,12 @@ describe("basic Loader simple", function () {
|
|
58
60
|
|
59
61
|
beforeEach(async function () {
|
60
62
|
const testDbName = "test-loader-commit";
|
61
|
-
await
|
62
|
-
const mockM = new MyMemoryBlockStore();
|
63
|
+
await sthis.start();
|
64
|
+
const mockM = new MyMemoryBlockStore(sthis);
|
63
65
|
t = new bs.CarTransaction(mockM as bs.EncryptedBlockstore);
|
64
|
-
loader = new bs.Loader(testDbName, { public: true });
|
66
|
+
loader = new bs.Loader(testDbName, { public: true }, sthis);
|
65
67
|
await loader.ready();
|
66
|
-
block = await encode({
|
68
|
+
block = await rt.mf.block.encode({
|
67
69
|
value: { hello: "world" },
|
68
70
|
hasher,
|
69
71
|
codec,
|
@@ -97,17 +99,19 @@ describe("basic Loader with two commits", function () {
|
|
97
99
|
let carCid: bs.CarGroup;
|
98
100
|
let carCid0: bs.CarGroup;
|
99
101
|
|
102
|
+
const sthis = mockSuperThis();
|
103
|
+
|
100
104
|
afterEach(async function () {
|
101
105
|
await loader.close();
|
102
106
|
await loader.destroy();
|
103
107
|
});
|
104
108
|
|
105
109
|
beforeEach(async function () {
|
106
|
-
await
|
107
|
-
const mockM = new MyMemoryBlockStore();
|
110
|
+
await sthis.start();
|
111
|
+
const mockM = new MyMemoryBlockStore(sthis);
|
108
112
|
t = new bs.CarTransaction(mockM);
|
109
|
-
loader = new bs.Loader("test-loader-two-commit", { public: true });
|
110
|
-
block = await encode({
|
113
|
+
loader = new bs.Loader("test-loader-two-commit", { public: true }, sthis);
|
114
|
+
block = await rt.mf.block.encode({
|
111
115
|
value: { hello: "world" },
|
112
116
|
hasher,
|
113
117
|
codec,
|
@@ -115,7 +119,7 @@ describe("basic Loader with two commits", function () {
|
|
115
119
|
await t.put(block.cid, block.bytes);
|
116
120
|
carCid0 = await loader.commit(t, { head: [block.cid] });
|
117
121
|
|
118
|
-
block2 = await encode({
|
122
|
+
block2 = await rt.mf.block.encode({
|
119
123
|
value: { hello: "universe" },
|
120
124
|
hasher,
|
121
125
|
codec,
|
@@ -123,14 +127,14 @@ describe("basic Loader with two commits", function () {
|
|
123
127
|
await t.put(block2.cid, block2.bytes);
|
124
128
|
carCid = await loader.commit(t, { head: [block2.cid] });
|
125
129
|
|
126
|
-
block3 = await encode({
|
130
|
+
block3 = await rt.mf.block.encode({
|
127
131
|
value: { hello: "multiverse" },
|
128
132
|
hasher,
|
129
133
|
codec,
|
130
134
|
});
|
131
135
|
await t.put(block3.cid, block3.bytes);
|
132
136
|
|
133
|
-
block4 = await encode({
|
137
|
+
block4 = await rt.mf.block.encode({
|
134
138
|
value: { hello: "megaverse" },
|
135
139
|
hasher,
|
136
140
|
codec,
|
@@ -197,6 +201,7 @@ describe("basic Loader with index commits", function () {
|
|
197
201
|
let indexerResult: IndexTransactionMeta;
|
198
202
|
let cid: CID;
|
199
203
|
// let indexMap: Map<string, CID>;
|
204
|
+
const sthis = mockSuperThis();
|
200
205
|
|
201
206
|
afterEach(async function () {
|
202
207
|
await ib.close();
|
@@ -205,10 +210,10 @@ describe("basic Loader with index commits", function () {
|
|
205
210
|
|
206
211
|
beforeEach(async function () {
|
207
212
|
const name = "test-loader-index" + Math.random();
|
208
|
-
await
|
213
|
+
await sthis.start();
|
209
214
|
// t = new CarTransaction()
|
210
|
-
ib = new bs.EncryptedBlockstore({ name });
|
211
|
-
block = await encode({
|
215
|
+
ib = new bs.EncryptedBlockstore(sthis, { name });
|
216
|
+
block = await rt.mf.block.encode({
|
212
217
|
value: { hello: "world" },
|
213
218
|
hasher,
|
214
219
|
codec,
|