@hwip/cli 0.0.1 → 0.1.0
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/LICENSE +190 -0
- package/NOTICE +11 -0
- package/README.md +1979 -0
- package/dist/agent-list.d.ts +76 -0
- package/dist/agent-list.js +102 -0
- package/dist/agent-read.d.ts +105 -0
- package/dist/agent-read.js +309 -0
- package/dist/agent-rules-fetch.d.ts +51 -0
- package/dist/agent-rules-fetch.js +275 -0
- package/dist/agent-rules.default.d.ts +30 -0
- package/dist/agent-rules.default.js +292 -0
- package/dist/agent-session.d.ts +23 -0
- package/dist/agent-session.js +44 -0
- package/dist/agent-state.d.ts +84 -0
- package/dist/agent-state.js +188 -0
- package/dist/agent-target.d.ts +60 -0
- package/dist/agent-target.js +81 -0
- package/dist/agents.d.ts +31 -0
- package/dist/agents.js +75 -0
- package/dist/api.d.ts +28 -0
- package/dist/api.js +76 -0
- package/dist/args.d.ts +74 -0
- package/dist/args.js +254 -0
- package/dist/ask-context-attach.d.ts +73 -0
- package/dist/ask-context-attach.js +151 -0
- package/dist/ask-context-screen.d.ts +21 -0
- package/dist/ask-context-screen.js +49 -0
- package/dist/ask-context-switch.d.ts +31 -0
- package/dist/ask-context-switch.js +74 -0
- package/dist/ask-context.d.ts +84 -0
- package/dist/ask-context.js +172 -0
- package/dist/ask-pending.d.ts +47 -0
- package/dist/ask-pending.js +221 -0
- package/dist/ask-seal.d.ts +120 -0
- package/dist/ask-seal.js +179 -0
- package/dist/ask.d.ts +107 -0
- package/dist/ask.js +551 -0
- package/dist/blocked-prompt-seal.d.ts +35 -0
- package/dist/blocked-prompt-seal.js +89 -0
- package/dist/blocked-prompt.d.ts +57 -0
- package/dist/blocked-prompt.js +181 -0
- package/dist/channel.d.ts +67 -0
- package/dist/channel.js +136 -0
- package/dist/check-update.d.ts +28 -0
- package/dist/check-update.js +153 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +813 -0
- package/dist/codex-config.d.ts +24 -0
- package/dist/codex-config.js +169 -0
- package/dist/codex-transcript.d.ts +59 -0
- package/dist/codex-transcript.js +373 -0
- package/dist/command-refusal.d.ts +56 -0
- package/dist/command-refusal.js +127 -0
- package/dist/command-scan.d.ts +46 -0
- package/dist/command-scan.js +154 -0
- package/dist/command-seal.d.ts +57 -0
- package/dist/command-seal.js +88 -0
- package/dist/command-seq.d.ts +30 -0
- package/dist/command-seq.js +150 -0
- package/dist/config.d.ts +156 -0
- package/dist/config.js +392 -0
- package/dist/core-sections.d.ts +18 -0
- package/dist/core-sections.js +28 -0
- package/dist/crypto.d.ts +278 -0
- package/dist/crypto.js +698 -0
- package/dist/desktop-notify.d.ts +33 -0
- package/dist/desktop-notify.js +49 -0
- package/dist/device-directory.d.ts +36 -0
- package/dist/device-directory.js +97 -0
- package/dist/device-presence.d.ts +17 -0
- package/dist/device-presence.js +62 -0
- package/dist/downloads.d.ts +29 -0
- package/dist/downloads.js +106 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +28 -0
- package/dist/file-crypto.d.ts +94 -0
- package/dist/file-crypto.js +272 -0
- package/dist/file-view-budget.d.ts +15 -0
- package/dist/file-view-budget.js +34 -0
- package/dist/file-view-switch.d.ts +28 -0
- package/dist/file-view-switch.js +122 -0
- package/dist/file-view.d.ts +108 -0
- package/dist/file-view.js +327 -0
- package/dist/gate.d.ts +141 -0
- package/dist/gate.js +336 -0
- package/dist/gemini-transcript.d.ts +32 -0
- package/dist/gemini-transcript.js +189 -0
- package/dist/http-failure.d.ts +98 -0
- package/dist/http-failure.js +349 -0
- package/dist/hwip-core.generated.d.ts +7 -0
- package/dist/hwip-core.generated.js +14 -0
- package/dist/hwip-hook.d.ts +77 -0
- package/dist/hwip-hook.js +340 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +14 -0
- package/dist/input-sequencer.d.ts +65 -0
- package/dist/input-sequencer.js +142 -0
- package/dist/insecure-url.d.ts +16 -0
- package/dist/insecure-url.js +76 -0
- package/dist/installer.d.ts +96 -0
- package/dist/installer.js +850 -0
- package/dist/inventory-offload.d.ts +49 -0
- package/dist/inventory-offload.js +209 -0
- package/dist/inventory-worker.d.ts +2 -0
- package/dist/inventory-worker.js +27 -0
- package/dist/jsonc-doc.d.ts +106 -0
- package/dist/jsonc-doc.js +354 -0
- package/dist/keep-awake.d.ts +32 -0
- package/dist/keep-awake.js +46 -0
- package/dist/key-changes.d.ts +48 -0
- package/dist/key-changes.js +140 -0
- package/dist/lan-auth.d.ts +140 -0
- package/dist/lan-auth.js +217 -0
- package/dist/lan-endpoint.d.ts +41 -0
- package/dist/lan-endpoint.js +115 -0
- package/dist/lan-receiver.d.ts +122 -0
- package/dist/lan-receiver.js +510 -0
- package/dist/lan-sender.d.ts +76 -0
- package/dist/lan-sender.js +184 -0
- package/dist/lan-transfer.d.ts +36 -0
- package/dist/lan-transfer.js +54 -0
- package/dist/listener-device-id.d.ts +20 -0
- package/dist/listener-device-id.js +133 -0
- package/dist/listener-log.d.ts +4 -0
- package/dist/listener-log.js +23 -0
- package/dist/listener-process.d.ts +200 -0
- package/dist/listener-process.js +470 -0
- package/dist/listener-service.d.ts +225 -0
- package/dist/listener-service.js +682 -0
- package/dist/listener-worktree-cleanup.d.ts +27 -0
- package/dist/listener-worktree-cleanup.js +62 -0
- package/dist/listener.d.ts +1325 -0
- package/dist/listener.js +5680 -0
- package/dist/login-address.d.ts +25 -0
- package/dist/login-address.js +97 -0
- package/dist/login-page.d.ts +29 -0
- package/dist/login-page.js +93 -0
- package/dist/login.d.ts +98 -0
- package/dist/login.js +388 -0
- package/dist/mcp-command.d.ts +45 -0
- package/dist/mcp-command.js +50 -0
- package/dist/mcp.d.ts +19 -0
- package/dist/mcp.js +29 -0
- package/dist/node-support.d.ts +19 -0
- package/dist/node-support.js +38 -0
- package/dist/notify-failure.d.ts +57 -0
- package/dist/notify-failure.js +150 -0
- package/dist/opencode-transcript.d.ts +139 -0
- package/dist/opencode-transcript.js +390 -0
- package/dist/optional-features.d.ts +6 -0
- package/dist/optional-features.js +19 -0
- package/dist/pane-fit.d.ts +40 -0
- package/dist/pane-fit.js +119 -0
- package/dist/peer-key.d.ts +33 -0
- package/dist/peer-key.js +34 -0
- package/dist/pi-transcript.d.ts +26 -0
- package/dist/pi-transcript.js +255 -0
- package/dist/presence.d.ts +14 -0
- package/dist/presence.js +124 -0
- package/dist/private-files.d.ts +51 -0
- package/dist/private-files.js +218 -0
- package/dist/project-switch.d.ts +19 -0
- package/dist/project-switch.js +60 -0
- package/dist/redact.d.ts +10 -0
- package/dist/redact.js +21 -0
- package/dist/remote-agents.d.ts +410 -0
- package/dist/remote-agents.js +1218 -0
- package/dist/remote-hook.d.ts +12 -0
- package/dist/remote-hook.js +196 -0
- package/dist/replace-file.d.ts +50 -0
- package/dist/replace-file.js +328 -0
- package/dist/schedule-command.d.ts +35 -0
- package/dist/schedule-command.js +260 -0
- package/dist/schedule-launch.d.ts +15 -0
- package/dist/schedule-launch.js +24 -0
- package/dist/schedule-ready.d.ts +44 -0
- package/dist/schedule-ready.js +71 -0
- package/dist/schedule-remote.d.ts +77 -0
- package/dist/schedule-remote.js +167 -0
- package/dist/schedule-runner.d.ts +89 -0
- package/dist/schedule-runner.js +452 -0
- package/dist/schedule.d.ts +149 -0
- package/dist/schedule.js +428 -0
- package/dist/secret-mask.d.ts +29 -0
- package/dist/secret-mask.js +245 -0
- package/dist/self-register.d.ts +45 -0
- package/dist/self-register.js +67 -0
- package/dist/send.d.ts +56 -0
- package/dist/send.js +104 -0
- package/dist/session-diff.d.ts +161 -0
- package/dist/session-diff.js +445 -0
- package/dist/session-registry.d.ts +143 -0
- package/dist/session-registry.js +216 -0
- package/dist/sessions-report.d.ts +59 -0
- package/dist/sessions-report.js +99 -0
- package/dist/shell-audit.d.ts +34 -0
- package/dist/shell-audit.js +47 -0
- package/dist/subagent-transcripts.d.ts +167 -0
- package/dist/subagent-transcripts.js +437 -0
- package/dist/subscriber-trust.d.ts +128 -0
- package/dist/subscriber-trust.js +397 -0
- package/dist/templates.d.ts +105 -0
- package/dist/templates.js +871 -0
- package/dist/tmux-install.d.ts +44 -0
- package/dist/tmux-install.js +65 -0
- package/dist/tmux-liveness.d.ts +45 -0
- package/dist/tmux-liveness.js +71 -0
- package/dist/tmux-pane.d.ts +55 -0
- package/dist/tmux-pane.js +126 -0
- package/dist/tmux-socket.d.ts +20 -0
- package/dist/tmux-socket.js +292 -0
- package/dist/todo-fold.d.ts +31 -0
- package/dist/todo-fold.js +102 -0
- package/dist/transcript-tail.d.ts +312 -0
- package/dist/transcript-tail.js +718 -0
- package/dist/trust-command.d.ts +49 -0
- package/dist/trust-command.js +200 -0
- package/dist/trust-lock.d.ts +26 -0
- package/dist/trust-lock.js +94 -0
- package/dist/trust-pins.d.ts +37 -0
- package/dist/trust-pins.js +82 -0
- package/dist/turn-recorder-wire.d.ts +70 -0
- package/dist/turn-recorder-wire.js +165 -0
- package/dist/turn-recorder.d.ts +190 -0
- package/dist/turn-recorder.js +695 -0
- package/dist/turn-ring.d.ts +93 -0
- package/dist/turn-ring.js +418 -0
- package/dist/turn-watch.d.ts +177 -0
- package/dist/turn-watch.js +630 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.js +2 -0
- package/dist/uninstall.d.ts +55 -0
- package/dist/uninstall.js +507 -0
- package/dist/usage.d.ts +17 -0
- package/dist/usage.js +421 -0
- package/dist/verify.d.ts +47 -0
- package/dist/verify.js +396 -0
- package/dist/worktree.d.ts +144 -0
- package/dist/worktree.js +310 -0
- package/dist/wrapper.d.ts +254 -0
- package/dist/wrapper.js +704 -0
- package/dist/ws-url.d.ts +109 -0
- package/dist/ws-url.js +202 -0
- package/package.json +78 -10
- package/bin/hwip.js +0 -3
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-device encryption for the Hook SDK — self-contained ECDH P-256 +
|
|
3
|
+
* AES-256-GCM. Mirrors @hwip/crypto API but bundled inline (no external
|
|
4
|
+
* dependency). Uses Web Crypto API via node:crypto webcrypto, imported rather
|
|
5
|
+
* than read off the `crypto` global.
|
|
6
|
+
*
|
|
7
|
+
* How it works (ADR-0007):
|
|
8
|
+
*
|
|
9
|
+
* This host holds its own ECDH keypair in ~/.hwip/device-keys.json. The
|
|
10
|
+
* private half is generated here and never leaves — the server only ever
|
|
11
|
+
* sees public keys. A push is encrypted once with a random AES key, and
|
|
12
|
+
* that key is wrapped separately for each of the user's registered devices
|
|
13
|
+
* using ECDH(this host, that device). Same keypair the stream frames below
|
|
14
|
+
* already used; push and file bodies now share it.
|
|
15
|
+
*
|
|
16
|
+
* What it does not give you:
|
|
17
|
+
* • Forward secrecy — the ECDH secret for a given (sender, device) pair is
|
|
18
|
+
* static, so a compromise of either private key retroactively opens every
|
|
19
|
+
* push wrapped for that pair.
|
|
20
|
+
* • Authenticity beyond the key pairing — nothing signs `senderPublicKey`.
|
|
21
|
+
*
|
|
22
|
+
* Superseded scheme: a single account-wide keypair whose private half the
|
|
23
|
+
* backend escrowed so it could sync to new devices. Key escrow was removed
|
|
24
|
+
* server-side and `GET /users/me/keys` has returned a public
|
|
25
|
+
* key only ever since. This client used to react by generating a fresh
|
|
26
|
+
* account keypair and PUTting it back — which overwrote the account public
|
|
27
|
+
* key and encrypted to a key no device held. Both that upload path and the
|
|
28
|
+
* account keypair are gone.
|
|
29
|
+
*/
|
|
30
|
+
/** One target device, as returned by `GET /devices`. */
|
|
31
|
+
export interface DeviceRecipient {
|
|
32
|
+
deviceId: string;
|
|
33
|
+
/** Base64 SPKI of that device's per-device public key. */
|
|
34
|
+
publicKey: string;
|
|
35
|
+
}
|
|
36
|
+
/** deviceId → JSON `{ encryptedKey, keyIv }`, the wire shape the clients parse. */
|
|
37
|
+
export type DeviceKeyMap = Record<string, string>;
|
|
38
|
+
/**
|
|
39
|
+
* Keep only devices this host can encrypt for: a device without a public key
|
|
40
|
+
* has never run a build that registers one, and wrapping for it produces a push
|
|
41
|
+
* it cannot open.
|
|
42
|
+
*/
|
|
43
|
+
export declare const selectRecipients: (devices: {
|
|
44
|
+
deviceId: string;
|
|
45
|
+
publicKey?: string;
|
|
46
|
+
}[]) => DeviceRecipient[];
|
|
47
|
+
/** A device a person reads pushes on: the iOS or Android app. A push or question nobody can read on a phone is not sent. */
|
|
48
|
+
export declare const isAppDevice: (d: {
|
|
49
|
+
type?: string;
|
|
50
|
+
}) => boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Encrypt a push body for the given recipient devices.
|
|
53
|
+
*
|
|
54
|
+
* Returns the wire fields the API expects: `body` carries the ciphertext and
|
|
55
|
+
* IV, `deviceKeyMap` the per-device wrapped keys, `senderPublicKey` the half
|
|
56
|
+
* recipients need to derive the same secret back.
|
|
57
|
+
*/
|
|
58
|
+
export declare const encryptPushBodyForDevices: (input: PushBodyInput, recipients: DeviceRecipient[]) => Promise<{
|
|
59
|
+
body: string;
|
|
60
|
+
deviceKeyMap: DeviceKeyMap;
|
|
61
|
+
senderPublicKey: string;
|
|
62
|
+
isEncrypted: true;
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* Encrypt file content for the given recipient devices.
|
|
66
|
+
*/
|
|
67
|
+
export declare const encryptFileForDevices: (content: string | Buffer, recipients: DeviceRecipient[]) => Promise<{
|
|
68
|
+
ciphertext: Buffer;
|
|
69
|
+
iv: string;
|
|
70
|
+
deviceKeyMap: DeviceKeyMap;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Load-or-create the per-device keypair. Local-only — no server round-trip,
|
|
74
|
+
* no upload. Safe to call concurrently (dedupes to one init). Returns the
|
|
75
|
+
* exported public key (Base64 SPKI).
|
|
76
|
+
*/
|
|
77
|
+
export declare const initDeviceCrypto: () => Promise<string>;
|
|
78
|
+
export declare const getDevicePublicKey: () => string | null;
|
|
79
|
+
/**
|
|
80
|
+
* Raw ECDH secret between this device and `peerPublicKeyRaw` (Base64
|
|
81
|
+
* SPKI) — the 32-byte x-coordinate WebCrypto's `deriveBits` yields for
|
|
82
|
+
* P-256. Input to the local-transfer MAC key (lan-auth.ts `deriveLanKey`);
|
|
83
|
+
* never used as a key by itself. Requires initDeviceCrypto().
|
|
84
|
+
*/
|
|
85
|
+
export declare const deriveLanSharedSecret: (peerPublicKeyRaw: string) => Promise<Buffer>;
|
|
86
|
+
export declare const unwrapDeviceKey: (entryJson: string, senderPublicKeyRaw: string) => Promise<Buffer>;
|
|
87
|
+
/**
|
|
88
|
+
* The label a sealed REST command carries inside its body (M5 D8): which
|
|
89
|
+
* session on which machine it is for, and a number that only grows per
|
|
90
|
+
* sender. A sealed body without one is not a command. `from` is the id of the
|
|
91
|
+
* computer that sent it, when it names itself.
|
|
92
|
+
*/
|
|
93
|
+
export interface SealedCommandLabel {
|
|
94
|
+
n: number;
|
|
95
|
+
session: string;
|
|
96
|
+
device: string;
|
|
97
|
+
from?: string;
|
|
98
|
+
}
|
|
99
|
+
/** One button of a sealed question: `id` and `style` also reach the server in the clear, `label` never does. */
|
|
100
|
+
export interface SealedAskAction {
|
|
101
|
+
id: string;
|
|
102
|
+
label: string;
|
|
103
|
+
style?: string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The label a sealed question carries inside its body: the asker's own random
|
|
107
|
+
* `id` (the answer must echo it, so a relay cannot pass an old question's answer
|
|
108
|
+
* off as a new one's), the Machine Device that asks, and the wording the server
|
|
109
|
+
* must not read.
|
|
110
|
+
*/
|
|
111
|
+
export interface SealedAskLabel {
|
|
112
|
+
id: string;
|
|
113
|
+
device: string;
|
|
114
|
+
actions?: SealedAskAction[];
|
|
115
|
+
placeholder?: string;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The summary a sealed question may carry in its body under `context` (F3): what the asking session has changed
|
|
119
|
+
* and how much of its screen the original holds. It is a new key of the same plaintext JSON — the envelope and
|
|
120
|
+
* the schema are unchanged, and a reader that does not know the key drops it with the rest of the keys it does
|
|
121
|
+
* not read. The original (the masked diff and screen) is never in the body: it is the question's sealed attachment.
|
|
122
|
+
*/
|
|
123
|
+
export interface SealedAskContext {
|
|
124
|
+
diff: 'ok' | 'no_repo' | 'failed';
|
|
125
|
+
files: number;
|
|
126
|
+
added: number;
|
|
127
|
+
removed: number;
|
|
128
|
+
listed: {
|
|
129
|
+
path: string;
|
|
130
|
+
status: 'M' | 'A' | 'D' | '?';
|
|
131
|
+
added: number;
|
|
132
|
+
removed: number;
|
|
133
|
+
binary?: true;
|
|
134
|
+
}[];
|
|
135
|
+
moreFiles: number;
|
|
136
|
+
screenLines: number;
|
|
137
|
+
masked: number;
|
|
138
|
+
cut: {
|
|
139
|
+
diff: boolean;
|
|
140
|
+
screen: boolean;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/** The label a sealed answer carries: which question it answers and what was chosen. */
|
|
144
|
+
export interface SealedAnswerLabel {
|
|
145
|
+
ask: string;
|
|
146
|
+
actionId?: string;
|
|
147
|
+
exit?: true;
|
|
148
|
+
}
|
|
149
|
+
/** What `encryptPushBodyForDevices` seals. Keys left out are left out of the plaintext JSON. */
|
|
150
|
+
export interface PushBodyInput {
|
|
151
|
+
title?: string;
|
|
152
|
+
body?: string;
|
|
153
|
+
url?: string;
|
|
154
|
+
cmd?: SealedCommandLabel;
|
|
155
|
+
ask?: SealedAskLabel;
|
|
156
|
+
answer?: SealedAnswerLabel;
|
|
157
|
+
files?: SealedFileMeta[];
|
|
158
|
+
/**
|
|
159
|
+
* Named keys (the blocked prompt's answer) inside a sealed command. Read
|
|
160
|
+
* back only when every entry is a string; the listener allowlists the names.
|
|
161
|
+
*/
|
|
162
|
+
keys?: string[];
|
|
163
|
+
/** The blocked prompt id the keys answer, inside a sealed command. */
|
|
164
|
+
ifPrompt?: string;
|
|
165
|
+
context?: SealedAskContext;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* One sealed attachment as the sealed body names it (M5): its IV — fresh per
|
|
169
|
+
* file, so an attachment from another message does not match — and what it
|
|
170
|
+
* really is. The list binds the attachments to the message, in order.
|
|
171
|
+
* `chunk` is there for a file sealed in chunks (`file-chunk-v1`): the plain
|
|
172
|
+
* bytes in each piece, and `iv` is then the 7-byte prefix of the piece nonces.
|
|
173
|
+
*/
|
|
174
|
+
export interface SealedFileMeta {
|
|
175
|
+
iv: string;
|
|
176
|
+
name: string;
|
|
177
|
+
type: string;
|
|
178
|
+
size: number;
|
|
179
|
+
chunk?: number;
|
|
180
|
+
}
|
|
181
|
+
/** The `code` of the errors above that a shorter choice list fixes. */
|
|
182
|
+
export declare const ASK_CHOICES_CODE = "ask-choices-over-limits";
|
|
183
|
+
/**
|
|
184
|
+
* Decrypt a push body sealed by `encryptPushBodyForDevices` (any client's
|
|
185
|
+
* twin of it) for this device: `body` is the JSON `{ ciphertext, iv }`
|
|
186
|
+
* envelope, the message key comes out of this device's `deviceKeyMap` slot.
|
|
187
|
+
* Returns the `{ title, body, url }` the sender put in, the `cmd` label of a
|
|
188
|
+
* sealed command, the `ask` / `answer` label of a sealed question / answer and
|
|
189
|
+
* the `files` list, the sealed `keys` / `ifPrompt` of a blocked-prompt answer,
|
|
190
|
+
* and the `context` summary — each only when well formed. `context` is read from any body;
|
|
191
|
+
* whether it belongs there (a question) is the caller's to decide.
|
|
192
|
+
*/
|
|
193
|
+
export declare const decryptPushBodyForDevice: (body: string, entryJson: string, senderPublicKeyRaw: string) => Promise<{
|
|
194
|
+
title?: string;
|
|
195
|
+
body?: string;
|
|
196
|
+
url?: string;
|
|
197
|
+
cmd?: SealedCommandLabel;
|
|
198
|
+
ask?: SealedAskLabel;
|
|
199
|
+
answer?: SealedAnswerLabel;
|
|
200
|
+
files?: SealedFileMeta[];
|
|
201
|
+
keys?: string[];
|
|
202
|
+
ifPrompt?: string;
|
|
203
|
+
/** A schedule request inside a sealed command (F8); its fields are the listener's to check. */
|
|
204
|
+
schedule?: Record<string, unknown>;
|
|
205
|
+
context?: SealedAskContext;
|
|
206
|
+
}>;
|
|
207
|
+
export type SealPurpose = 'stream.frame' | 'stream.input' | 'stream.alive' | 'stream.started' | 'screen.snapshot' | 'screen.history' | 'session.diff' | 'schedule.list' | 'turn.batch';
|
|
208
|
+
export interface SealedV2 {
|
|
209
|
+
v: 2;
|
|
210
|
+
/** Base64, 32 bytes — the HKDF salt, fresh per message. */
|
|
211
|
+
salt: string;
|
|
212
|
+
/** Base64, 12 bytes. */
|
|
213
|
+
iv: string;
|
|
214
|
+
/** Base64 ciphertext ‖ 16-byte tag. */
|
|
215
|
+
ciphertext: string;
|
|
216
|
+
/** Base64 SPKI of the sealing device. Covered by the seal (AAD). */
|
|
217
|
+
senderPublicKey: string;
|
|
218
|
+
}
|
|
219
|
+
/** Every field of a v2 envelope is relay JSON: check the shape before any of
|
|
220
|
+
* it reaches WebCrypto, so a malformed one is a refusal and not a throw from
|
|
221
|
+
* inside a Base64 decode. */
|
|
222
|
+
export declare const isSealedV2: (value: unknown) => value is SealedV2;
|
|
223
|
+
/**
|
|
224
|
+
* The X9.63 point of a device public key, or null when the string is not
|
|
225
|
+
* spelled as one. Only the spelling is checked: whether the 65 bytes are a
|
|
226
|
+
* point on the curve is left to the key import that follows, which is where
|
|
227
|
+
* `sealV2` and `openV2` reject one that is not.
|
|
228
|
+
*
|
|
229
|
+
* A device key has exactly one spelling here: standard padded Base64 of the
|
|
230
|
+
* 91-byte SPKI with an uncompressed point — what WebCrypto's
|
|
231
|
+
* `exportKey('spki')` and the app's CryptoKit `derRepresentation` both write.
|
|
232
|
+
* The same key spelled another way (a compressed point, unpadded Base64) is
|
|
233
|
+
* refused rather than normalised. With one spelling, two keys are the same
|
|
234
|
+
* exactly when their strings are, here and in the app, which cannot read the
|
|
235
|
+
* compressed form at all.
|
|
236
|
+
*/
|
|
237
|
+
export declare const publicKeyPoint: (spkiBase64: string) => Buffer | null;
|
|
238
|
+
/**
|
|
239
|
+
* Who a sealed message is from, as far as a replay check can tell: the x
|
|
240
|
+
* coordinate of the sender's point, in hex (null for a string that is not a
|
|
241
|
+
* device key). A sealed push opens from the ECDH x coordinate alone — the
|
|
242
|
+
* secret is the same for a point and its mirror (x, p − y) — so a relay can
|
|
243
|
+
* hand the same box to the listener under the mirrored key without the
|
|
244
|
+
* phone's secret. The string of that key is another one, the sender is not.
|
|
245
|
+
* Pins and fingerprints still compare the whole key; only the question "have
|
|
246
|
+
* I taken this number from this sender" asks for x.
|
|
247
|
+
*/
|
|
248
|
+
export declare const publicKeySender: (spkiBase64: string) => string | null;
|
|
249
|
+
/** Whether two strings are the same device public key. A string that is not
|
|
250
|
+
* in the one spelling `publicKeyPoint` takes equals nothing, itself included. */
|
|
251
|
+
export declare const samePublicKey: (a: string, b: string) => boolean;
|
|
252
|
+
/**
|
|
253
|
+
* A device public key as something two people can compare: the first 16 bytes
|
|
254
|
+
* of SHA-256 over its X9.63 point, as eight groups of four hex digits. The app
|
|
255
|
+
* prints the same string for the same key (`Envelope.fingerprint`), which is
|
|
256
|
+
* the point — `hwip trust` on this side, the device screen on that one. null
|
|
257
|
+
* for a string that is not a device key.
|
|
258
|
+
*/
|
|
259
|
+
export declare const keyFingerprint: (spkiBase64: string) => string | null;
|
|
260
|
+
/**
|
|
261
|
+
* Seal `plaintext` for one recipient device, for one purpose. Requires
|
|
262
|
+
* initDeviceCrypto().
|
|
263
|
+
*/
|
|
264
|
+
export declare const sealV2: (purpose: SealPurpose, plaintext: string, recipientPublicKey: string, context?: string) => Promise<SealedV2>;
|
|
265
|
+
/**
|
|
266
|
+
* Open a v2 envelope addressed to this device.
|
|
267
|
+
*
|
|
268
|
+
* Rejects rather than returning null, like every open here: a throw means the
|
|
269
|
+
* envelope was sealed by another key than `expectedSender`, for another
|
|
270
|
+
* device, purpose or context, was tampered with, or is not a v2 envelope.
|
|
271
|
+
*
|
|
272
|
+
* `expectedSender` is not optional: opening alone proves only that the sender
|
|
273
|
+
* holds the private half of `senderPublicKey`, and anyone can mint a keypair.
|
|
274
|
+
* Every caller knows who it is talking to; naming that key here is what turns
|
|
275
|
+
* "it opened" into "the peer sent it". Requires initDeviceCrypto().
|
|
276
|
+
*/
|
|
277
|
+
export declare const openV2: (purpose: SealPurpose, envelope: SealedV2, expectedSender: string, context?: string) => Promise<string>;
|
|
278
|
+
//# sourceMappingURL=crypto.d.ts.map
|