nervur 0.22.0 → 0.22.2-3
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/AUTHORING.md +741 -0
- package/KIT-SPEC.md +286 -0
- package/LICENSE +1 -1
- package/NOTICE +6 -2
- package/README.md +97 -424
- package/dist/app/app-ground.d.ts +18 -0
- package/dist/app/app-ground.js +25 -0
- package/dist/app/index.d.ts +2 -0
- package/dist/app/index.js +5 -0
- package/dist/app/native.d.ts +46 -0
- package/dist/app/native.js +101 -0
- package/dist/being/being.d.ts +229 -0
- package/dist/being/being.js +20 -0
- package/dist/being/covers.d.ts +9 -0
- package/dist/being/covers.js +21 -0
- package/dist/being/index.d.ts +3 -0
- package/dist/being/index.js +5 -0
- package/dist/being/need.d.ts +49 -0
- package/dist/being/need.js +33 -0
- package/dist/being/schema.d.ts +100 -0
- package/dist/being/schema.js +132 -0
- package/dist/being/table.d.ts +42 -0
- package/dist/being/table.js +288 -0
- package/dist/bench/bench-ground.d.ts +55 -0
- package/dist/bench/bench-ground.js +101 -0
- package/dist/bench/bench.d.ts +87 -0
- package/dist/bench/bench.js +260 -0
- package/dist/bench/fake-carry.d.ts +32 -0
- package/dist/bench/fake-carry.js +56 -0
- package/dist/bench/fake-clock.d.ts +17 -0
- package/dist/bench/fake-clock.js +34 -0
- package/dist/bench/fake-custody.d.ts +9 -0
- package/dist/bench/fake-custody.js +10 -0
- package/dist/bench/fake-faculty.d.ts +25 -0
- package/dist/bench/fake-faculty.js +48 -0
- package/dist/bench/fake-keys.d.ts +5 -0
- package/dist/bench/fake-keys.js +9 -0
- package/dist/bench/fake-memory.d.ts +14 -0
- package/dist/bench/fake-memory.js +46 -0
- package/dist/bench/fake-network.d.ts +57 -0
- package/dist/bench/fake-network.js +169 -0
- package/dist/bench/index.d.ts +11 -0
- package/dist/bench/index.js +13 -0
- package/dist/bench/seeded.d.ts +11 -0
- package/dist/bench/seeded.js +37 -0
- package/dist/bench/settle.d.ts +2 -0
- package/dist/bench/settle.js +49 -0
- package/dist/bench/stewards.d.ts +17 -0
- package/dist/bench/stewards.js +20 -0
- package/dist/bodies/class-list.d.ts +14 -0
- package/dist/bodies/class-list.js +33 -0
- package/dist/bodies/joined-carry.d.ts +23 -0
- package/dist/bodies/joined-carry.js +42 -0
- package/dist/bodies/noble-crypto.d.ts +22 -0
- package/dist/bodies/noble-crypto.js +88 -0
- package/dist/bodies/seed-keys.d.ts +10 -0
- package/dist/bodies/seed-keys.js +42 -0
- package/dist/bodies/strict-tools.d.ts +10 -0
- package/dist/bodies/strict-tools.js +306 -0
- package/dist/bodies/web-carry.d.ts +65 -0
- package/dist/bodies/web-carry.js +224 -0
- package/dist/bodies/web-clock.d.ts +12 -0
- package/dist/bodies/web-clock.js +33 -0
- package/dist/browser/browser-ground.d.ts +69 -0
- package/dist/browser/browser-ground.js +219 -0
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.js +7 -0
- package/dist/browser/indexeddb-memory.d.ts +17 -0
- package/dist/browser/indexeddb-memory.js +97 -0
- package/dist/browser/locked-custody.d.ts +25 -0
- package/dist/browser/locked-custody.js +89 -0
- package/dist/browser/origin-classes.d.ts +7 -0
- package/dist/browser/origin-classes.js +31 -0
- package/dist/foundation.d.ts +150 -0
- package/dist/foundation.js +4 -0
- package/dist/ground/ground.d.ts +177 -0
- package/dist/ground/ground.js +363 -0
- package/dist/house/crossing.d.ts +37 -0
- package/dist/house/crossing.js +131 -0
- package/dist/house/house.d.ts +80 -0
- package/dist/house/house.js +1753 -0
- package/dist/house/rows-shape.d.ts +103 -0
- package/dist/house/rows-shape.js +12 -0
- package/dist/house/rows.d.ts +27 -0
- package/dist/house/rows.js +168 -0
- package/dist/index.d.ts +29 -1
- package/dist/index.js +25 -14
- package/dist/node/bridge.d.ts +17 -0
- package/dist/node/bridge.js +188 -0
- package/dist/node/cli.js +170 -0
- package/dist/node/custody.d.ts +20 -0
- package/dist/node/custody.js +34 -0
- package/dist/node/file-keys.d.ts +7 -0
- package/dist/node/file-keys.js +30 -0
- package/dist/node/file-memory.d.ts +13 -0
- package/dist/node/file-memory.js +91 -0
- package/dist/node/folder-classes.d.ts +5 -0
- package/dist/node/folder-classes.js +40 -0
- package/dist/node/gone.d.ts +2 -0
- package/dist/node/gone.js +7 -0
- package/dist/node/hand.d.ts +29 -0
- package/dist/node/hand.js +85 -0
- package/dist/node/held-keys.d.ts +14 -0
- package/dist/node/held-keys.js +36 -0
- package/dist/node/http.d.ts +11 -0
- package/dist/node/http.js +90 -0
- package/dist/node/index.d.ts +13 -0
- package/dist/node/index.js +15 -0
- package/dist/node/keychain-keys.d.ts +10 -0
- package/dist/node/keychain-keys.js +51 -0
- package/dist/node/ledger-memory.d.ts +17 -0
- package/dist/node/ledger-memory.js +151 -0
- package/dist/node/lock.d.ts +10 -0
- package/dist/node/lock.js +78 -0
- package/dist/node/node-ground.d.ts +33 -0
- package/dist/node/node-ground.js +147 -0
- package/dist/node/notify.d.ts +1 -0
- package/dist/node/notify.js +18 -0
- package/dist/node/tcp-carry.d.ts +39 -0
- package/dist/node/tcp-carry.js +216 -0
- package/dist/node/websocket.d.ts +6 -0
- package/dist/node/websocket.js +118 -0
- package/dist/quo/frame.d.ts +20 -0
- package/dist/quo/frame.js +48 -0
- package/dist/quo/room.d.ts +154 -0
- package/dist/quo/room.js +362 -0
- package/dist/serve/index.d.ts +27 -0
- package/dist/serve/index.js +55 -0
- package/package.json +49 -47
- package/dist/browser.d.ts +0 -1
- package/dist/browser.js +0 -8
- package/dist/cli.js +0 -16
- package/dist/core/being/being.d.ts +0 -17
- package/dist/core/being/being.js +0 -72
- package/dist/core/being/digest.d.ts +0 -3
- package/dist/core/being/digest.js +0 -17
- package/dist/core/being/faculty.d.ts +0 -10
- package/dist/core/being/faculty.js +0 -77
- package/dist/core/being/index.d.ts +0 -6
- package/dist/core/being/index.js +0 -8
- package/dist/core/being/kind.d.ts +0 -6
- package/dist/core/being/kind.js +0 -34
- package/dist/core/being/types.d.ts +0 -61
- package/dist/core/being/types.js +0 -4
- package/dist/core/being/words.d.ts +0 -13
- package/dist/core/being/words.js +0 -14
- package/dist/core/browser/index.d.ts +0 -37
- package/dist/core/browser/index.js +0 -196
- package/dist/core/browser/worker.d.ts +0 -11
- package/dist/core/browser/worker.js +0 -37
- package/dist/core/cli/command.d.ts +0 -13
- package/dist/core/cli/command.js +0 -330
- package/dist/core/cli/edge.d.ts +0 -7
- package/dist/core/cli/edge.js +0 -79
- package/dist/core/cli/harbor.d.ts +0 -25
- package/dist/core/cli/harbor.js +0 -115
- package/dist/core/contract/index.d.ts +0 -42
- package/dist/core/contract/index.js +0 -34
- package/dist/core/contract/link.d.ts +0 -4
- package/dist/core/contract/link.js +0 -45
- package/dist/core/crypto/aes.d.ts +0 -3
- package/dist/core/crypto/aes.js +0 -24
- package/dist/core/crypto/bytes.d.ts +0 -6
- package/dist/core/crypto/bytes.js +0 -33
- package/dist/core/crypto/ed25519.d.ts +0 -3
- package/dist/core/crypto/ed25519.js +0 -93
- package/dist/core/crypto/hash.d.ts +0 -2
- package/dist/core/crypto/hash.js +0 -11
- package/dist/core/crypto/index.d.ts +0 -7
- package/dist/core/crypto/index.js +0 -10
- package/dist/core/crypto/json.d.ts +0 -8
- package/dist/core/crypto/json.js +0 -250
- package/dist/core/crypto/mlkem.d.ts +0 -12
- package/dist/core/crypto/mlkem.js +0 -36
- package/dist/core/crypto/subtle.d.ts +0 -3
- package/dist/core/crypto/subtle.js +0 -11
- package/dist/core/crypto/x25519.d.ts +0 -2
- package/dist/core/crypto/x25519.js +0 -24
- package/dist/core/edge/index.d.ts +0 -164
- package/dist/core/edge/index.js +0 -739
- package/dist/core/edge/kit.d.ts +0 -2
- package/dist/core/edge/kit.js +0 -2
- package/dist/core/folder/index.d.ts +0 -18
- package/dist/core/folder/index.js +0 -130
- package/dist/core/git/http.d.ts +0 -6
- package/dist/core/git/http.js +0 -102
- package/dist/core/git/index.d.ts +0 -5
- package/dist/core/git/index.js +0 -10
- package/dist/core/git/object.d.ts +0 -40
- package/dist/core/git/object.js +0 -103
- package/dist/core/git/pack.d.ts +0 -9
- package/dist/core/git/pack.js +0 -171
- package/dist/core/git/store.d.ts +0 -23
- package/dist/core/git/store.js +0 -120
- package/dist/core/git/zlib.d.ts +0 -6
- package/dist/core/git/zlib.js +0 -210
- package/dist/core/harbor/carrying.d.ts +0 -51
- package/dist/core/harbor/carrying.js +0 -69
- package/dist/core/harbor/catalogue.d.ts +0 -33
- package/dist/core/harbor/catalogue.js +0 -365
- package/dist/core/harbor/dna.d.ts +0 -13
- package/dist/core/harbor/dna.js +0 -120
- package/dist/core/harbor/dock.d.ts +0 -62
- package/dist/core/harbor/dock.js +0 -381
- package/dist/core/harbor/harbor.d.ts +0 -16
- package/dist/core/harbor/harbor.js +0 -438
- package/dist/core/harbor/index.d.ts +0 -11
- package/dist/core/harbor/index.js +0 -14
- package/dist/core/harbor/memory.d.ts +0 -10
- package/dist/core/harbor/memory.js +0 -25
- package/dist/core/harbor/package.d.ts +0 -20
- package/dist/core/harbor/package.js +0 -172
- package/dist/core/harbor/probe.d.ts +0 -22
- package/dist/core/harbor/probe.js +0 -15
- package/dist/core/harbor/registry.d.ts +0 -15
- package/dist/core/harbor/registry.js +0 -110
- package/dist/core/harbor/root-line.d.ts +0 -7
- package/dist/core/harbor/root-line.js +0 -9
- package/dist/core/harbor/terrain.d.ts +0 -25
- package/dist/core/harbor/terrain.js +0 -28
- package/dist/core/http/index.d.ts +0 -2
- package/dist/core/http/index.js +0 -154
- package/dist/core/http/websocket.d.ts +0 -29
- package/dist/core/http/websocket.js +0 -133
- package/dist/core/line/answer.d.ts +0 -8
- package/dist/core/line/answer.js +0 -60
- package/dist/core/line/frame.d.ts +0 -29
- package/dist/core/line/frame.js +0 -77
- package/dist/core/line/ground.d.ts +0 -3
- package/dist/core/line/ground.js +0 -7
- package/dist/core/line/index.d.ts +0 -4
- package/dist/core/line/index.js +0 -8
- package/dist/core/line/web.d.ts +0 -12
- package/dist/core/line/web.js +0 -117
- package/dist/core/node/index.d.ts +0 -23
- package/dist/core/node/index.js +0 -124
- package/dist/core/pointer/bodies.d.ts +0 -31
- package/dist/core/pointer/bodies.js +0 -118
- package/dist/core/pointer/index.d.ts +0 -2
- package/dist/core/pointer/index.js +0 -4
- package/dist/core/pointer/world.d.ts +0 -45
- package/dist/core/pointer/world.js +0 -106
- package/dist/core/proof/contracts.d.ts +0 -19
- package/dist/core/proof/contracts.js +0 -116
- package/dist/core/proof/expect.d.ts +0 -6
- package/dist/core/proof/expect.js +0 -18
- package/dist/core/proof/index.d.ts +0 -3
- package/dist/core/proof/index.js +0 -14
- package/dist/core/proof/law.d.ts +0 -25
- package/dist/core/proof/law.js +0 -715
- package/dist/core/quo/address.d.ts +0 -19
- package/dist/core/quo/address.js +0 -84
- package/dist/core/quo/door.d.ts +0 -34
- package/dist/core/quo/door.js +0 -174
- package/dist/core/quo/index.d.ts +0 -9
- package/dist/core/quo/index.js +0 -12
- package/dist/core/quo/invitation.d.ts +0 -8
- package/dist/core/quo/invitation.js +0 -19
- package/dist/core/quo/keys.d.ts +0 -40
- package/dist/core/quo/keys.js +0 -79
- package/dist/core/quo/payload.d.ts +0 -15
- package/dist/core/quo/payload.js +0 -55
- package/dist/core/quo/relations.d.ts +0 -40
- package/dist/core/quo/relations.js +0 -33
- package/dist/core/quo/reply.d.ts +0 -13
- package/dist/core/quo/reply.js +0 -35
- package/dist/core/quo/seal.d.ts +0 -42
- package/dist/core/quo/seal.js +0 -78
- package/dist/core/quo/standing.d.ts +0 -39
- package/dist/core/quo/standing.js +0 -90
- package/dist/core/tcp/index.d.ts +0 -27
- package/dist/core/tcp/index.js +0 -209
- package/dist/core/ward/allowance.d.ts +0 -14
- package/dist/core/ward/allowance.js +0 -32
- package/dist/core/ward/cells.d.ts +0 -7
- package/dist/core/ward/cells.js +0 -74
- package/dist/core/ward/house.d.ts +0 -67
- package/dist/core/ward/house.js +0 -473
- package/dist/core/ward/index.d.ts +0 -5
- package/dist/core/ward/index.js +0 -7
- package/dist/core/ward/partition.d.ts +0 -50
- package/dist/core/ward/partition.js +0 -66
- package/dist/core/ward/stance.d.ts +0 -29
- package/dist/core/ward/stance.js +0 -186
- package/dist/core/ward/ward.d.ts +0 -44
- package/dist/core/ward/ward.js +0 -140
- package/dist/core.d.ts +0 -10
- package/dist/core.js +0 -19
- package/dist/defaults/dock/index.d.ts +0 -4
- package/dist/defaults/dock/index.js +0 -11
- package/dist/defaults/index.d.ts +0 -5
- package/dist/defaults/index.js +0 -10
- package/dist/defaults/memory/index.d.ts +0 -12
- package/dist/defaults/memory/index.js +0 -39
- package/dist/defaults/tcp/index.d.ts +0 -16
- package/dist/defaults/tcp/index.js +0 -82
- package/dist/defaults/ward/index.d.ts +0 -4
- package/dist/defaults/ward/index.js +0 -11
- package/dist/defaults/web/index.d.ts +0 -15
- package/dist/defaults/web/index.js +0 -90
- package/dist/edge.d.ts +0 -1
- package/dist/edge.js +0 -9
- package/dist/kit.d.ts +0 -4
- package/dist/kit.js +0 -12
- package/dist/node.d.ts +0 -1
- package/dist/node.js +0 -8
- package/src/browser.ts +0 -10
- package/src/cli.ts +0 -15
- package/src/core/being/being.ts +0 -84
- package/src/core/being/digest.ts +0 -18
- package/src/core/being/faculty.ts +0 -76
- package/src/core/being/index.ts +0 -8
- package/src/core/being/kind.ts +0 -37
- package/src/core/being/types.ts +0 -74
- package/src/core/being/words.ts +0 -31
- package/src/core/browser/index.ts +0 -219
- package/src/core/browser/worker.ts +0 -63
- package/src/core/cli/command.ts +0 -311
- package/src/core/cli/edge.ts +0 -86
- package/src/core/cli/harbor.ts +0 -120
- package/src/core/contract/index.ts +0 -82
- package/src/core/contract/link.ts +0 -58
- package/src/core/crypto/aes.ts +0 -26
- package/src/core/crypto/bytes.ts +0 -37
- package/src/core/crypto/ed25519.ts +0 -92
- package/src/core/crypto/hash.ts +0 -14
- package/src/core/crypto/index.ts +0 -10
- package/src/core/crypto/json.ts +0 -241
- package/src/core/crypto/mlkem.ts +0 -38
- package/src/core/crypto/subtle.ts +0 -13
- package/src/core/crypto/x25519.ts +0 -23
- package/src/core/edge/index.ts +0 -865
- package/src/core/folder/index.ts +0 -137
- package/src/core/git/http.ts +0 -103
- package/src/core/git/index.ts +0 -10
- package/src/core/git/object.ts +0 -116
- package/src/core/git/pack.ts +0 -147
- package/src/core/git/store.ts +0 -122
- package/src/core/git/zlib.ts +0 -197
- package/src/core/harbor/carrying.ts +0 -124
- package/src/core/harbor/catalogue.ts +0 -386
- package/src/core/harbor/dna.ts +0 -116
- package/src/core/harbor/dock.ts +0 -420
- package/src/core/harbor/harbor.ts +0 -433
- package/src/core/harbor/index.ts +0 -14
- package/src/core/harbor/memory.ts +0 -31
- package/src/core/harbor/package.ts +0 -195
- package/src/core/harbor/probe.ts +0 -39
- package/src/core/harbor/registry.ts +0 -107
- package/src/core/harbor/root-line.ts +0 -19
- package/src/core/harbor/terrain.ts +0 -54
- package/src/core/http/index.ts +0 -147
- package/src/core/http/websocket.ts +0 -124
- package/src/core/line/answer.ts +0 -60
- package/src/core/line/frame.ts +0 -83
- package/src/core/line/ground.ts +0 -18
- package/src/core/line/index.ts +0 -8
- package/src/core/line/web.ts +0 -123
- package/src/core/node/index.ts +0 -139
- package/src/core/pointer/bodies.ts +0 -122
- package/src/core/pointer/index.ts +0 -4
- package/src/core/pointer/world.ts +0 -134
- package/src/core/proof/contracts.ts +0 -134
- package/src/core/proof/expect.ts +0 -25
- package/src/core/proof/index.ts +0 -14
- package/src/core/proof/law.ts +0 -742
- package/src/core/quo/address.ts +0 -87
- package/src/core/quo/door.ts +0 -180
- package/src/core/quo/index.ts +0 -12
- package/src/core/quo/invitation.ts +0 -19
- package/src/core/quo/keys.ts +0 -91
- package/src/core/quo/payload.ts +0 -61
- package/src/core/quo/relations.ts +0 -62
- package/src/core/quo/reply.ts +0 -38
- package/src/core/quo/seal.ts +0 -101
- package/src/core/quo/standing.ts +0 -111
- package/src/core/stand/main.ts +0 -20
- package/src/core/stand/stand.ts +0 -259
- package/src/core/tcp/index.ts +0 -227
- package/src/core/ward/allowance.ts +0 -47
- package/src/core/ward/cells.ts +0 -77
- package/src/core/ward/house.ts +0 -524
- package/src/core/ward/index.ts +0 -7
- package/src/core/ward/partition.ts +0 -117
- package/src/core/ward/stance.ts +0 -207
- package/src/core/ward/ward.ts +0 -166
- package/src/core.ts +0 -55
- package/src/defaults/dock/index.ts +0 -12
- package/src/defaults/index.ts +0 -10
- package/src/defaults/memory/index.ts +0 -50
- package/src/defaults/tcp/index.ts +0 -89
- package/src/defaults/ward/index.ts +0 -12
- package/src/defaults/web/index.ts +0 -97
- package/src/edge.ts +0 -11
- package/src/index.ts +0 -18
- package/src/kit.ts +0 -15
- package/src/node.ts +0 -10
- /package/dist/{cli.d.ts → node/cli.d.ts} +0 -0
package/src/core/cli/edge.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// `nervur edge dev`: an edge harbor on this machine, as it will stand on
|
|
3
|
-
// Cloudflare. The harbor of a folder is packed under its name into the
|
|
4
|
-
// pack the worker imports, beside the harbors the pack holds already, and
|
|
5
|
-
// the worker's own `wrangler dev` runs them all, in the folder the command
|
|
6
|
-
// runs from, with the secret handed as `NERVUR_SECRET` through the
|
|
7
|
-
// environment so no listing of processes shows it. The secret is the one
|
|
8
|
-
// the command's environment names, or one drawn once and kept under
|
|
9
|
-
// `.nervur-edge`, beside the objects' storage, so a harbor landed once
|
|
10
|
-
// stands again across restarts, as it does on Cloudflare.
|
|
11
|
-
//
|
|
12
|
-
// wrangler is the worker's tool and never the kit's: the one who deploys
|
|
13
|
-
// an edge has it already, and `edge dev` finds it where npm put it.
|
|
14
|
-
import { spawn, type ChildProcess } from 'node:child_process';
|
|
15
|
-
import { existsSync } from 'node:fs';
|
|
16
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
17
|
-
import { join } from 'node:path';
|
|
18
|
-
import { hex } from '../crypto/index.ts';
|
|
19
|
-
import { CryptoEntropy } from '../pointer/index.ts';
|
|
20
|
-
import { pack } from './harbor.ts';
|
|
21
|
-
|
|
22
|
-
export const EDGE_STATE = '.nervur-edge';
|
|
23
|
-
// A refused fetch costs next to nothing, so wrangler is asked often and is
|
|
24
|
-
// found the moment it answers, within the same minute as ever.
|
|
25
|
-
const READY_TRIES = 2400;
|
|
26
|
-
const READY_EVERY = 25;
|
|
27
|
-
|
|
28
|
-
export type EdgeDev = { readonly at: string; readonly places: number; close(): Promise<void> };
|
|
29
|
-
|
|
30
|
-
const answers = (url: string): Promise<boolean> =>
|
|
31
|
-
fetch(url).then(
|
|
32
|
-
() => true,
|
|
33
|
-
() => false,
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
// Resolved once wrangler answers at `url`, rejected once it exits or never
|
|
37
|
-
// answers.
|
|
38
|
-
const ready = async (child: ChildProcess, url: string, said: () => string): Promise<void> => {
|
|
39
|
-
let gone = false;
|
|
40
|
-
child.once('exit', () => (gone = true));
|
|
41
|
-
for (let i = 0; i < READY_TRIES; i += 1) {
|
|
42
|
-
if (gone) throw new Error(`wrangler dev exited: ${said()}`);
|
|
43
|
-
if (await answers(url)) return;
|
|
44
|
-
await new Promise((r) => setTimeout(r, READY_EVERY));
|
|
45
|
-
}
|
|
46
|
-
throw new Error(`wrangler dev never answered at ${url}: ${said()}`);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// The secret `edge dev` runs under: the one named, or the one kept here.
|
|
50
|
-
const devSecret = async (state: string, named: string | undefined): Promise<string> => {
|
|
51
|
-
if (named) return named;
|
|
52
|
-
const file = join(state, 'secret');
|
|
53
|
-
if (!existsSync(file)) {
|
|
54
|
-
await mkdir(state, { recursive: true, mode: 0o700 });
|
|
55
|
-
await writeFile(file, `${hex(new CryptoEntropy().draw(32))}\n`, { mode: 0o600, flag: 'wx' });
|
|
56
|
-
}
|
|
57
|
-
return (await readFile(file, 'utf8')).trim();
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export const edgeDev = async (dir: string, file: string, name: string, cwd: string, port: number, named?: string): Promise<EdgeDev> => {
|
|
61
|
-
const state = join(cwd, EDGE_STATE);
|
|
62
|
-
const secret = await devSecret(state, named);
|
|
63
|
-
const { places } = (await pack(dir, file, name, secret)) as { places: number };
|
|
64
|
-
const child = spawn('npx', ['--no-install', 'wrangler', 'dev', '--ip', '127.0.0.1', '--port', String(port), '--persist-to', state, '--log-level', 'warn'], {
|
|
65
|
-
cwd,
|
|
66
|
-
env: { ...process.env, NERVUR_SECRET: secret, CLOUDFLARE_INCLUDE_PROCESS_ENV: 'true' },
|
|
67
|
-
stdio: ['ignore', 'ignore', 'pipe'],
|
|
68
|
-
detached: true,
|
|
69
|
-
});
|
|
70
|
-
let err = '';
|
|
71
|
-
child.stderr!.on('data', (chunk: Buffer) => (err = `${err}${chunk.toString('utf8')}`.slice(-4000)));
|
|
72
|
-
const at = `http://127.0.0.1:${String(port)}/${name}/quo`;
|
|
73
|
-
const close = (): Promise<void> =>
|
|
74
|
-
new Promise((done) => {
|
|
75
|
-
if (child.exitCode !== null) return done();
|
|
76
|
-
child.once('exit', () => done());
|
|
77
|
-
process.kill(-child.pid!, 'SIGTERM');
|
|
78
|
-
});
|
|
79
|
-
try {
|
|
80
|
-
await ready(child, at, () => err);
|
|
81
|
-
} catch (e) {
|
|
82
|
-
await close();
|
|
83
|
-
throw e;
|
|
84
|
-
}
|
|
85
|
-
return { at, places, close };
|
|
86
|
-
};
|
package/src/core/cli/harbor.ts
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// A harbor on this machine, as the `nervur` command stands it: a harbor of
|
|
3
|
-
// the Node ground in a folder, served while `serve` runs, and asked over
|
|
4
|
-
// its root line's socket.
|
|
5
|
-
//
|
|
6
|
-
// A root request goes to a served harbor over its socket. With none served,
|
|
7
|
-
// the command unpacks the harbor from its folder, asks, and closes it, so
|
|
8
|
-
// one process at a time writes the folder.
|
|
9
|
-
import { existsSync } from 'node:fs';
|
|
10
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
11
|
-
import { join } from 'node:path';
|
|
12
|
-
import type { JsonObject } from '../being/index.ts';
|
|
13
|
-
import { hex, unhex } from '../crypto/index.ts';
|
|
14
|
-
import { isHarborName, readPack, sealSeed, type Pack } from '../edge/index.ts';
|
|
15
|
-
import { FolderCustody, FolderMemory } from '../folder/index.ts';
|
|
16
|
-
import { carrierIn, carryPlaces, Harbor, landPlaces, readCarried, type Carried, type Defaults, type RootRequest } from '../harbor/index.ts';
|
|
17
|
-
import { askServed, NodeTerrain, socketOf } from '../node/index.ts';
|
|
18
|
-
import { CryptoEntropy } from '../pointer/index.ts';
|
|
19
|
-
import { tcpAddress } from '../quo/index.ts';
|
|
20
|
-
|
|
21
|
-
// A harbor of a folder, opened for one ask: it listens nowhere and serves
|
|
22
|
-
// nothing.
|
|
23
|
-
// Every harbor the command opens runs the defaults its entry hands it, and
|
|
24
|
-
// the command holds it, so it asks its `stand` once it opens.
|
|
25
|
-
const standing = async (terrain: NodeTerrain): Promise<Harbor> => {
|
|
26
|
-
const harbor = await Harbor.open(terrain);
|
|
27
|
-
await harbor.ask({ method: 'stand' });
|
|
28
|
-
return harbor;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// The box ward's census, as the root reads it.
|
|
32
|
-
export type Census = { pk: string; beings: Record<string, { class: string; absent: boolean }>; listening: string[] };
|
|
33
|
-
export const census = async (harbor: Harbor): Promise<Census> => ((await harbor.ask({})).answer as { notes: Census }).notes;
|
|
34
|
-
|
|
35
|
-
export const open = (dir: string, defaults: Defaults): Promise<Harbor> => standing(new NodeTerrain({ dir, defaults, wakes: false, serves: false }));
|
|
36
|
-
|
|
37
|
-
// Whether a harbor of this folder is served now.
|
|
38
|
-
export const isServed = async (dir: string): Promise<boolean> => (await askServed(dir, {})) !== undefined;
|
|
39
|
-
|
|
40
|
-
export const request = async (dir: string, defaults: Defaults, req: RootRequest): Promise<JsonObject> => {
|
|
41
|
-
const served = await askServed(dir, req);
|
|
42
|
-
if (served !== undefined) return served;
|
|
43
|
-
const harbor = await open(dir, defaults);
|
|
44
|
-
try {
|
|
45
|
-
return await harbor.ask(req);
|
|
46
|
-
} finally {
|
|
47
|
-
await harbor.close();
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// The harbor of a folder, read as bytes alone, its seed only where the
|
|
52
|
-
// one who asks says so, since custody holds it and a package without it
|
|
53
|
-
// opens nowhere. No harbor opens, so nothing is asked and nothing is
|
|
54
|
-
// written.
|
|
55
|
-
export const carry = async (dir: string, seed: boolean): Promise<Carried> => ({
|
|
56
|
-
...(seed ? { seed: hex(await new FolderCustody(dir, new CryptoEntropy()).seed()) } : {}),
|
|
57
|
-
places: await carryPlaces(new FolderMemory(dir)),
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// What `nervur edge pack` hands a deploy: the harbor of a folder, under
|
|
61
|
-
// its name, in the pack the worker bundles, its seed sealed under the
|
|
62
|
-
// worker's `NERVUR_SECRET` beside its sealed places. Its code travels in
|
|
63
|
-
// its places, as its DNA, so the edge loads what `live` names from there.
|
|
64
|
-
// Every other harbor the pack holds stays, so one worker carries them all,
|
|
65
|
-
// and nothing in the pack opens without the secret.
|
|
66
|
-
export const pack = async (dir: string, file: string, name: string, secret: string | undefined): Promise<JsonObject> => {
|
|
67
|
-
if (!isHarborName(name)) throw new Error(`${name} is no harbor name: lowercase letters, digits and -`);
|
|
68
|
-
if (!secret) throw new Error('edge pack seals the seed under NERVUR_SECRET, and none is set');
|
|
69
|
-
if (!existsSync(join(dir, 'seed'))) throw new Error(`no harbor stands at ${dir}`);
|
|
70
|
-
const { seed, places } = await carry(dir, true);
|
|
71
|
-
const held = existsSync(file) ? readPack(JSON.parse(await readFile(file, 'utf8'))) : {};
|
|
72
|
-
if (held === null) throw new Error(`${file} is no pack`);
|
|
73
|
-
const packed: Pack = { ...held, [name]: { sealed: await sealSeed(secret, unhex(seed!)), places } };
|
|
74
|
-
await writeFile(file, `${JSON.stringify(packed)}\n`, { mode: 0o600 });
|
|
75
|
-
return { packed: name, package: file, harbors: Object.keys(packed).sort(), places: Object.keys(places).length };
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
// A carried harbor into an empty folder. A folder holding a seed or a
|
|
79
|
-
// place is left as it stands, and a package with no seed needs one there
|
|
80
|
-
// already, which a terrain that seals its custody writes its own way.
|
|
81
|
-
export const land = async (dir: string, value: unknown): Promise<string[]> => {
|
|
82
|
-
const held = readCarried(value);
|
|
83
|
-
if (held === null) throw new Error('that is no carried harbor');
|
|
84
|
-
const memory = new FolderMemory(dir);
|
|
85
|
-
if ((await memory.places()).length > 0 || (held.seed !== undefined && existsSync(join(dir, 'seed')))) throw new Error(`a harbor stands at ${dir}`);
|
|
86
|
-
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
87
|
-
if (held.seed !== undefined) await writeFile(join(dir, 'seed'), `${held.seed}\n`, { mode: 0o600, flag: 'wx' });
|
|
88
|
-
else if (!existsSync(join(dir, 'seed'))) throw new Error('the package carries no seed, and none is held here');
|
|
89
|
-
return landPlaces(memory, held);
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
// A served harbor: its pk, its tcp address, every address its carriers
|
|
93
|
-
// listen at, and its root line's socket.
|
|
94
|
-
export type Served = { pk: string; at: string; listening: string[]; root: string; close(): Promise<void> };
|
|
95
|
-
|
|
96
|
-
// The harbor served: a harbor of the Node ground, with Quo over the TCP
|
|
97
|
-
// carrier its root opened, on host and port. Serving adds nothing to the
|
|
98
|
-
// harbor, so one with no TCP carrier is not served.
|
|
99
|
-
export const serve = async (dir: string, defaults: Defaults, host?: string, port?: number): Promise<Served> => {
|
|
100
|
-
if (!existsSync(join(dir, 'seed'))) throw new Error(`no harbor stands at ${dir}: init one first`);
|
|
101
|
-
const harbor = await standing(new NodeTerrain({ dir, defaults }));
|
|
102
|
-
const tcpOf = (listening: string[]): string | undefined => listening.find((address) => tcpAddress(address) !== null);
|
|
103
|
-
const before = await census(harbor);
|
|
104
|
-
const present = Object.fromEntries(Object.entries(before.beings).filter(([, being]) => !being.absent));
|
|
105
|
-
const tcp = carrierIn(present, defaults.classes, 'tcp');
|
|
106
|
-
if (tcp?.open !== undefined || tcp === null) {
|
|
107
|
-
await harbor.close();
|
|
108
|
-
const kind = tcp?.open?.args?.class;
|
|
109
|
-
throw new Error(`the harbor at ${dir} has no tcp carrier${typeof kind === 'string' ? `: open one with \`nervur open tcp ${kind}\`` : ''}`);
|
|
110
|
-
}
|
|
111
|
-
if (host !== undefined || port !== undefined || tcpOf(before.listening) === undefined) {
|
|
112
|
-
const heard = await harbor.ask({ method: 'ask', args: { being: tcp.key, method: 'listen', args: { ...(host === undefined ? {} : { host }), ...(port === undefined ? {} : { port }) } } });
|
|
113
|
-
if (typeof ((heard.answer as JsonObject | undefined)?.answer as JsonObject | undefined)?.at !== 'string') {
|
|
114
|
-
await harbor.close();
|
|
115
|
-
throw new Error(`the harbor does not listen: ${JSON.stringify(heard.answer ?? heard)}`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
const { pk, listening } = await census(harbor);
|
|
119
|
-
return { pk, at: tcpOf(listening)!, listening, root: socketOf(dir), close: () => harbor.close() };
|
|
120
|
-
};
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The contracts: what the onion cannot unpack from cells, a module's code
|
|
3
|
-
// among them, each an abstract class, so a registry can tell at run time
|
|
4
|
-
// which class fulfils which. The class differs by terrain, and the
|
|
5
|
-
// contract does not.
|
|
6
|
-
import type { Draw } from '../quo/index.ts';
|
|
7
|
-
|
|
8
|
-
// Drawn bytes.
|
|
9
|
-
export abstract class Entropy {
|
|
10
|
-
abstract draw(length: number): Uint8Array;
|
|
11
|
-
// The same source, as the function `quo/` takes.
|
|
12
|
-
get drawer(): Draw {
|
|
13
|
-
return (length) => this.draw(length);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// The moment, and a wait that ends.
|
|
18
|
-
export abstract class Clock {
|
|
19
|
-
abstract now(): number;
|
|
20
|
-
// Resolves after `ms`, unless cancelled first.
|
|
21
|
-
abstract wait(ms: number): { done: Promise<void>; cancel(): void };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// One ward's partition, as the harbor's package opens it: the rows the
|
|
25
|
-
// ward writes into directly, told after every write, and kept once at the
|
|
26
|
-
// end of an arrival.
|
|
27
|
-
export interface Rows {
|
|
28
|
-
readonly rows: Record<string, unknown>;
|
|
29
|
-
told(row: string): void;
|
|
30
|
-
kept(): Promise<boolean>;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// A harbor's memory as a terrain keeps it: sealed entries it cannot read,
|
|
34
|
-
// in places, each entry by name. Every name is lowercase hex the kit
|
|
35
|
-
// chose, so a body may use it as a file name as it stands.
|
|
36
|
-
export abstract class Memory {
|
|
37
|
-
// Every entry kept in a place; a place nothing was kept in is empty.
|
|
38
|
-
abstract read(place: string): Promise<Map<string, Uint8Array>>;
|
|
39
|
-
// One keep, whole: every entry written and every null removed together,
|
|
40
|
-
// or none of them. A read after a keep that did not finish, in this run
|
|
41
|
-
// or in the run before it, holds the place as it was or as the keep
|
|
42
|
-
// leaves it, and never half of each.
|
|
43
|
-
abstract write(place: string, entries: ReadonlyMap<string, Uint8Array | null>): Promise<void>;
|
|
44
|
-
// Every place this memory holds something in, in any order.
|
|
45
|
-
abstract places(): Promise<string[]>;
|
|
46
|
-
// A place and everything in it, gone.
|
|
47
|
-
abstract forget(place: string): Promise<void>;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// The harbor's seed: thirty-two bytes, the same every time. It is the one
|
|
51
|
-
// secret a terrain holds.
|
|
52
|
-
export abstract class Custody {
|
|
53
|
-
abstract seed(): Promise<Uint8Array>;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// A module: the code a harbor's classes come from. It declares its own
|
|
57
|
-
// name, a reversed domain as a kind is, and its version.
|
|
58
|
-
export type Module = { readonly module: string; readonly version: string; readonly classes: readonly unknown[] };
|
|
59
|
-
|
|
60
|
-
// Bytes become a module. A module's source is one self-contained ES
|
|
61
|
-
// module that imports nothing but `'nervur'`, and `id` is the git id of
|
|
62
|
-
// its blob, the one name a bundle finds it by. What does not load throws,
|
|
63
|
-
// saying why. How code runs differs by ground, an import of a data: URL,
|
|
64
|
-
// of a Blob URL, or a lookup in the bundle an edge was deployed with, so
|
|
65
|
-
// the loader is the one body beside the seed a terrain hands in that code
|
|
66
|
-
// passes through.
|
|
67
|
-
export abstract class Loader {
|
|
68
|
-
abstract load(source: string, id: string): Promise<Module>;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// A module a bundle carries: its source, whose blob's id names it, and the
|
|
72
|
-
// module the bundler built from that source.
|
|
73
|
-
export type Bundled = { readonly source: string; readonly module: Module };
|
|
74
|
-
|
|
75
|
-
export { bindKit, linked, moduleOf } from './link.ts';
|
|
76
|
-
|
|
77
|
-
// Bytes to a ward pk in; bytes, or null for nothing, out. A harbor hands a
|
|
78
|
-
// terrain's carrier what it holds no route for; what it routes goes to its
|
|
79
|
-
// carrier faculties.
|
|
80
|
-
export abstract class Carrier {
|
|
81
|
-
abstract carry(pk: string, bytes: Uint8Array): Promise<Uint8Array | null>;
|
|
82
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// A module's `'nervur'` is the kit already running. An author writes
|
|
3
|
-
// `import { Being } from 'nervur'`, and a loader rewrites each such import
|
|
4
|
-
// into a read of this copy's exports before it runs the source, so a
|
|
5
|
-
// class the module declares extends the very `Being` the harbor checks it
|
|
6
|
-
// against. Each copy of the kit a process holds keeps its exports under
|
|
7
|
-
// its own token in one registered map, since two copies in one process are
|
|
8
|
-
// two sets of classes. The entry binds them once it has evaluated.
|
|
9
|
-
import type { Module } from './index.ts';
|
|
10
|
-
|
|
11
|
-
const KITS = 'org.nervur.kits';
|
|
12
|
-
|
|
13
|
-
type Kits = Map<string, object>;
|
|
14
|
-
const kits = (): Kits => {
|
|
15
|
-
const holder = globalThis as unknown as Record<symbol, Kits | undefined>;
|
|
16
|
-
return (holder[Symbol.for(KITS)] ??= new Map());
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// This copy's token, the count of copies bound before it, since an edge
|
|
20
|
-
// draws no random bytes while its script loads.
|
|
21
|
-
let token: string | undefined;
|
|
22
|
-
|
|
23
|
-
// This copy's exports, as a module's `'nervur'` reads them.
|
|
24
|
-
export const bindKit = (kit: object): void => {
|
|
25
|
-
const all = kits();
|
|
26
|
-
token ??= `kit${String(all.size)}`;
|
|
27
|
-
all.set(token, kit);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const IMPORT = /\bimport\s*(\{[^}]*\}|\*\s*as\s+[A-Za-z_$][\w$]*)\s*from\s*(['"])nervur\2\s*;?/g;
|
|
31
|
-
const OTHER = /(^|[\n;{}])\s*(import\s*[\w{*'"]|export\s*(\*|\{[^}]*\})\s*from\b)/;
|
|
32
|
-
|
|
33
|
-
// A module's source with its `'nervur'` imports read from this copy, or a
|
|
34
|
-
// throw where it imports anything else.
|
|
35
|
-
export const linked = (source: string): string => {
|
|
36
|
-
if (token === undefined) throw new Error('no kit is bound to link a module against');
|
|
37
|
-
const kit = `globalThis[Symbol.for(${JSON.stringify(KITS)})].get(${JSON.stringify(token)})`;
|
|
38
|
-
const out = source.replace(IMPORT, (_all, names: string) => {
|
|
39
|
-
if (names.startsWith('*')) return `const ${names.replace(/^\*\s*as\s+/, '')} = ${kit};`;
|
|
40
|
-
const fields = names
|
|
41
|
-
.slice(1, -1)
|
|
42
|
-
.split(',')
|
|
43
|
-
.map((n) => n.trim())
|
|
44
|
-
.filter((n) => n !== '')
|
|
45
|
-
.map((n) => n.replace(/\s+as\s+/, ': '));
|
|
46
|
-
return `const { ${fields.join(', ')} } = ${kit};`;
|
|
47
|
-
});
|
|
48
|
-
if (OTHER.test(out)) throw new Error("a module imports nothing but 'nervur'");
|
|
49
|
-
return out;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// What a module's code exported, read as a module, or a throw saying what
|
|
53
|
-
// it lacks.
|
|
54
|
-
export const moduleOf = (exported: unknown): Module => {
|
|
55
|
-
const { module, version, classes } = (exported ?? {}) as { module?: unknown; version?: unknown; classes?: unknown };
|
|
56
|
-
if (typeof module !== 'string' || typeof version !== 'string' || !Array.isArray(classes)) throw new Error('the code exports no module: module, version and classes');
|
|
57
|
-
return { module, version, classes };
|
|
58
|
-
};
|
package/src/core/crypto/aes.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// AES-256-GCM with a sixteen-byte tag at the end of the ciphertext.
|
|
3
|
-
import { own, subtle } from './subtle.ts';
|
|
4
|
-
|
|
5
|
-
export const TAG = 16;
|
|
6
|
-
|
|
7
|
-
const cipher = (key: Uint8Array, nonce: Uint8Array, additional: Uint8Array) => ({
|
|
8
|
-
params: { name: 'AES-GCM', iv: own(nonce), additionalData: own(additional), tagLength: TAG * 8 },
|
|
9
|
-
key: subtle().importKey('raw', own(key), 'AES-GCM', false, ['encrypt', 'decrypt']),
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export const encrypt = async (key: Uint8Array, nonce: Uint8Array, additional: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array> => {
|
|
13
|
-
const c = cipher(key, nonce, additional);
|
|
14
|
-
return new Uint8Array(await subtle().encrypt(c.params, await c.key, own(plaintext)));
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
// The plaintext, or null when the ciphertext does not open.
|
|
18
|
-
export const decrypt = async (key: Uint8Array, nonce: Uint8Array, additional: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array | null> => {
|
|
19
|
-
if (ciphertext.length < TAG) return null;
|
|
20
|
-
const c = cipher(key, nonce, additional);
|
|
21
|
-
try {
|
|
22
|
-
return new Uint8Array(await subtle().decrypt(c.params, await c.key, own(ciphertext)));
|
|
23
|
-
} catch {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
};
|
package/src/core/crypto/bytes.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// Bytes and the one text spelling Quo gives them: hex, two lowercase digits
|
|
3
|
-
// a byte.
|
|
4
|
-
const DIGITS = Array.from({ length: 256 }, (_, at) => at.toString(16).padStart(2, '0'));
|
|
5
|
-
const HEX = /^(?:[0-9a-f]{2})*$/;
|
|
6
|
-
|
|
7
|
-
export const hex = (bytes: Uint8Array): string => {
|
|
8
|
-
let out = '';
|
|
9
|
-
for (const byte of bytes) out += DIGITS[byte];
|
|
10
|
-
return out;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// Hex of `length` bytes, or any length when none is named.
|
|
14
|
-
export const isHex = (text: unknown, length?: number): text is string =>
|
|
15
|
-
typeof text === 'string' && HEX.test(text) && (length === undefined || text.length === length * 2);
|
|
16
|
-
|
|
17
|
-
export const unhex = (text: string): Uint8Array => {
|
|
18
|
-
if (!isHex(text)) throw new TypeError('not hex');
|
|
19
|
-
const out = new Uint8Array(text.length / 2);
|
|
20
|
-
for (let at = 0; at < out.length; at += 1) out[at] = parseInt(text.slice(at * 2, at * 2 + 2), 16);
|
|
21
|
-
return out;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const concat = (...parts: Uint8Array[]): Uint8Array => {
|
|
25
|
-
const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
|
|
26
|
-
let at = 0;
|
|
27
|
-
for (const part of parts) {
|
|
28
|
-
out.set(part, at);
|
|
29
|
-
at += part.length;
|
|
30
|
-
}
|
|
31
|
-
return out;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export const zero = (bytes: Uint8Array): boolean => bytes.every((b) => b === 0);
|
|
35
|
-
|
|
36
|
-
const encoder = new TextEncoder();
|
|
37
|
-
export const utf8 = (text: string): Uint8Array => encoder.encode(text);
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// Ed25519 signs, as RFC 8032 defines it, by `@noble/curves` in every
|
|
3
|
-
// engine, since an engine's Web Crypto may refuse a secret the curve takes,
|
|
4
|
-
// and verifies with the cofactorless check the spec names, which the
|
|
5
|
-
// library's own verify does not make. The decoding rules are held here:
|
|
6
|
-
//
|
|
7
|
-
// a signature of any length but sixty-four
|
|
8
|
-
// an `s` at or above the group order
|
|
9
|
-
// an `R` that does not decode, or whose bytes are not its point's encoding
|
|
10
|
-
// a public key that does not decode, or whose y is at or above the prime
|
|
11
|
-
// a public key of small order, in any spelling
|
|
12
|
-
import { ed25519 } from '@noble/curves/ed25519.js';
|
|
13
|
-
import { concat } from './bytes.ts';
|
|
14
|
-
import { own, subtle } from './subtle.ts';
|
|
15
|
-
|
|
16
|
-
const P = 2n ** 255n - 19n;
|
|
17
|
-
const L = 2n ** 252n + 27742317777372353535851937790883648493n;
|
|
18
|
-
|
|
19
|
-
const mod = (a: bigint): bigint => ((a % P) + P) % P;
|
|
20
|
-
const power = (base: bigint, exponent: bigint): bigint => {
|
|
21
|
-
let out = 1n;
|
|
22
|
-
let b = mod(base);
|
|
23
|
-
for (let e = exponent; e > 0n; e >>= 1n) {
|
|
24
|
-
if (e & 1n) out = (out * b) % P;
|
|
25
|
-
b = (b * b) % P;
|
|
26
|
-
}
|
|
27
|
-
return out;
|
|
28
|
-
};
|
|
29
|
-
const D = mod(-121665n * power(121666n, P - 2n));
|
|
30
|
-
const ROOT_MINUS_ONE = power(2n, (P - 1n) / 4n);
|
|
31
|
-
|
|
32
|
-
const little = (bytes: Uint8Array): bigint => bytes.reduceRight((n, b) => (n << 8n) | BigInt(b), 0n);
|
|
33
|
-
|
|
34
|
-
type Point = { x: bigint; y: bigint; z: bigint; t: bigint };
|
|
35
|
-
|
|
36
|
-
// A point from its thirty-two bytes, or null where RFC 8032 section 5.1.3
|
|
37
|
-
// refuses it, the sign bit set on x = 0 included.
|
|
38
|
-
const decode = (bytes: Uint8Array): Point | null => {
|
|
39
|
-
if (bytes.length !== 32) return null;
|
|
40
|
-
const sign = (bytes[31]! & 0x80) !== 0;
|
|
41
|
-
const y = little(bytes) & ((1n << 255n) - 1n);
|
|
42
|
-
if (y >= P) return null;
|
|
43
|
-
const u = mod(y * y - 1n);
|
|
44
|
-
const v = mod(D * y * y + 1n);
|
|
45
|
-
let x = mod(u * power(v, 3n) * power(u * power(v, 7n), (P - 5n) / 8n));
|
|
46
|
-
const check = mod(v * x * x);
|
|
47
|
-
if (check === mod(-u)) x = mod(x * ROOT_MINUS_ONE);
|
|
48
|
-
else if (check !== u) return null;
|
|
49
|
-
if (x === 0n && sign) return null;
|
|
50
|
-
if ((x & 1n) !== (sign ? 1n : 0n)) x = mod(-x);
|
|
51
|
-
return { x, y, z: 1n, t: mod(x * y) };
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const add = (a: Point, b: Point): Point => {
|
|
55
|
-
const A = mod((a.y - a.x) * (b.y - b.x));
|
|
56
|
-
const B = mod((a.y + a.x) * (b.y + b.x));
|
|
57
|
-
const C = mod(2n * D * a.t * b.t);
|
|
58
|
-
const E = mod(2n * a.z * b.z);
|
|
59
|
-
const [e, f, g, h] = [B - A, E - C, E + C, B + A];
|
|
60
|
-
return { x: mod(e * f), y: mod(g * h), z: mod(f * g), t: mod(e * h) };
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
// Small order: eight times the point is the identity.
|
|
64
|
-
const smallOrder = (p: Point): boolean => {
|
|
65
|
-
let q = p;
|
|
66
|
-
for (let i = 0; i < 3; i += 1) q = add(q, q);
|
|
67
|
-
return q.x === 0n && q.y === q.z;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const secretOf = (secret: Uint8Array): Uint8Array => {
|
|
71
|
-
if (secret.length !== 32) throw new TypeError('a secret is thirty-two bytes');
|
|
72
|
-
return secret;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
export const ed25519Public = async (secret: Uint8Array): Promise<Uint8Array> => ed25519.getPublicKey(secretOf(secret));
|
|
76
|
-
|
|
77
|
-
export const sign = async (secret: Uint8Array, message: Uint8Array): Promise<Uint8Array> => ed25519.sign(message, secretOf(secret));
|
|
78
|
-
|
|
79
|
-
// The cofactorless check, `[s]B = R + [k]A`, on points decoded as above.
|
|
80
|
-
export const verify = async (pk: Uint8Array, message: Uint8Array, signature: Uint8Array): Promise<boolean> => {
|
|
81
|
-
if (signature.length !== 64) return false;
|
|
82
|
-
const key = decode(pk);
|
|
83
|
-
if (key === null || smallOrder(key)) return false;
|
|
84
|
-
if (decode(signature.subarray(0, 32)) === null) return false;
|
|
85
|
-
const s = little(signature.subarray(32));
|
|
86
|
-
if (s >= L) return false;
|
|
87
|
-
const R = ed25519.Point.fromBytes(signature.subarray(0, 32));
|
|
88
|
-
const A = ed25519.Point.fromBytes(pk);
|
|
89
|
-
const hashed = new Uint8Array(await subtle().digest('SHA-512', own(concat(signature.subarray(0, 32), pk, message))));
|
|
90
|
-
const k = little(hashed) % L;
|
|
91
|
-
return ed25519.Point.BASE.multiplyUnsafe(s).equals(R.add(A.multiplyUnsafe(k)));
|
|
92
|
-
};
|
package/src/core/crypto/hash.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// SHA-256 hashes, and HKDF-SHA-256 derives under the zero-length salt, with
|
|
3
|
-
// the label's ASCII bytes as `info`.
|
|
4
|
-
import { own, subtle } from './subtle.ts';
|
|
5
|
-
|
|
6
|
-
const SALT = new Uint8Array(0);
|
|
7
|
-
|
|
8
|
-
export const sha256 = async (bytes: Uint8Array): Promise<Uint8Array> => new Uint8Array(await subtle().digest('SHA-256', own(bytes)));
|
|
9
|
-
|
|
10
|
-
export const hkdf = async (ikm: Uint8Array, info: Uint8Array, length: number): Promise<Uint8Array> => {
|
|
11
|
-
const material = await subtle().importKey('raw', own(ikm), 'HKDF', false, ['deriveBits']);
|
|
12
|
-
const bits = await subtle().deriveBits({ name: 'HKDF', hash: 'SHA-256', salt: SALT, info: own(info) }, material, length * 8);
|
|
13
|
-
return new Uint8Array(bits);
|
|
14
|
-
};
|
package/src/core/crypto/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// The six algorithms Quo names, and bytes. Arithmetic only: no label, no
|
|
3
|
-
// key of Quo's, no decision.
|
|
4
|
-
export { concat, hex, isHex, unhex, utf8, zero } from './bytes.ts';
|
|
5
|
-
export { hkdf, sha256 } from './hash.ts';
|
|
6
|
-
export { isCount, readObject, readValue, writeValue, type Fields, type Json } from './json.ts';
|
|
7
|
-
export { decrypt, encrypt, TAG } from './aes.ts';
|
|
8
|
-
export { agree, x25519Public } from './x25519.ts';
|
|
9
|
-
export { ed25519Public, sign, verify } from './ed25519.ts';
|
|
10
|
-
export { CIPHERTEXT, decapsulate, EK, encapsulate, lockFrom, type Lock } from './mlkem.ts';
|