@fireproof/core 0.19.8-dev-global → 0.19.8-dev-series-1
Sign up to get free protection for your applications and to get access to all the features.
- 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 +20 -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 +2317 -1838
- package/index.cjs.map +1 -1
- package/index.d.cts +663 -535
- package/index.d.ts +663 -535
- package/index.global.js +26290 -20732
- package/index.global.js.map +1 -1
- package/index.js +1618 -1032
- 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 +12 -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-1",
|
4
4
|
"description": "Live database for the web.",
|
5
5
|
"type": "module",
|
6
6
|
"module": "./index.js",
|
@@ -46,17 +46,21 @@
|
|
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
|
-
"@ipld/unixfs": "^3.0.0",
|
59
|
-
"@ipld/car": "^5.3.2"
|
63
|
+
"react": "^18.3.1"
|
60
64
|
},
|
61
65
|
"scripts": {}
|
62
66
|
}
|
@@ -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,
|