@amalgm/shell 0.1.113 → 0.1.115
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/PURPOSE.md +67 -6
- package/README.md +38 -7
- package/dist/authorization/device-key.d.ts +19 -0
- package/dist/authorization/device-key.js +81 -0
- package/dist/authorization/device-key.js.map +1 -0
- package/dist/authorization/index.d.ts +65 -0
- package/dist/authorization/index.js +63 -0
- package/dist/authorization/index.js.map +1 -0
- package/dist/authorization/issuer.d.ts +11 -0
- package/dist/authorization/issuer.js +76 -0
- package/dist/authorization/issuer.js.map +1 -0
- package/dist/authorization/key-store.d.ts +15 -0
- package/dist/authorization/key-store.js +148 -0
- package/dist/authorization/key-store.js.map +1 -0
- package/dist/authorization/recovery-client.d.ts +19 -0
- package/dist/authorization/recovery-client.js +102 -0
- package/dist/authorization/recovery-client.js.map +1 -0
- package/dist/authorization/recovery-host.d.ts +28 -0
- package/dist/authorization/recovery-host.js +93 -0
- package/dist/authorization/recovery-host.js.map +1 -0
- package/dist/authorization/recovery.d.ts +13 -0
- package/dist/authorization/recovery.js +27 -0
- package/dist/authorization/recovery.js.map +1 -0
- package/dist/authorization/secret-process.d.ts +2 -0
- package/dist/authorization/secret-process.js +32 -0
- package/dist/authorization/secret-process.js.map +1 -0
- package/dist/boot.d.ts +19 -11
- package/dist/boot.js +34 -25
- package/dist/boot.js.map +1 -1
- package/dist/builtin-agents.d.ts +3 -0
- package/dist/builtin-agents.js +15 -0
- package/dist/builtin-agents.js.map +1 -0
- package/dist/chat-composition.d.ts +19 -0
- package/dist/chat-composition.js +83 -0
- package/dist/chat-composition.js.map +1 -0
- package/dist/chat-host.d.ts +9 -25
- package/dist/chat-host.js +12 -158
- package/dist/chat-host.js.map +1 -1
- package/dist/cli.js +21 -13
- package/dist/cli.js.map +1 -1
- package/dist/content-cache-host.d.ts +7 -0
- package/dist/content-cache-host.js +23 -1
- package/dist/content-cache-host.js.map +1 -1
- package/dist/credentials-host.d.ts +1 -5
- package/dist/credentials-host.js +1 -5
- package/dist/credentials-host.js.map +1 -1
- package/dist/entity-record-store.d.ts +2 -0
- package/dist/entity-record-store.js +15 -0
- package/dist/entity-record-store.js.map +1 -1
- package/dist/forward.js +1 -1
- package/dist/forward.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/machine-host.d.ts +29 -0
- package/dist/machine-host.js +240 -10
- package/dist/machine-host.js.map +1 -1
- package/dist/parity.d.ts +1 -5
- package/dist/parity.js +4 -41
- package/dist/parity.js.map +1 -1
- package/dist/release-catalog.js +7 -4
- package/dist/release-catalog.js.map +1 -1
- package/dist/runtime-command-host.d.ts +11 -0
- package/dist/runtime-command-host.js +65 -0
- package/dist/runtime-command-host.js.map +1 -1
- package/dist/user-ground-host.js +60 -5
- package/dist/user-ground-host.js.map +1 -1
- package/npm-shrinkwrap.json +2326 -0
- package/package.json +15 -5
- package/dist/chat-payloads-host.d.ts +0 -8
- package/dist/chat-payloads-host.js +0 -76
- package/dist/chat-payloads-host.js.map +0 -1
- package/dist/chat-relay-host.d.ts +0 -24
- package/dist/chat-relay-host.js +0 -90
- package/dist/chat-relay-host.js.map +0 -1
- package/dist/drivers/claude-code.d.ts +0 -27
- package/dist/drivers/claude-code.js +0 -72
- package/dist/drivers/claude-code.js.map +0 -1
package/PURPOSE.md
CHANGED
|
@@ -13,7 +13,9 @@ shell only assembles.
|
|
|
13
13
|
|
|
14
14
|
2. **Bricks arrive through the registry.** Every `@amalgm/*` dependency is a
|
|
15
15
|
published npm version — never a `file:` link, never a copied source tree.
|
|
16
|
-
Upgrading the runtime means bumping a version, not merging code.
|
|
16
|
+
Upgrading the runtime means bumping a version, not merging code. Registry
|
|
17
|
+
proof runs under the supported Node executable that launched the gate;
|
|
18
|
+
ambient package-manager shims are not runtime evidence.
|
|
17
19
|
|
|
18
20
|
3. **Parity gates each released service.** The target begins with
|
|
19
21
|
`amalgm-engine`'s runtime surface, then subtracts only owner-approved
|
|
@@ -45,8 +47,8 @@ shell only assembles.
|
|
|
45
47
|
|
|
46
48
|
8. **The shell is the production runtime for its signed release.** The `amalgm`
|
|
47
49
|
bootstrap may install, supervise, and update the shell, but it never starts
|
|
48
|
-
an Engine implementation
|
|
49
|
-
|
|
50
|
+
an Engine implementation beside it or falls back to copied Engine behavior.
|
|
51
|
+
The current release is Core + Files + Agents + Tools + Chat.
|
|
50
52
|
|
|
51
53
|
9. **Login is Core followed by Live.** Core owns authentication, credential
|
|
52
54
|
separation, installation verification, restart proof, and readiness. Its
|
|
@@ -209,6 +211,13 @@ shell only assembles.
|
|
|
209
211
|
declared cargo is bounded, Shell supplies the cached manifest and blocks to
|
|
210
212
|
Live for the same submit frame; otherwise it uses the ordinary missing-block
|
|
211
213
|
effect. The cloud, not Shell, owns the final seal-before-number decision.
|
|
214
|
+
Cache bytes remain only while an unresolved durable operation names their
|
|
215
|
+
content head or while the current verified text or repository head is the
|
|
216
|
+
one exact base for that entity's next delta. Once Send acceptance is
|
|
217
|
+
durable, Shell removes every sealed artifact and manifest that neither a
|
|
218
|
+
pending Record nor a current replay base retains; restart performs the same
|
|
219
|
+
derivation from SQLite, so accepted history cannot accumulate as machine
|
|
220
|
+
storage.
|
|
212
221
|
|
|
213
222
|
25. **Each cold stage performs only its necessary byte pass.** Registration
|
|
214
223
|
reads every ordinary text or binary file once through the bounded capture
|
|
@@ -695,10 +704,62 @@ shell only assembles.
|
|
|
695
704
|
across restart, and all pre-page journal shapes convert atomically without
|
|
696
705
|
dropping an unknown authority outcome.
|
|
697
706
|
|
|
707
|
+
60. **Runtime binding is proved, never inferred.** A platform adapter adopts
|
|
708
|
+
an existing runtime only when Shell's published loopback address answers
|
|
709
|
+
its authenticated health probe for the selected user and runtime label. A
|
|
710
|
+
durable ready registration with no answering runtime may be resumed; an
|
|
711
|
+
absent or incomplete registration requires login. A UI marker, PID, open
|
|
712
|
+
port, or installed executable alone is never service readiness.
|
|
713
|
+
|
|
714
|
+
61. **Browser is composed once and driven through capability ports.** Shell
|
|
715
|
+
owns the one `BrowserService` composition for a machine runtime. A fresh,
|
|
716
|
+
private Electron host may supply Browser's visible driver and isolated
|
|
717
|
+
cookie adapter; without that capability Browser selects headless. Shell
|
|
718
|
+
never implements a second browser action, registry, profile, cookie, or
|
|
719
|
+
authentication authority, and a Browser session never changes backend. A
|
|
720
|
+
signed machine release that does not declare Browser must not instantiate
|
|
721
|
+
Browser state merely because the SDK is installed.
|
|
722
|
+
|
|
723
|
+
62. **PTY is one authenticated Shell host capability.** The running machine
|
|
724
|
+
runtime mounts the Core-owned PTY contract through Shell's native process
|
|
725
|
+
adapter and closes every spawned process with that runtime. A UI targeting
|
|
726
|
+
this computer connects through the published authenticated loopback
|
|
727
|
+
binding; only a different computer uses the remote relay. Electron never
|
|
728
|
+
creates a second PTY implementation. A session with no explicit working
|
|
729
|
+
directory starts at that signed-in user's portable Amalgm root.
|
|
730
|
+
|
|
731
|
+
63. **Chat has one execution path.** Agents resolves an installed identity and
|
|
732
|
+
exact immutable revision; Tools resolves the selected catalog revision;
|
|
733
|
+
Chat owns the conversation, provider pump, journal, reconnect, usage, and
|
|
734
|
+
interrupt. Shell mounts Chat's public HTTP adapter in both `bootShell` and
|
|
735
|
+
the signed `MachineHost`; it owns no session store, event translation, or
|
|
736
|
+
callback driver.
|
|
737
|
+
|
|
738
|
+
64. **One installation device key and broker serve every local product.**
|
|
739
|
+
Before registration, Shell creates one P-256 private key for the physical
|
|
740
|
+
installation, binds its public thumbprint into the approved setup intent,
|
|
741
|
+
and proves possession before pinning that thumbprint across the computer's
|
|
742
|
+
runtime labels. The key stays in macOS Keychain or a Windows DPAPI envelope
|
|
743
|
+
where available (or one mode-0600 fallback file). A registered runtime
|
|
744
|
+
treats missing or corrupt key material as a visible failure; it never
|
|
745
|
+
generates a replacement during startup. Replacement is an explicit,
|
|
746
|
+
browser-approved recovery: Shell stages one candidate, proves its private
|
|
747
|
+
key, reuses it across uncertain retries, and promotes it only after the
|
|
748
|
+
control plane conditionally accepts the server-derived prior thumbprint.
|
|
749
|
+
Shell mints short-lived grants through Core's broker and creates a fresh
|
|
750
|
+
DPoP proof for each request. Chat, Apps, and future products never receive
|
|
751
|
+
the key or durable machine credential.
|
|
752
|
+
|
|
753
|
+
65. **A Shell release is tested as the artifact users install.** The release
|
|
754
|
+
gate packs Shell, installs that tarball with the exact public Amalgm
|
|
755
|
+
dependency versions declared by its manifest, and exercises authorization
|
|
756
|
+
through Chat using package exports only. Sibling repositories and source
|
|
757
|
+
paths are never an integration-test dependency.
|
|
758
|
+
|
|
698
759
|
## Relationship to amalgm-engine
|
|
699
760
|
|
|
700
761
|
Stage 1 cut the bricks out of the engine. Stage 2 proves them here, composed.
|
|
701
762
|
Stage 3 ships each signed service from this shell and retires its Engine copy.
|
|
702
|
-
The
|
|
703
|
-
|
|
704
|
-
|
|
763
|
+
The current signed release is Core + Files + Agents + Tools + Chat. Later
|
|
764
|
+
services cross the same parity gate without creating a second runtime for
|
|
765
|
+
anything already released.
|
package/README.md
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
# @amalgm/shell
|
|
2
2
|
|
|
3
|
-
The Amalgm runtime, assembled from published `@amalgm/*` SDK
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
axioms.
|
|
3
|
+
The Amalgm runtime, assembled from published `@amalgm/*` SDK capabilities.
|
|
4
|
+
This repository owns their host composition; see [PURPOSE.md](PURPOSE.md) for
|
|
5
|
+
the axioms.
|
|
7
6
|
|
|
8
|
-
The
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
The signed runtime composes Core + Files + Agents + Tools + Chat. Agents owns
|
|
8
|
+
identity and immutable revision resolution; Chat alone owns durable
|
|
9
|
+
conversations, turns, reconnect, and interrupt; Shell supplies the host effects
|
|
10
|
+
and one authenticated `/chat` protocol.
|
|
11
11
|
|
|
12
12
|
## Layout
|
|
13
13
|
|
|
14
14
|
- `src/boot.ts` — assembles the HTTP/MCP runtime from bricks.
|
|
15
15
|
- `src/machine-host.ts` — production effects injected into Core's machine setup.
|
|
16
|
+
- `src/runtime-command-host.ts` — authenticated loopback publication and the
|
|
17
|
+
read-only runtime-health contract used by platform adapters.
|
|
18
|
+
- `src/authorization/` — the installation device key, UI issuance adapter, and
|
|
19
|
+
Core credential-broker composition shared by local products.
|
|
16
20
|
- `src/user-ground-host.ts` — production effects injected into Live registration.
|
|
17
21
|
- `src/wire-client.ts` — the single authenticated gateway control path.
|
|
18
22
|
- `src/content-direct.ts` — authorized direct-R2 download and local envelope opening.
|
|
@@ -20,12 +24,24 @@ injects the real filesystem, SQLite, watcher, and authenticated cloud wire.
|
|
|
20
24
|
health, and retry; portable Watch law remains in `@amalgm/live`.
|
|
21
25
|
- `tests/` — parity, adapter, restart, watcher, and two-device examinations.
|
|
22
26
|
|
|
27
|
+
Authorization issuers must be HTTPS origins outside loopback development,
|
|
28
|
+
credential-bearing redirects are rejected, and missing or unreadable stored
|
|
29
|
+
key material fails closed rather than silently rotating a server-pinned
|
|
30
|
+
identity. Recovery stages a separate candidate, requires browser approval and
|
|
31
|
+
candidate-key proof, and promotes only the server-accepted key.
|
|
32
|
+
Consumers use the contained `@amalgm/shell/authorization` export; importing
|
|
33
|
+
authorization does not load unrelated native runtime adapters.
|
|
34
|
+
|
|
23
35
|
## Run
|
|
24
36
|
|
|
25
37
|
```bash
|
|
26
38
|
npm install
|
|
27
39
|
npm test
|
|
28
40
|
|
|
41
|
+
# Pack Shell, install its exact released Amalgm dependencies in isolation,
|
|
42
|
+
# and exercise issuance, renewal, revocation, Chat egress, and key recovery.
|
|
43
|
+
npm run test:released-package
|
|
44
|
+
|
|
29
45
|
# Isolated real-kernel Watch certification (macOS/Linux/Windows)
|
|
30
46
|
AMALGM_NATIVE_WATCH=1 node --test tests/watching/native.test.js
|
|
31
47
|
|
|
@@ -37,6 +53,12 @@ npx --package @amalgm/shell amalgm login --no-open
|
|
|
37
53
|
# Resume one user on a machine that has several
|
|
38
54
|
npx --package @amalgm/shell amalgm run --user person@example.com
|
|
39
55
|
|
|
56
|
+
# Inspect registration and authenticated runtime health without starting either
|
|
57
|
+
npx --package @amalgm/shell amalgm status --user person@example.com
|
|
58
|
+
|
|
59
|
+
# Explicitly recover a missing, corrupt, or server-rejected device key
|
|
60
|
+
npx --package @amalgm/shell amalgm auth recover --user person@example.com
|
|
61
|
+
|
|
40
62
|
# In another shell, declare an external workspace; the running Watch performs registration
|
|
41
63
|
npx --package @amalgm/shell amalgm files register ./project --user person@example.com
|
|
42
64
|
|
|
@@ -46,6 +68,15 @@ npx --package @amalgm/shell amalgm files add <workspace-id> --user person@exampl
|
|
|
46
68
|
|
|
47
69
|
Requires Node ≥ 20.19 (native `require(esm)` support; all bricks are ESM).
|
|
48
70
|
|
|
71
|
+
Package releases use `.github/workflows/publish-package.yml`. A reviewed main
|
|
72
|
+
commit is tagged exactly `v<package version>`; trusted npm publishing stages
|
|
73
|
+
that package, and a maintainer approves the staged artifact with 2FA. Manual
|
|
74
|
+
dirty-worktree publishing is not a release path. The release workflow also
|
|
75
|
+
installs the packed Shell in a clean temporary project and runs the public
|
|
76
|
+
authorization/Chat E2E against the exact registry versions in `package.json`.
|
|
77
|
+
The published `npm-shrinkwrap.json` fixes the complete dependency tree, and
|
|
78
|
+
that examination rejects any installed direct dependency that differs from it.
|
|
79
|
+
|
|
49
80
|
Every push to `main` and every pull request runs the complete suite plus the
|
|
50
81
|
isolated real-kernel Watch examination on GitHub-hosted Linux, macOS, and
|
|
51
82
|
Windows machines. This certifies the same create, change, rename, move, delete,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type JsonWebKey } from "node:crypto";
|
|
2
|
+
import { type DpopSignerPort } from "@amalgm/core/authorization";
|
|
3
|
+
import type { DeviceKeyStore, StoredDeviceKey } from "./key-store.js";
|
|
4
|
+
export interface DeviceKey extends DpopSignerPort {
|
|
5
|
+
readonly publicJwk: JsonWebKey;
|
|
6
|
+
}
|
|
7
|
+
export declare function loadDeviceKey(store: DeviceKeyStore, ports?: Readonly<{
|
|
8
|
+
nowMs?: () => number;
|
|
9
|
+
randomUuid?: () => string;
|
|
10
|
+
}>): Promise<DeviceKey>;
|
|
11
|
+
export declare function requireDeviceKey(store: DeviceKeyStore, ports?: Readonly<{
|
|
12
|
+
nowMs?: () => number;
|
|
13
|
+
randomUuid?: () => string;
|
|
14
|
+
}>): Promise<DeviceKey>;
|
|
15
|
+
export declare function generateStoredDeviceKey(): StoredDeviceKey;
|
|
16
|
+
export declare function deviceKeyFromStored(stored: StoredDeviceKey, ports: Readonly<{
|
|
17
|
+
nowMs?: () => number;
|
|
18
|
+
randomUuid?: () => string;
|
|
19
|
+
}>): DeviceKey;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createHash, createPrivateKey, generateKeyPairSync, randomUUID, sign, } from "node:crypto";
|
|
2
|
+
import { normalizeDpopHtu, normalizeDpopMethod, } from "@amalgm/core/authorization";
|
|
3
|
+
export async function loadDeviceKey(store, ports = {}) {
|
|
4
|
+
let stored = await store.load();
|
|
5
|
+
if (!stored) {
|
|
6
|
+
stored = generateStoredDeviceKey();
|
|
7
|
+
await store.save(stored);
|
|
8
|
+
}
|
|
9
|
+
return deviceKeyFromStored(stored, ports);
|
|
10
|
+
}
|
|
11
|
+
export async function requireDeviceKey(store, ports = {}) {
|
|
12
|
+
const stored = await store.load();
|
|
13
|
+
if (!stored) {
|
|
14
|
+
throw Object.assign(new Error("Stored authorization key is missing"), {
|
|
15
|
+
code: "authorization_key_missing",
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return deviceKeyFromStored(stored, ports);
|
|
19
|
+
}
|
|
20
|
+
export function generateStoredDeviceKey() {
|
|
21
|
+
const { privateKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
|
|
22
|
+
return Object.freeze({
|
|
23
|
+
version: 1,
|
|
24
|
+
privateJwk: privateKey.export({ format: "jwk" }),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export function deviceKeyFromStored(stored, ports) {
|
|
28
|
+
const privateJwk = stored.privateJwk;
|
|
29
|
+
if (stored.version !== 1
|
|
30
|
+
|| privateJwk.kty !== "EC"
|
|
31
|
+
|| privateJwk.crv !== "P-256"
|
|
32
|
+
|| !privateJwk.x
|
|
33
|
+
|| !privateJwk.y
|
|
34
|
+
|| !privateJwk.d) {
|
|
35
|
+
throw new Error("Stored authorization key is not a P-256 private JWK");
|
|
36
|
+
}
|
|
37
|
+
const publicJwk = Object.freeze({
|
|
38
|
+
kty: "EC",
|
|
39
|
+
crv: "P-256",
|
|
40
|
+
x: privateJwk.x,
|
|
41
|
+
y: privateJwk.y,
|
|
42
|
+
});
|
|
43
|
+
const keyThumbprint = base64url(createHash("sha256").update(JSON.stringify({
|
|
44
|
+
crv: publicJwk.crv,
|
|
45
|
+
kty: publicJwk.kty,
|
|
46
|
+
x: publicJwk.x,
|
|
47
|
+
y: publicJwk.y,
|
|
48
|
+
})).digest());
|
|
49
|
+
const privateKey = createPrivateKey({ key: privateJwk, format: "jwk" });
|
|
50
|
+
return Object.freeze({
|
|
51
|
+
publicJwk,
|
|
52
|
+
keyThumbprint,
|
|
53
|
+
signProof: async (input) => {
|
|
54
|
+
const header = base64url(JSON.stringify({
|
|
55
|
+
typ: "dpop+jwt",
|
|
56
|
+
alg: "ES256",
|
|
57
|
+
jwk: publicJwk,
|
|
58
|
+
}));
|
|
59
|
+
const payload = base64url(JSON.stringify({
|
|
60
|
+
htm: normalizeDpopMethod(input.method),
|
|
61
|
+
htu: normalizeDpopHtu(input.url),
|
|
62
|
+
iat: Math.floor((ports.nowMs?.() ?? Date.now()) / 1000),
|
|
63
|
+
jti: ports.randomUuid?.() ?? randomUUID(),
|
|
64
|
+
...(input.accessToken ? { ath: tokenHash(input.accessToken) } : {}),
|
|
65
|
+
}));
|
|
66
|
+
const signingInput = `${header}.${payload}`;
|
|
67
|
+
const signature = sign("sha256", Buffer.from(signingInput), {
|
|
68
|
+
key: privateKey,
|
|
69
|
+
dsaEncoding: "ieee-p1363",
|
|
70
|
+
});
|
|
71
|
+
return `${signingInput}.${base64url(signature)}`;
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function tokenHash(token) {
|
|
76
|
+
return base64url(createHash("sha256").update(token).digest());
|
|
77
|
+
}
|
|
78
|
+
function base64url(value) {
|
|
79
|
+
return Buffer.from(value).toString("base64url");
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=device-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-key.js","sourceRoot":"","sources":["../../src/authorization/device-key.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { CredentialBroker } from "@amalgm/core/authorization";
|
|
2
|
+
import type { DeviceKeyStore } from "./key-store.js";
|
|
3
|
+
import { type DeviceKeyRecoveryStores } from "./recovery.js";
|
|
4
|
+
export { requestAuthorizationKeyRecovery } from "./recovery-client.js";
|
|
5
|
+
export type { AuthorizationRecoveryClientOptions } from "./recovery-client.js";
|
|
6
|
+
export interface ShellAuthorizationOptions {
|
|
7
|
+
/** Installation-scoped Shell state directory, shared by every local product. */
|
|
8
|
+
readonly stateDir: string;
|
|
9
|
+
readonly appUrl: string;
|
|
10
|
+
readonly computerAuthToken: string;
|
|
11
|
+
readonly computerId: string;
|
|
12
|
+
readonly deviceId: string;
|
|
13
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
14
|
+
readonly platform?: NodeJS.Platform;
|
|
15
|
+
readonly keyStore?: DeviceKeyStore;
|
|
16
|
+
readonly nowMs?: () => number;
|
|
17
|
+
readonly random?: () => number;
|
|
18
|
+
}
|
|
19
|
+
export declare function loadInstallationDeviceKey(options: Readonly<{
|
|
20
|
+
stateDir: string;
|
|
21
|
+
deviceId: string;
|
|
22
|
+
platform?: NodeJS.Platform;
|
|
23
|
+
keyStore?: DeviceKeyStore;
|
|
24
|
+
nowMs?: () => number;
|
|
25
|
+
}>): Promise<import("./device-key.js").DeviceKey>;
|
|
26
|
+
export declare function requireInstallationDeviceKey(options: Readonly<{
|
|
27
|
+
stateDir: string;
|
|
28
|
+
deviceId: string;
|
|
29
|
+
platform?: NodeJS.Platform;
|
|
30
|
+
keyStore?: DeviceKeyStore;
|
|
31
|
+
nowMs?: () => number;
|
|
32
|
+
}>): Promise<import("./device-key.js").DeviceKey>;
|
|
33
|
+
export declare function installationDeviceKeyStores(options: Readonly<{
|
|
34
|
+
stateDir: string;
|
|
35
|
+
deviceId: string;
|
|
36
|
+
platform?: NodeJS.Platform;
|
|
37
|
+
keyStore?: DeviceKeyStore;
|
|
38
|
+
recoveryKeyStore?: DeviceKeyStore;
|
|
39
|
+
}>): DeviceKeyRecoveryStores;
|
|
40
|
+
export declare function stageInstallationDeviceKeyRecovery(options: Readonly<{
|
|
41
|
+
stateDir: string;
|
|
42
|
+
deviceId: string;
|
|
43
|
+
platform?: NodeJS.Platform;
|
|
44
|
+
keyStore?: DeviceKeyStore;
|
|
45
|
+
recoveryKeyStore?: DeviceKeyStore;
|
|
46
|
+
nowMs?: () => number;
|
|
47
|
+
}>): Promise<import("./device-key.js").DeviceKey>;
|
|
48
|
+
export declare function promoteInstallationDeviceKeyRecovery(options: Readonly<{
|
|
49
|
+
stateDir: string;
|
|
50
|
+
deviceId: string;
|
|
51
|
+
acceptedKeyThumbprint: string;
|
|
52
|
+
platform?: NodeJS.Platform;
|
|
53
|
+
keyStore?: DeviceKeyStore;
|
|
54
|
+
recoveryKeyStore?: DeviceKeyStore;
|
|
55
|
+
}>): Promise<import("./device-key.js").DeviceKey>;
|
|
56
|
+
/** Compose one key and one live broker for every local product in this runtime. */
|
|
57
|
+
export declare function createShellAuthorization(options: ShellAuthorizationOptions): Promise<CredentialBroker>;
|
|
58
|
+
export { deviceKeyFromStored, generateStoredDeviceKey, loadDeviceKey, requireDeviceKey, } from "./device-key.js";
|
|
59
|
+
export type { DeviceKey } from "./device-key.js";
|
|
60
|
+
export { createDeviceKeyStore } from "./key-store.js";
|
|
61
|
+
export type { DeviceKeyStore, StoredDeviceKey } from "./key-store.js";
|
|
62
|
+
export { promoteDeviceKeyRecovery, stageDeviceKeyRecovery } from "./recovery.js";
|
|
63
|
+
export type { DeviceKeyRecoveryStores } from "./recovery.js";
|
|
64
|
+
export { createShellCredentialIssuer } from "./issuer.js";
|
|
65
|
+
export type { ShellCredentialIssuerOptions } from "./issuer.js";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { CredentialBroker } from "@amalgm/core/authorization";
|
|
3
|
+
import { loadDeviceKey, requireDeviceKey } from "./device-key.js";
|
|
4
|
+
import { createShellCredentialIssuer } from "./issuer.js";
|
|
5
|
+
import { createDeviceKeyStore } from "./key-store.js";
|
|
6
|
+
import { promoteDeviceKeyRecovery, stageDeviceKeyRecovery, } from "./recovery.js";
|
|
7
|
+
export { requestAuthorizationKeyRecovery } from "./recovery-client.js";
|
|
8
|
+
export async function loadInstallationDeviceKey(options) {
|
|
9
|
+
const store = options.keyStore ?? createDeviceKeyStore({
|
|
10
|
+
file: join(options.stateDir, "authorization", "device-key.json"),
|
|
11
|
+
account: `device:${options.deviceId}`,
|
|
12
|
+
...(options.platform ? { platform: options.platform } : {}),
|
|
13
|
+
});
|
|
14
|
+
return loadDeviceKey(store, { nowMs: options.nowMs });
|
|
15
|
+
}
|
|
16
|
+
export async function requireInstallationDeviceKey(options) {
|
|
17
|
+
const stores = installationDeviceKeyStores(options);
|
|
18
|
+
return requireDeviceKey(stores.active, { nowMs: options.nowMs });
|
|
19
|
+
}
|
|
20
|
+
export function installationDeviceKeyStores(options) {
|
|
21
|
+
const platform = options.platform ? { platform: options.platform } : {};
|
|
22
|
+
return Object.freeze({
|
|
23
|
+
active: options.keyStore ?? createDeviceKeyStore({
|
|
24
|
+
file: join(options.stateDir, "authorization", "device-key.json"),
|
|
25
|
+
account: `device:${options.deviceId}`,
|
|
26
|
+
...platform,
|
|
27
|
+
}),
|
|
28
|
+
pending: options.recoveryKeyStore ?? createDeviceKeyStore({
|
|
29
|
+
file: join(options.stateDir, "authorization", "device-key-recovery.json"),
|
|
30
|
+
account: `device:${options.deviceId}:recovery`,
|
|
31
|
+
...platform,
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export async function stageInstallationDeviceKeyRecovery(options) {
|
|
36
|
+
return stageDeviceKeyRecovery(installationDeviceKeyStores(options), { nowMs: options.nowMs });
|
|
37
|
+
}
|
|
38
|
+
export async function promoteInstallationDeviceKeyRecovery(options) {
|
|
39
|
+
return promoteDeviceKeyRecovery(installationDeviceKeyStores(options), options.acceptedKeyThumbprint);
|
|
40
|
+
}
|
|
41
|
+
/** Compose one key and one live broker for every local product in this runtime. */
|
|
42
|
+
export async function createShellAuthorization(options) {
|
|
43
|
+
const signer = await requireInstallationDeviceKey(options);
|
|
44
|
+
const issuer = createShellCredentialIssuer({
|
|
45
|
+
appUrl: options.appUrl,
|
|
46
|
+
computerAuthToken: options.computerAuthToken,
|
|
47
|
+
computerId: options.computerId,
|
|
48
|
+
deviceId: options.deviceId,
|
|
49
|
+
signer,
|
|
50
|
+
...(options.fetch ? { fetch: options.fetch } : {}),
|
|
51
|
+
});
|
|
52
|
+
return new CredentialBroker({
|
|
53
|
+
issuer,
|
|
54
|
+
signer,
|
|
55
|
+
nowMs: options.nowMs ?? (() => Date.now()),
|
|
56
|
+
random: options.random ?? (() => Math.random()),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export { deviceKeyFromStored, generateStoredDeviceKey, loadDeviceKey, requireDeviceKey, } from "./device-key.js";
|
|
60
|
+
export { createDeviceKeyStore } from "./key-store.js";
|
|
61
|
+
export { promoteDeviceKeyRecovery, stageDeviceKeyRecovery } from "./recovery.js";
|
|
62
|
+
export { createShellCredentialIssuer } from "./issuer.js";
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/authorization/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CredentialIssuerPort, DpopSignerPort } from "@amalgm/core/authorization";
|
|
2
|
+
export interface ShellCredentialIssuerOptions {
|
|
3
|
+
readonly appUrl: string;
|
|
4
|
+
readonly computerAuthToken: string;
|
|
5
|
+
readonly computerId: string;
|
|
6
|
+
readonly deviceId: string;
|
|
7
|
+
readonly clientId?: string;
|
|
8
|
+
readonly signer: DpopSignerPort;
|
|
9
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
10
|
+
}
|
|
11
|
+
export declare function createShellCredentialIssuer(options: ShellCredentialIssuerOptions): CredentialIssuerPort;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export function createShellCredentialIssuer(options) {
|
|
2
|
+
const endpoint = `${authorizationOrigin(options.appUrl)}/api/authorization/v1/tokens`;
|
|
3
|
+
const request = options.fetch ?? globalThis.fetch;
|
|
4
|
+
return {
|
|
5
|
+
issue: async (grant) => {
|
|
6
|
+
const proof = await options.signer.signProof({ method: "POST", url: endpoint });
|
|
7
|
+
const response = await request(endpoint, {
|
|
8
|
+
method: "POST",
|
|
9
|
+
headers: {
|
|
10
|
+
authorization: `Bearer ${options.computerAuthToken}`,
|
|
11
|
+
"content-type": "application/json",
|
|
12
|
+
dpop: proof,
|
|
13
|
+
},
|
|
14
|
+
redirect: "error",
|
|
15
|
+
body: JSON.stringify({
|
|
16
|
+
computer_id: options.computerId,
|
|
17
|
+
device_id: options.deviceId,
|
|
18
|
+
client_id: options.clientId ?? "amalgm-shell",
|
|
19
|
+
audience: grant.audience,
|
|
20
|
+
scopes: grant.scopes,
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
const body = await response.json().catch(() => ({}));
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
throw Object.assign(new Error(text(body.error) || "Access credential issuance failed"), {
|
|
26
|
+
code: text(body.code) || `authorization_http_${response.status}`,
|
|
27
|
+
status: response.status,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return issuedCredential(body, grant.keyThumbprint);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function authorizationOrigin(value) {
|
|
35
|
+
let url;
|
|
36
|
+
try {
|
|
37
|
+
url = new URL(value);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new TypeError("appUrl must be an HTTPS origin");
|
|
41
|
+
}
|
|
42
|
+
const local = url.hostname === "localhost" || url.hostname === "127.0.0.1";
|
|
43
|
+
if ((url.protocol !== "https:" && !(local && url.protocol === "http:"))
|
|
44
|
+
|| url.username
|
|
45
|
+
|| url.password
|
|
46
|
+
|| url.search
|
|
47
|
+
|| url.hash
|
|
48
|
+
|| url.pathname !== "/")
|
|
49
|
+
throw new TypeError("appUrl must be an HTTPS origin");
|
|
50
|
+
return url.origin;
|
|
51
|
+
}
|
|
52
|
+
function issuedCredential(body, keyThumbprint) {
|
|
53
|
+
const accessToken = text(body.access_token);
|
|
54
|
+
const audience = text(body.audience);
|
|
55
|
+
const scopes = Array.isArray(body.scopes)
|
|
56
|
+
? body.scopes.filter((scope) => typeof scope === "string")
|
|
57
|
+
: [];
|
|
58
|
+
const expiresAtMs = Date.parse(text(body.expires_at));
|
|
59
|
+
if (!accessToken || body.token_type !== "DPoP" || !audience || scopes.length === 0 || !Number.isFinite(expiresAtMs)) {
|
|
60
|
+
throw Object.assign(new Error("Authorization server returned an invalid credential"), {
|
|
61
|
+
code: "invalid_authorization_response",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return Object.freeze({
|
|
65
|
+
accessToken,
|
|
66
|
+
tokenType: "DPoP",
|
|
67
|
+
audience,
|
|
68
|
+
scopes: Object.freeze(scopes),
|
|
69
|
+
expiresAtMs,
|
|
70
|
+
keyThumbprint,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function text(value) {
|
|
74
|
+
return typeof value === "string" ? value.trim() : "";
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=issuer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issuer.js","sourceRoot":"","sources":["../../src/authorization/issuer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { JsonWebKey } from "node:crypto";
|
|
2
|
+
export interface StoredDeviceKey {
|
|
3
|
+
readonly version: 1;
|
|
4
|
+
readonly privateJwk: JsonWebKey;
|
|
5
|
+
}
|
|
6
|
+
export interface DeviceKeyStore {
|
|
7
|
+
load(): Promise<StoredDeviceKey | null>;
|
|
8
|
+
save(key: StoredDeviceKey): Promise<void>;
|
|
9
|
+
remove(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export declare function createDeviceKeyStore(input: Readonly<{
|
|
12
|
+
file: string;
|
|
13
|
+
account: string;
|
|
14
|
+
platform?: NodeJS.Platform;
|
|
15
|
+
}>): DeviceKeyStore;
|