@toon-protocol/client-mcp 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/README.md +302 -0
- package/dist/anon-proxy-W3KMM7GU-FN7ZJY7P.js +25 -0
- package/dist/anon-proxy-W3KMM7GU-FN7ZJY7P.js.map +1 -0
- package/dist/chunk-32QD72IL.js +83 -0
- package/dist/chunk-32QD72IL.js.map +1 -0
- package/dist/chunk-3NAWISI5.js +2245 -0
- package/dist/chunk-3NAWISI5.js.map +1 -0
- package/dist/chunk-5KFXUT5Q.js +11321 -0
- package/dist/chunk-5KFXUT5Q.js.map +1 -0
- package/dist/chunk-F22GNSF6.js +12 -0
- package/dist/chunk-F22GNSF6.js.map +1 -0
- package/dist/chunk-FSS45ZX3.js +2633 -0
- package/dist/chunk-FSS45ZX3.js.map +1 -0
- package/dist/chunk-LR7W2ISE.js +657 -0
- package/dist/chunk-LR7W2ISE.js.map +1 -0
- package/dist/chunk-SKQTKZIH.js +278 -0
- package/dist/chunk-SKQTKZIH.js.map +1 -0
- package/dist/chunk-VA7XC4FD.js +185 -0
- package/dist/chunk-VA7XC4FD.js.map +1 -0
- package/dist/chunk-ZQKYZJWT.js +359 -0
- package/dist/chunk-ZQKYZJWT.js.map +1 -0
- package/dist/daemon.d.ts +1 -0
- package/dist/daemon.js +141 -0
- package/dist/daemon.js.map +1 -0
- package/dist/ed25519-2QVPINLS.js +27 -0
- package/dist/ed25519-2QVPINLS.js.map +1 -0
- package/dist/gateway-QOK47RKS-SEGTXBR3.js +16 -0
- package/dist/gateway-QOK47RKS-SEGTXBR3.js.map +1 -0
- package/dist/hmac-26UC6YKX.js +12 -0
- package/dist/hmac-26UC6YKX.js.map +1 -0
- package/dist/index.d.ts +965 -0
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +1 -0
- package/dist/mcp.js +81 -0
- package/dist/mcp.js.map +1 -0
- package/dist/sha512-WYC446ZM.js +34 -0
- package/dist/sha512-WYC446ZM.js.map +1 -0
- package/dist/socks5-WTJBYGME-6COK4LXW.js +139 -0
- package/dist/socks5-WTJBYGME-6COK4LXW.js.map +1 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# @toon-protocol/client-mcp
|
|
2
|
+
|
|
3
|
+
Let a Claude agent — **Claude Desktop or Claude Code** — act as a full TOON
|
|
4
|
+
Protocol client: **pay-to-write** publishing, **free** reads/subscriptions,
|
|
5
|
+
payment-channel/balance management, and mill swaps.
|
|
6
|
+
|
|
7
|
+
The agent surface is an **MCP server** — bin **`toon-mcp`**, which registers
|
|
8
|
+
with the host under the server name **`toon-client`** (this is the name that
|
|
9
|
+
appears in Claude's MCP server list and in the `initialize` handshake;
|
|
10
|
+
`mcpServers.toon` in config is just your local alias). The two long-lived
|
|
11
|
+
connections that can't live in an ephemeral agent session — a **BTP** session
|
|
12
|
+
(paid writes via the connector/apex, optionally over a managed `.anyone`
|
|
13
|
+
SOCKS5h proxy) and a **town-relay Nostr-WS** subscription (free reads) — live in
|
|
14
|
+
an **always-on detached daemon** (`toon-clientd`). The MCP server is a thin
|
|
15
|
+
stdio proxy that auto-spawns the daemon and never holds chain keys.
|
|
16
|
+
|
|
17
|
+
| | Name |
|
|
18
|
+
|---|---|
|
|
19
|
+
| npm package | `@toon-protocol/client-mcp` |
|
|
20
|
+
| MCP server name (handshake) | `toon-client` |
|
|
21
|
+
| MCP server bin | `toon-mcp` |
|
|
22
|
+
| Daemon bin | `toon-clientd` |
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
Claude (Desktop / Code)
|
|
26
|
+
│ stdio (MCP)
|
|
27
|
+
▼
|
|
28
|
+
toon-mcp ──HTTP──▶ toon-clientd (detached, always-on)
|
|
29
|
+
├─ ToonClient: BTP session + payment channels + signer
|
|
30
|
+
└─ RelaySubscription: persistent town-relay Nostr-WS
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Architecture
|
|
34
|
+
|
|
35
|
+
| Layer | Bin / module | Responsibility |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| **Daemon** | `toon-clientd` | Owns one `ToonClient` (BTP + managed anon + channels + mnemonic keystore + network targeting) **plus** a persistent town-relay subscription. Loopback HTTP control API, single-instance PID lock, channel nonce-watermark persistence, graceful shutdown. |
|
|
38
|
+
| **MCP server** | `toon-mcp` | `@modelcontextprotocol/sdk` stdio server. Maps tools → daemon HTTP; auto-spawns the daemon detached if down; reports "bootstrapping — retry" while anon boots; holds no keys. |
|
|
39
|
+
| **Skill** | `.claude/skills/toon-client/` | Teaches the agent pay-to-write / free-read / settlement semantics. |
|
|
40
|
+
|
|
41
|
+
## Tools
|
|
42
|
+
|
|
43
|
+
The `toon-client` MCP server exposes **8 tools**:
|
|
44
|
+
|
|
45
|
+
| MCP tool | Daemon endpoint | Backing |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `toon_status` | `GET /status` | ready/bootstrapping, transport, relay health, per-chain settlement, active chain |
|
|
48
|
+
| `toon_identity` | `GET /status` | Nostr pubkey + EVM/Solana/Mina addresses (no keys) |
|
|
49
|
+
| `toon_publish(event,{destination?,fee?})` | `POST /publish` | `signBalanceProof` + `publishEvent` (paid write) |
|
|
50
|
+
| `toon_subscribe(filters,{subId?})` | `POST /subscribe` | register a persistent free-read subscription |
|
|
51
|
+
| `toon_read({subId?,cursor?,limit?})` | `GET /events` | drain buffered events by cursor (free) |
|
|
52
|
+
| `toon_open_channel({destination?})` | `POST /channels` | `openChannel` (pre-open / fetch a channel) |
|
|
53
|
+
| `toon_channels` | `GET /channels` | `getTrackedChannels` + nonce watermark + cumulative spend |
|
|
54
|
+
| `toon_swap(destination,amount,{toonData?})` | `POST /swap` | `sendSwapPacket` (mill swap) |
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pnpm add -g @toon-protocol/client-mcp # installs both bins
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This installs two bins: `toon-clientd` and `toon-mcp`. To run a bin straight
|
|
63
|
+
from npm without a global install, name it explicitly (the package name is not a
|
|
64
|
+
bin, so plain `npx @toon-protocol/client-mcp` fails):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npx -y -p @toon-protocol/client-mcp toon-mcp # MCP stdio server
|
|
68
|
+
npx -y -p @toon-protocol/client-mcp toon-clientd # daemon
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## First run (zero-config onboarding)
|
|
72
|
+
|
|
73
|
+
On the **first** `toon-clientd run`/`start` (including the auto-spawn from
|
|
74
|
+
`toon-mcp`), the daemon onboards a brand-new user with no manual setup:
|
|
75
|
+
|
|
76
|
+
- **Identity** — if no mnemonic is configured, it generates a fresh BIP-39
|
|
77
|
+
mnemonic, encrypts it to `~/.toon-client/keystore.json`, records
|
|
78
|
+
`keystorePath` in `config.json`, and prints the seed phrase + derived
|
|
79
|
+
addresses **once** (back it up). The keystore is encrypted with
|
|
80
|
+
`TOON_CLIENT_KEYSTORE_PASSWORD` when set, otherwise a default password so the
|
|
81
|
+
identity reloads on every restart with **no env var required**.
|
|
82
|
+
- **Transport scaffolding** — it writes a starter `~/.toon-client/config.json`
|
|
83
|
+
carrying the `btpUrl`/`relayUrl`/`managedAnonProxy` knobs plus a `_help`
|
|
84
|
+
block documenting direct-vs-`.anyone` selection.
|
|
85
|
+
|
|
86
|
+
The one thing you must supply is the apex you pay: set **`btpUrl`** (and usually
|
|
87
|
+
`relayUrl`) in the scaffolded config, then publish. Everything below is for
|
|
88
|
+
overriding those auto-provisioned defaults.
|
|
89
|
+
|
|
90
|
+
## Configure the daemon
|
|
91
|
+
|
|
92
|
+
The daemon reads `~/.toon-client/config.json` (override with `TOON_CLIENT_CONFIG`).
|
|
93
|
+
The **mnemonic is never stored in plaintext by default** — it is auto-generated
|
|
94
|
+
into an encrypted keystore (scrypt + AES-256-GCM, mode 0600) on first run, or you
|
|
95
|
+
can supply your own via env or an imported keystore.
|
|
96
|
+
|
|
97
|
+
```jsonc
|
|
98
|
+
// ~/.toon-client/config.json
|
|
99
|
+
{
|
|
100
|
+
"network": "testnet", // settlement presets (#209)
|
|
101
|
+
"keystorePath": "~/.toon-client/keystore.json",
|
|
102
|
+
"btpUrl": "ws://<apex-host>.anyone:3000/btp",
|
|
103
|
+
"relayUrl": "wss://<relay-host>.anyone/", // free reads
|
|
104
|
+
"destination": "g.townhouse.town",
|
|
105
|
+
"feePerEvent": "1",
|
|
106
|
+
"httpPort": 8787,
|
|
107
|
+
// HS / direct-apex mode: bootstrap finds 0 peers, so name the apex's
|
|
108
|
+
// settlement address directly (mirrors the docker entrypoint):
|
|
109
|
+
"apex": {
|
|
110
|
+
"destination": "g.townhouse.town",
|
|
111
|
+
"peerId": "town",
|
|
112
|
+
"chain": "evm",
|
|
113
|
+
"chainKey": "evm:base:84532",
|
|
114
|
+
"chainId": 84532,
|
|
115
|
+
"settlementAddress": "0x<apex-receive-addr>",
|
|
116
|
+
"tokenAddress": "0x<usdc>",
|
|
117
|
+
"tokenNetwork": "0x<token-network>"
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Environment overrides: `TOON_CLIENT_MNEMONIC`, `TOON_CLIENT_KEYSTORE_PASSWORD`,
|
|
123
|
+
`TOON_CLIENT_BTP_URL`, `TOON_CLIENT_RELAY_URL`, `TOON_CLIENT_SOCKS`,
|
|
124
|
+
`TOON_CLIENT_HTTP_PORT`, `TOON_CLIENT_NETWORK`, `TOON_CLIENT_HOME`.
|
|
125
|
+
|
|
126
|
+
**Transport is inferred from the URLs — no separate "direct vs hidden-service"
|
|
127
|
+
switch.** The daemon parses the host of each URL independently:
|
|
128
|
+
|
|
129
|
+
- `btpUrl`/`relayUrl` on a normal host (`ws://1.2.3.4:3000/btp`, `wss://…`) →
|
|
130
|
+
**direct**, dialed as-is.
|
|
131
|
+
- `btpUrl` on a `.anyone` host → the ToonClient auto-starts a managed `anon`
|
|
132
|
+
SOCKS5h proxy and routes paid writes (and reads) through it.
|
|
133
|
+
- `btpUrl` **direct** but `relayUrl` on a `.anyone` host → the daemon starts its
|
|
134
|
+
own managed `anon` proxy just for the free-read subscription; paid writes stay
|
|
135
|
+
direct. (Mixed transports — a direct apex with a hidden-service relay — work
|
|
136
|
+
out of the box.)
|
|
137
|
+
|
|
138
|
+
No explicit `socksProxy` is needed for any of these. Set `socksProxy` only to
|
|
139
|
+
point at your own external proxy, or `managedAnonProxy: false` to opt out of the
|
|
140
|
+
managed proxy entirely. The first bootstrap pays the anon warm-up cost (~30–90s)
|
|
141
|
+
**once** — the detached daemon then stays up. A read-proxy failure surfaces under
|
|
142
|
+
`relay.proxyError` in `toon_status` and never blocks direct paid writes.
|
|
143
|
+
|
|
144
|
+
### Create an encrypted keystore
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
TOON_CLIENT_MNEMONIC="word word ..." \
|
|
148
|
+
TOON_CLIENT_KEYSTORE_PASSWORD="…" \
|
|
149
|
+
node -e "import('@toon-protocol/client').then(m => m.importKeystore(process.env.HOME+'/.toon-client/keystore.json', process.env.TOON_CLIENT_MNEMONIC, process.env.TOON_CLIENT_KEYSTORE_PASSWORD))"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Daemon lifecycle (Claude Code only — it has a shell)
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
toon-clientd start # spawn detached, wait until reachable
|
|
156
|
+
toon-clientd status # print status JSON
|
|
157
|
+
toon-clientd stop # SIGTERM the locked PID
|
|
158
|
+
toon-clientd run # run in the foreground (what the detached spawn runs)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The MCP server auto-spawns the daemon, so `start` is optional.
|
|
162
|
+
|
|
163
|
+
## Register with Claude
|
|
164
|
+
|
|
165
|
+
### Claude Code
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
claude mcp add toon -- toon-mcp
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
…or add to `.mcp.json` in your project:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"mcpServers": {
|
|
176
|
+
"toon": { "command": "toon-mcp" }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Claude Desktop
|
|
182
|
+
|
|
183
|
+
Add to `claude_desktop_config.json`:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"mcpServers": {
|
|
188
|
+
"toon": {
|
|
189
|
+
"command": "toon-mcp",
|
|
190
|
+
"env": {
|
|
191
|
+
"TOON_CLIENT_KEYSTORE_PASSWORD": "…"
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Then restart Claude Desktop. The TOON tools appear in the tool list; the first
|
|
199
|
+
`toon_publish` after a cold start may report "bootstrapping — retry" while the
|
|
200
|
+
anon proxy + BTP session come up.
|
|
201
|
+
|
|
202
|
+
## Usage example
|
|
203
|
+
|
|
204
|
+
You don't call these tools by hand — the agent does, in response to plain
|
|
205
|
+
requests. A typical "post a note, then read it back" flow:
|
|
206
|
+
|
|
207
|
+
> **You:** Post a note to TOON saying "gm from my agent", then show me when it lands.
|
|
208
|
+
|
|
209
|
+
The agent runs:
|
|
210
|
+
|
|
211
|
+
1. **`toon_status`** → confirm the client is up.
|
|
212
|
+
```json
|
|
213
|
+
{ "ready": true, "bootstrapping": false, "settlementChain": "evm",
|
|
214
|
+
"relay": { "connected": true }, "identity": { "evmAddress": "0x99ed…" } }
|
|
215
|
+
```
|
|
216
|
+
(If it returns `bootstrapping: true` or a "retry shortly" message, wait ~30–90s
|
|
217
|
+
for the anon proxy + BTP session, then retry.)
|
|
218
|
+
|
|
219
|
+
2. **`toon_subscribe`** for its own author so it can read the note back:
|
|
220
|
+
```json
|
|
221
|
+
{ "filters": { "authors": ["<my-hex-pubkey>"], "kinds": [1] } }
|
|
222
|
+
→ { "subId": "sub-1" }
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
3. **`toon_publish`** the signed kind:1 event (the daemon signs the payment-channel
|
|
226
|
+
claim and forwards it over BTP):
|
|
227
|
+
```json
|
|
228
|
+
{ "event": { "kind": 1, "content": "gm from my agent", "id": "…", "sig": "…", … } }
|
|
229
|
+
→ { "eventId": "0d0c1f98…", "channelId": "0xc73a77…", "nonce": 7 }
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
4. **`toon_read`** until the event appears (free; cursor long-poll):
|
|
233
|
+
```json
|
|
234
|
+
{ "subId": "sub-1" }
|
|
235
|
+
→ { "events": [ { "id": "0d0c1f98…", "content": "gm from my agent", … } ],
|
|
236
|
+
"cursor": 12, "hasMore": false }
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
5. **`toon_channels`** to show what it cost:
|
|
240
|
+
```json
|
|
241
|
+
→ { "channels": [ { "channelId": "0xc73a77…", "nonce": 7, "cumulativeAmount": "7" } ] }
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Other common calls: **`toon_open_channel`** to pre-open a channel before a burst
|
|
245
|
+
of publishes, and **`toon_swap({ destination, amount })`** to pay a mill peer and
|
|
246
|
+
receive a target-chain claim.
|
|
247
|
+
|
|
248
|
+
> **CLI equivalent** (handy for scripting/debugging — the MCP tools map 1:1 to
|
|
249
|
+
> these daemon endpoints):
|
|
250
|
+
> ```bash
|
|
251
|
+
> toon-clientd start # boot the daemon
|
|
252
|
+
> curl -s localhost:8787/status | jq # toon_status
|
|
253
|
+
> curl -s -XPOST localhost:8787/subscribe \
|
|
254
|
+
> -H content-type:application/json \
|
|
255
|
+
> -d '{"filters":{"authors":["<hex>"],"kinds":[1]}}' # toon_subscribe
|
|
256
|
+
> curl -s -XPOST localhost:8787/publish \
|
|
257
|
+
> -H content-type:application/json \
|
|
258
|
+
> -d '{"event":{…signed kind:1…}}' # toon_publish
|
|
259
|
+
> curl -s 'localhost:8787/events?subId=sub-1' | jq # toon_read
|
|
260
|
+
> curl -s localhost:8787/channels | jq # toon_channels
|
|
261
|
+
> ```
|
|
262
|
+
|
|
263
|
+
## Security
|
|
264
|
+
|
|
265
|
+
- The daemon holds the mnemonic/keystore; the agent sees **only addresses and
|
|
266
|
+
results**, never private keys.
|
|
267
|
+
- A single-instance PID lock prevents two daemons from racing the channel nonce
|
|
268
|
+
watermark (which would corrupt the payment proof).
|
|
269
|
+
- The control plane binds `127.0.0.1` only (no auth layer — it never leaves
|
|
270
|
+
loopback).
|
|
271
|
+
|
|
272
|
+
## Tests
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
pnpm --filter @toon-protocol/client-mcp test # unit
|
|
276
|
+
RUN_LIVE_HS_E2E=1 …env… \
|
|
277
|
+
pnpm --filter @toon-protocol/client-mcp test:integration # gated live-HS round-trip
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The gated integration test boots the daemon against a live `.anyone` HS apex,
|
|
281
|
+
publishes a paid event, reads it back through the subscription, verifies the
|
|
282
|
+
channel nonce advanced, restarts the daemon, and confirms the nonce watermark
|
|
283
|
+
persisted. See `src/__integration__/`.
|
|
284
|
+
|
|
285
|
+
## Publishing
|
|
286
|
+
|
|
287
|
+
This package is **published to npm automatically by CI/CD**, in lockstep with the
|
|
288
|
+
repo's release tag (the same `vX.Y.Z` semantic-release cuts for
|
|
289
|
+
`@toon-protocol/townhouse`). On a release, `publish-townhouse-images.yml` builds
|
|
290
|
+
this package, sets its version to the tag, and runs
|
|
291
|
+
`pnpm --filter @toon-protocol/client-mcp publish --access public`.
|
|
292
|
+
|
|
293
|
+
It is **self-contained**: its `@toon-protocol/*` workspace deps (`client`, `core`)
|
|
294
|
+
are **bundled into `dist`** at build time (tsup `noExternal`), so the published
|
|
295
|
+
`package.json` carries **zero `@toon-protocol/*` runtime deps** — only npm
|
|
296
|
+
packages (`fastify`, `@modelcontextprotocol/sdk`, `nostr-tools`, `viem`, `ws`,
|
|
297
|
+
`@toon-format/toon`) plus optional chain libs (`o1js`, `mina-signer`,
|
|
298
|
+
`@solana/web3.js`, `socks-proxy-agent`) installed only when you use those chains.
|
|
299
|
+
A guard test (`src/package-structure.test.ts`) fails the build if a
|
|
300
|
+
`@toon-protocol/*` runtime dep ever leaks in.
|
|
301
|
+
|
|
302
|
+
To publish manually: `pnpm --filter @toon-protocol/client-mcp build && pnpm --filter @toon-protocol/client-mcp publish --access public`.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
ANON_ASSETS,
|
|
4
|
+
ANON_VERSION,
|
|
5
|
+
defaultCacheDir,
|
|
6
|
+
ensureAnonBinary,
|
|
7
|
+
renderTorrc,
|
|
8
|
+
selectAnonAsset,
|
|
9
|
+
startManagedAnonProxy,
|
|
10
|
+
tcpProbe,
|
|
11
|
+
waitForAnonSocks
|
|
12
|
+
} from "./chunk-SKQTKZIH.js";
|
|
13
|
+
import "./chunk-F22GNSF6.js";
|
|
14
|
+
export {
|
|
15
|
+
ANON_ASSETS,
|
|
16
|
+
ANON_VERSION,
|
|
17
|
+
defaultCacheDir,
|
|
18
|
+
ensureAnonBinary,
|
|
19
|
+
renderTorrc,
|
|
20
|
+
selectAnonAsset,
|
|
21
|
+
startManagedAnonProxy,
|
|
22
|
+
tcpProbe,
|
|
23
|
+
waitForAnonSocks
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=anon-proxy-W3KMM7GU-FN7ZJY7P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
Hash,
|
|
4
|
+
abytes,
|
|
5
|
+
aexists,
|
|
6
|
+
ahash,
|
|
7
|
+
clean,
|
|
8
|
+
toBytes
|
|
9
|
+
} from "./chunk-VA7XC4FD.js";
|
|
10
|
+
|
|
11
|
+
// ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/hmac.js
|
|
12
|
+
var HMAC = class extends Hash {
|
|
13
|
+
constructor(hash, _key) {
|
|
14
|
+
super();
|
|
15
|
+
this.finished = false;
|
|
16
|
+
this.destroyed = false;
|
|
17
|
+
ahash(hash);
|
|
18
|
+
const key = toBytes(_key);
|
|
19
|
+
this.iHash = hash.create();
|
|
20
|
+
if (typeof this.iHash.update !== "function")
|
|
21
|
+
throw new Error("Expected instance of class which extends utils.Hash");
|
|
22
|
+
this.blockLen = this.iHash.blockLen;
|
|
23
|
+
this.outputLen = this.iHash.outputLen;
|
|
24
|
+
const blockLen = this.blockLen;
|
|
25
|
+
const pad = new Uint8Array(blockLen);
|
|
26
|
+
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
27
|
+
for (let i = 0; i < pad.length; i++)
|
|
28
|
+
pad[i] ^= 54;
|
|
29
|
+
this.iHash.update(pad);
|
|
30
|
+
this.oHash = hash.create();
|
|
31
|
+
for (let i = 0; i < pad.length; i++)
|
|
32
|
+
pad[i] ^= 54 ^ 92;
|
|
33
|
+
this.oHash.update(pad);
|
|
34
|
+
clean(pad);
|
|
35
|
+
}
|
|
36
|
+
update(buf) {
|
|
37
|
+
aexists(this);
|
|
38
|
+
this.iHash.update(buf);
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
digestInto(out) {
|
|
42
|
+
aexists(this);
|
|
43
|
+
abytes(out, this.outputLen);
|
|
44
|
+
this.finished = true;
|
|
45
|
+
this.iHash.digestInto(out);
|
|
46
|
+
this.oHash.update(out);
|
|
47
|
+
this.oHash.digestInto(out);
|
|
48
|
+
this.destroy();
|
|
49
|
+
}
|
|
50
|
+
digest() {
|
|
51
|
+
const out = new Uint8Array(this.oHash.outputLen);
|
|
52
|
+
this.digestInto(out);
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
_cloneInto(to) {
|
|
56
|
+
to || (to = Object.create(Object.getPrototypeOf(this), {}));
|
|
57
|
+
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
|
58
|
+
to = to;
|
|
59
|
+
to.finished = finished;
|
|
60
|
+
to.destroyed = destroyed;
|
|
61
|
+
to.blockLen = blockLen;
|
|
62
|
+
to.outputLen = outputLen;
|
|
63
|
+
to.oHash = oHash._cloneInto(to.oHash);
|
|
64
|
+
to.iHash = iHash._cloneInto(to.iHash);
|
|
65
|
+
return to;
|
|
66
|
+
}
|
|
67
|
+
clone() {
|
|
68
|
+
return this._cloneInto();
|
|
69
|
+
}
|
|
70
|
+
destroy() {
|
|
71
|
+
this.destroyed = true;
|
|
72
|
+
this.oHash.destroy();
|
|
73
|
+
this.iHash.destroy();
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
var hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
|
|
77
|
+
hmac.create = (hash, key) => new HMAC(hash, key);
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
HMAC,
|
|
81
|
+
hmac
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=chunk-32QD72IL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/src/hmac.ts"],"sourcesContent":["/**\n * HMAC: RFC2104 message authentication code.\n * @module\n */\nimport { abytes, aexists, ahash, clean, Hash, toBytes, type CHash, type Input } from './utils.ts';\n\nexport class HMAC<T extends Hash<T>> extends Hash<HMAC<T>> {\n oHash: T;\n iHash: T;\n blockLen: number;\n outputLen: number;\n private finished = false;\n private destroyed = false;\n\n constructor(hash: CHash, _key: Input) {\n super();\n ahash(hash);\n const key = toBytes(_key);\n this.iHash = hash.create() as T;\n if (typeof this.iHash.update !== 'function')\n throw new Error('Expected instance of class which extends utils.Hash');\n this.blockLen = this.iHash.blockLen;\n this.outputLen = this.iHash.outputLen;\n const blockLen = this.blockLen;\n const pad = new Uint8Array(blockLen);\n // blockLen can be bigger than outputLen\n pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);\n for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36;\n this.iHash.update(pad);\n // By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone\n this.oHash = hash.create() as T;\n // Undo internal XOR && apply outer XOR\n for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36 ^ 0x5c;\n this.oHash.update(pad);\n clean(pad);\n }\n update(buf: Input): this {\n aexists(this);\n this.iHash.update(buf);\n return this;\n }\n digestInto(out: Uint8Array): void {\n aexists(this);\n abytes(out, this.outputLen);\n this.finished = true;\n this.iHash.digestInto(out);\n this.oHash.update(out);\n this.oHash.digestInto(out);\n this.destroy();\n }\n digest(): Uint8Array {\n const out = new Uint8Array(this.oHash.outputLen);\n this.digestInto(out);\n return out;\n }\n _cloneInto(to?: HMAC<T>): HMAC<T> {\n // Create new instance without calling constructor since key already in state and we don't know it.\n to ||= Object.create(Object.getPrototypeOf(this), {});\n const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;\n to = to as this;\n to.finished = finished;\n to.destroyed = destroyed;\n to.blockLen = blockLen;\n to.outputLen = outputLen;\n to.oHash = oHash._cloneInto(to.oHash);\n to.iHash = iHash._cloneInto(to.iHash);\n return to;\n }\n clone(): HMAC<T> {\n return this._cloneInto();\n }\n destroy(): void {\n this.destroyed = true;\n this.oHash.destroy();\n this.iHash.destroy();\n }\n}\n\n/**\n * HMAC: RFC2104 message authentication code.\n * @param hash - function that would be used e.g. sha256\n * @param key - message key\n * @param message - message data\n * @example\n * import { hmac } from '@noble/hashes/hmac';\n * import { sha256 } from '@noble/hashes/sha2';\n * const mac1 = hmac(sha256, 'key', 'message');\n */\nexport const hmac: {\n (hash: CHash, key: Input, message: Input): Uint8Array;\n create(hash: CHash, key: Input): HMAC<any>;\n} = (hash: CHash, key: Input, message: Input): Uint8Array =>\n new HMAC<any>(hash, key).update(message).digest();\nhmac.create = (hash: CHash, key: Input) => new HMAC<any>(hash, key);\n"],"mappings":";;;;;;;;;;;AAMM,IAAO,OAAP,cAAuC,KAAa;EAQxD,YAAY,MAAa,MAAW;AAClC,UAAK;AAJC,SAAA,WAAW;AACX,SAAA,YAAY;AAIlB,UAAM,IAAI;AACV,UAAM,MAAM,QAAQ,IAAI;AACxB,SAAK,QAAQ,KAAK,OAAM;AACxB,QAAI,OAAO,KAAK,MAAM,WAAW;AAC/B,YAAM,IAAI,MAAM,qDAAqD;AACvE,SAAK,WAAW,KAAK,MAAM;AAC3B,SAAK,YAAY,KAAK,MAAM;AAC5B,UAAM,WAAW,KAAK;AACtB,UAAM,MAAM,IAAI,WAAW,QAAQ;AAEnC,QAAI,IAAI,IAAI,SAAS,WAAW,KAAK,OAAM,EAAG,OAAO,GAAG,EAAE,OAAM,IAAK,GAAG;AACxE,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ;AAAK,UAAI,CAAC,KAAK;AAC/C,SAAK,MAAM,OAAO,GAAG;AAErB,SAAK,QAAQ,KAAK,OAAM;AAExB,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ;AAAK,UAAI,CAAC,KAAK,KAAO;AACtD,SAAK,MAAM,OAAO,GAAG;AACrB,UAAM,GAAG;EACX;EACA,OAAO,KAAU;AACf,YAAQ,IAAI;AACZ,SAAK,MAAM,OAAO,GAAG;AACrB,WAAO;EACT;EACA,WAAW,KAAe;AACxB,YAAQ,IAAI;AACZ,WAAO,KAAK,KAAK,SAAS;AAC1B,SAAK,WAAW;AAChB,SAAK,MAAM,WAAW,GAAG;AACzB,SAAK,MAAM,OAAO,GAAG;AACrB,SAAK,MAAM,WAAW,GAAG;AACzB,SAAK,QAAO;EACd;EACA,SAAM;AACJ,UAAM,MAAM,IAAI,WAAW,KAAK,MAAM,SAAS;AAC/C,SAAK,WAAW,GAAG;AACnB,WAAO;EACT;EACA,WAAW,IAAY;AAErB,WAAA,KAAO,OAAO,OAAO,OAAO,eAAe,IAAI,GAAG,CAAA,CAAE;AACpD,UAAM,EAAE,OAAO,OAAO,UAAU,WAAW,UAAU,UAAS,IAAK;AACnE,SAAK;AACL,OAAG,WAAW;AACd,OAAG,YAAY;AACf,OAAG,WAAW;AACd,OAAG,YAAY;AACf,OAAG,QAAQ,MAAM,WAAW,GAAG,KAAK;AACpC,OAAG,QAAQ,MAAM,WAAW,GAAG,KAAK;AACpC,WAAO;EACT;EACA,QAAK;AACH,WAAO,KAAK,WAAU;EACxB;EACA,UAAO;AACL,SAAK,YAAY;AACjB,SAAK,MAAM,QAAO;AAClB,SAAK,MAAM,QAAO;EACpB;;AAaK,IAAM,OAGT,CAAC,MAAa,KAAY,YAC5B,IAAI,KAAU,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,OAAM;AACjD,KAAK,SAAS,CAAC,MAAa,QAAe,IAAI,KAAU,MAAM,GAAG;","names":[]}
|