protect-mcp 0.1.0 → 0.2.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 +161 -59
- package/dist/chunk-D733KAPG.mjs +252 -0
- package/dist/chunk-ZCKNFULF.mjs +613 -0
- package/dist/cli.js +3100 -20
- package/dist/cli.mjs +144 -7
- package/dist/ed25519-EDO4K4EP.mjs +2289 -0
- package/dist/index.d.mts +681 -6
- package/dist/index.d.ts +681 -6
- package/dist/index.js +698 -17
- package/dist/index.mjs +357 -3
- package/dist/utils-IDWBSHJU.mjs +76 -0
- package/package.json +12 -4
- package/dist/chunk-L3QWKSGY.mjs +0 -297
package/README.md
CHANGED
|
@@ -1,44 +1,147 @@
|
|
|
1
|
-
#
|
|
1
|
+
# protect-mcp
|
|
2
2
|
|
|
3
|
-
Security gateway for MCP servers. Tool-level policies,
|
|
3
|
+
Security gateway for MCP servers. Tool-level policies, trust-tier gating, credential isolation, and signed decision receipts.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Shadow mode by default.** Wraps any MCP server as a transparent proxy. Logs every tool call. Signs every decision. Optionally enforces policies.
|
|
6
6
|
|
|
7
7
|
## Quick Start
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
#
|
|
11
|
-
npx
|
|
10
|
+
# Shadow mode — log and sign every tool call, enforce nothing
|
|
11
|
+
npx protect-mcp -- node my-server.js
|
|
12
|
+
|
|
13
|
+
# Initialize a new project with keys + config template
|
|
14
|
+
npx protect-mcp init
|
|
12
15
|
|
|
13
16
|
# Enforce mode with a policy file
|
|
14
|
-
npx
|
|
17
|
+
npx protect-mcp --policy policy.json --enforce -- node my-server.js
|
|
15
18
|
```
|
|
16
19
|
|
|
17
|
-
##
|
|
20
|
+
## What It Does
|
|
18
21
|
|
|
19
22
|
protect-mcp sits between your MCP client and server as a stdio proxy:
|
|
20
23
|
|
|
21
24
|
```
|
|
22
|
-
MCP Client
|
|
25
|
+
MCP Client ←stdin/stdout→ protect-mcp ←stdin/stdout→ your MCP server
|
|
23
26
|
```
|
|
24
27
|
|
|
25
28
|
It intercepts `tools/call` JSON-RPC requests and:
|
|
26
|
-
- **
|
|
27
|
-
- **Enforce mode**: applies policy rules
|
|
29
|
+
- **Shadow mode** (default): logs every tool call, signs a decision receipt, allows everything through
|
|
30
|
+
- **Enforce mode**: applies policy rules — block, rate-limit, or gate by trust tier
|
|
28
31
|
|
|
29
32
|
All other MCP messages (`initialize`, `tools/list`, notifications) pass through transparently.
|
|
30
33
|
|
|
31
|
-
##
|
|
34
|
+
## Key Features
|
|
35
|
+
|
|
36
|
+
### Trust-Tier Gating
|
|
37
|
+
|
|
38
|
+
Agents present signed manifests. protect-mcp evaluates them into trust tiers and gates tool access accordingly:
|
|
39
|
+
|
|
40
|
+
| Tier | Meaning | How Assigned |
|
|
41
|
+
|------|---------|--------------|
|
|
42
|
+
| `unknown` | No manifest, or invalid signature | Default |
|
|
43
|
+
| `signed-known` | Valid signed manifest | Automatic |
|
|
44
|
+
| `evidenced` | Manifest + sufficient evidence history | Automatic |
|
|
45
|
+
| `privileged` | Operator-granted elevated trust | Manual override |
|
|
46
|
+
|
|
47
|
+
Policy example — require `signed-known` for destructive tools:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"default_tier": "unknown",
|
|
52
|
+
"tools": {
|
|
53
|
+
"delete_user": { "min_tier": "signed-known", "rate_limit": "5/hour" },
|
|
54
|
+
"read_file": { "require": "any" },
|
|
55
|
+
"*": { "rate_limit": "100/hour" }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Credential Vault
|
|
61
|
+
|
|
62
|
+
Agents never see raw API keys. Credentials are resolved from environment variables at call time and injected transparently:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"credentials": {
|
|
67
|
+
"stripe_api": {
|
|
68
|
+
"inject": "header",
|
|
69
|
+
"name": "Authorization",
|
|
70
|
+
"value_env": "STRIPE_SECRET_KEY"
|
|
71
|
+
},
|
|
72
|
+
"github_token": {
|
|
73
|
+
"inject": "header",
|
|
74
|
+
"name": "Authorization",
|
|
75
|
+
"value_env": "GITHUB_TOKEN"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Decision logs reference credential labels (`stripe_api`), never values.
|
|
82
|
+
|
|
83
|
+
### Signed Decision Receipts
|
|
84
|
+
|
|
85
|
+
Every tool call produces an Ed25519-signed v2 artifact — independently verifiable, no trust required:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
[PROTECT_MCP_RECEIPT] {"v":2,"type":"decision_receipt","algorithm":"ed25519","kid":"kPrK...","issuer":"sb:protect","issued_at":"2026-03-21T10:00:00Z","payload":{"decision":"allow","tool":"read_file","tier":"signed-known","policy_digest":"a1b2c3d4","scope":"default","mode":"shadow"},"signature":"a1b2c3..."}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Verify with the CLI: `npx @veritasacta/verify receipt.json`
|
|
92
|
+
Verify in browser: [scopeblind.com/verify](https://scopeblind.com/verify)
|
|
93
|
+
|
|
94
|
+
### Bring Your Own Policy Engine (BYOPE)
|
|
95
|
+
|
|
96
|
+
Plug in OPA, Cerbos, or any HTTP policy endpoint:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"policy_engine": "external",
|
|
101
|
+
"external": {
|
|
102
|
+
"endpoint": "http://localhost:8181/v1/data/mcp/allow",
|
|
103
|
+
"format": "opa",
|
|
104
|
+
"timeout_ms": 500,
|
|
105
|
+
"fallback": "deny"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Supported formats: `opa`, `cerbos`, `generic`. ScopeBlind signs the receipt regardless of who made the decision.
|
|
111
|
+
|
|
112
|
+
### Audit Bundle Export
|
|
32
113
|
|
|
33
|
-
|
|
114
|
+
Export self-contained audit bundles for offline verification or compliance:
|
|
34
115
|
|
|
35
116
|
```json
|
|
36
117
|
{
|
|
118
|
+
"format": "scopeblind:audit-bundle",
|
|
119
|
+
"version": 1,
|
|
120
|
+
"tenant": "my-service",
|
|
121
|
+
"receipts": [ ...signed artifacts... ],
|
|
122
|
+
"verification": {
|
|
123
|
+
"algorithm": "ed25519",
|
|
124
|
+
"signing_keys": [ ...JWK keys... ]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Policy File
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"default_tier": "unknown",
|
|
37
134
|
"tools": {
|
|
38
|
-
"dangerous_tool": { "
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"*": { "
|
|
135
|
+
"dangerous_tool": { "block": true },
|
|
136
|
+
"admin_tool": { "min_tier": "signed-known", "rate_limit": "5/hour" },
|
|
137
|
+
"read_tool": { "require": "any", "rate_limit": "100/hour" },
|
|
138
|
+
"*": { "rate_limit": "500/hour" }
|
|
139
|
+
},
|
|
140
|
+
"credentials": {
|
|
141
|
+
"api_key": { "inject": "header", "name": "Authorization", "value_env": "MY_API_KEY" }
|
|
142
|
+
},
|
|
143
|
+
"signing": {
|
|
144
|
+
"key_file": ".protect-mcp-key.json"
|
|
42
145
|
}
|
|
43
146
|
}
|
|
44
147
|
```
|
|
@@ -47,11 +150,10 @@ Create a `policy.json`:
|
|
|
47
150
|
|
|
48
151
|
| Field | Values | Description |
|
|
49
152
|
|-------|--------|-------------|
|
|
50
|
-
| `require` | `"gateway"`, `"any"`, `"none"` | Identity requirement (metadata only in v1 — not enforced until v2 SSE transport) |
|
|
51
|
-
| `rate_limit` | `"N/unit"` | Rate limit (e.g. `"5/hour"`, `"100/day"`, `"10/minute"`) |
|
|
52
153
|
| `block` | `true` | Explicitly block this tool |
|
|
53
|
-
|
|
54
|
-
|
|
154
|
+
| `require` | `"any"`, `"none"` | Basic access requirement |
|
|
155
|
+
| `min_tier` | `"unknown"`, `"signed-known"`, `"evidenced"`, `"privileged"` | Minimum trust tier required |
|
|
156
|
+
| `rate_limit` | `"N/unit"` | Rate limit (e.g. `"5/hour"`, `"100/day"`) |
|
|
55
157
|
|
|
56
158
|
Tool names match exactly, with `"*"` as a wildcard fallback.
|
|
57
159
|
|
|
@@ -67,7 +169,7 @@ Add to `claude_desktop_config.json`:
|
|
|
67
169
|
"my-protected-server": {
|
|
68
170
|
"command": "npx",
|
|
69
171
|
"args": [
|
|
70
|
-
"-y", "
|
|
172
|
+
"-y", "protect-mcp",
|
|
71
173
|
"--policy", "/path/to/policy.json",
|
|
72
174
|
"--enforce",
|
|
73
175
|
"--", "node", "my-server.js"
|
|
@@ -81,39 +183,19 @@ Add to `claude_desktop_config.json`:
|
|
|
81
183
|
|
|
82
184
|
Same pattern — replace the server command with protect-mcp wrapping it.
|
|
83
185
|
|
|
84
|
-
## Decision Logs
|
|
85
|
-
|
|
86
|
-
Every tool call emits a structured JSON log to stderr:
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
[PROTECT_MCP] {"v":1,"tool":"dangerous_tool","decision":"deny","reason_code":"rate_limit_exceeded","policy_digest":"a1b2c3d4","request_id":"req_abc123","timestamp":1710000000,"mode":"enforce","rate_limit_remaining":0}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Log Fields
|
|
93
|
-
|
|
94
|
-
| Field | Description |
|
|
95
|
-
|-------|-------------|
|
|
96
|
-
| `v` | Schema version (always `1`) |
|
|
97
|
-
| `tool` | Tool name that was called |
|
|
98
|
-
| `decision` | `"allow"` or `"deny"` |
|
|
99
|
-
| `reason_code` | `"policy_allow"`, `"policy_block"`, `"rate_limit_exceeded"`, `"observe_mode"`, `"default_allow"` |
|
|
100
|
-
| `policy_digest` | SHA-256 prefix of the policy file |
|
|
101
|
-
| `request_id` | Unique request identifier |
|
|
102
|
-
| `timestamp` | Unix timestamp (ms) |
|
|
103
|
-
| `mode` | `"observe"` or `"enforce"` |
|
|
104
|
-
| `rate_limit_remaining` | Remaining rate limit budget (if applicable) |
|
|
105
|
-
|
|
106
|
-
These are **decision logs**, not signed receipts. Cryptographically signed receipts require the ScopeBlind API (v2).
|
|
107
|
-
|
|
108
186
|
## CLI Options
|
|
109
187
|
|
|
110
188
|
```
|
|
111
189
|
protect-mcp [options] -- <command> [args...]
|
|
190
|
+
protect-mcp init
|
|
191
|
+
|
|
192
|
+
Commands:
|
|
193
|
+
init Generate Ed25519 keypair + config template
|
|
112
194
|
|
|
113
195
|
Options:
|
|
114
|
-
--policy <path> Policy JSON file (default: allow-all)
|
|
115
|
-
--slug <slug>
|
|
116
|
-
--enforce Enable enforcement mode (default:
|
|
196
|
+
--policy <path> Policy JSON file (default: shadow mode, allow-all)
|
|
197
|
+
--slug <slug> Service identifier for receipts
|
|
198
|
+
--enforce Enable enforcement mode (default: shadow)
|
|
117
199
|
--verbose Enable debug logging
|
|
118
200
|
--help Show help
|
|
119
201
|
```
|
|
@@ -121,21 +203,41 @@ Options:
|
|
|
121
203
|
## Programmatic API
|
|
122
204
|
|
|
123
205
|
```typescript
|
|
124
|
-
import {
|
|
206
|
+
import {
|
|
207
|
+
ProtectGateway,
|
|
208
|
+
loadPolicy,
|
|
209
|
+
evaluateTier,
|
|
210
|
+
meetsMinTier,
|
|
211
|
+
resolveCredential,
|
|
212
|
+
initSigning,
|
|
213
|
+
signDecision,
|
|
214
|
+
createAuditBundle,
|
|
215
|
+
} from 'protect-mcp';
|
|
216
|
+
```
|
|
125
217
|
|
|
126
|
-
|
|
218
|
+
## Decision Logs
|
|
127
219
|
|
|
128
|
-
|
|
129
|
-
command: 'node',
|
|
130
|
-
args: ['my-server.js'],
|
|
131
|
-
policy,
|
|
132
|
-
policyDigest: digest,
|
|
133
|
-
enforce: true,
|
|
134
|
-
});
|
|
220
|
+
Every tool call emits structured JSON to stderr:
|
|
135
221
|
|
|
136
|
-
await gateway.start();
|
|
137
222
|
```
|
|
223
|
+
[PROTECT_MCP] {"v":2,"tool":"read_file","decision":"allow","tier":"signed-known","reason_code":"policy_allow","policy_digest":"a1b2c3d4","mode":"shadow","timestamp":1710000000}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
When signing is configured, a signed receipt follows:
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
[PROTECT_MCP_RECEIPT] {"v":2,"type":"decision_receipt","algorithm":"ed25519",...,"signature":"..."}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Philosophy
|
|
233
|
+
|
|
234
|
+
- **Shadow first.** See what's happening before you control anything.
|
|
235
|
+
- **Receipts, not logs.** Signed, independently verifiable. Not "trust us."
|
|
236
|
+
- **Credential isolation.** Agents call tools. They never see API keys.
|
|
237
|
+
- **Observe → Enforce → Audit.** Progressive adoption, not all-or-nothing.
|
|
138
238
|
|
|
139
239
|
## License
|
|
140
240
|
|
|
141
|
-
FSL-1.1-MIT
|
|
241
|
+
FSL-1.1-MIT — free to use, converts to full MIT after 2 years.
|
|
242
|
+
|
|
243
|
+
[scopeblind.com](https://scopeblind.com) · [npm](https://www.npmjs.com/package/protect-mcp) · [GitHub](https://github.com/tomjwxf/scopeblind-gateway)
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// node_modules/@noble/hashes/esm/cryptoNode.js
|
|
2
|
+
import * as nc from "crypto";
|
|
3
|
+
var crypto = nc && typeof nc === "object" && "webcrypto" in nc ? nc.webcrypto : nc && typeof nc === "object" && "randomBytes" in nc ? nc : void 0;
|
|
4
|
+
|
|
5
|
+
// node_modules/@noble/hashes/esm/utils.js
|
|
6
|
+
function isBytes(a) {
|
|
7
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
8
|
+
}
|
|
9
|
+
function anumber(n) {
|
|
10
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
11
|
+
throw new Error("positive integer expected, got " + n);
|
|
12
|
+
}
|
|
13
|
+
function abytes(b, ...lengths) {
|
|
14
|
+
if (!isBytes(b))
|
|
15
|
+
throw new Error("Uint8Array expected");
|
|
16
|
+
if (lengths.length > 0 && !lengths.includes(b.length))
|
|
17
|
+
throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
|
|
18
|
+
}
|
|
19
|
+
function ahash(h) {
|
|
20
|
+
if (typeof h !== "function" || typeof h.create !== "function")
|
|
21
|
+
throw new Error("Hash should be wrapped by utils.createHasher");
|
|
22
|
+
anumber(h.outputLen);
|
|
23
|
+
anumber(h.blockLen);
|
|
24
|
+
}
|
|
25
|
+
function aexists(instance, checkFinished = true) {
|
|
26
|
+
if (instance.destroyed)
|
|
27
|
+
throw new Error("Hash instance has been destroyed");
|
|
28
|
+
if (checkFinished && instance.finished)
|
|
29
|
+
throw new Error("Hash#digest() has already been called");
|
|
30
|
+
}
|
|
31
|
+
function aoutput(out, instance) {
|
|
32
|
+
abytes(out);
|
|
33
|
+
const min = instance.outputLen;
|
|
34
|
+
if (out.length < min) {
|
|
35
|
+
throw new Error("digestInto() expects output buffer of length at least " + min);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function u8(arr) {
|
|
39
|
+
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
40
|
+
}
|
|
41
|
+
function u32(arr) {
|
|
42
|
+
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
|
43
|
+
}
|
|
44
|
+
function clean(...arrays) {
|
|
45
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
46
|
+
arrays[i].fill(0);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function createView(arr) {
|
|
50
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
51
|
+
}
|
|
52
|
+
function rotr(word, shift) {
|
|
53
|
+
return word << 32 - shift | word >>> shift;
|
|
54
|
+
}
|
|
55
|
+
function rotl(word, shift) {
|
|
56
|
+
return word << shift | word >>> 32 - shift >>> 0;
|
|
57
|
+
}
|
|
58
|
+
var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
59
|
+
function byteSwap(word) {
|
|
60
|
+
return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
|
|
61
|
+
}
|
|
62
|
+
var swap8IfBE = isLE ? (n) => n : (n) => byteSwap(n);
|
|
63
|
+
var byteSwapIfBE = swap8IfBE;
|
|
64
|
+
function byteSwap32(arr) {
|
|
65
|
+
for (let i = 0; i < arr.length; i++) {
|
|
66
|
+
arr[i] = byteSwap(arr[i]);
|
|
67
|
+
}
|
|
68
|
+
return arr;
|
|
69
|
+
}
|
|
70
|
+
var swap32IfBE = isLE ? (u) => u : byteSwap32;
|
|
71
|
+
var hasHexBuiltin = /* @__PURE__ */ (() => (
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
|
|
74
|
+
))();
|
|
75
|
+
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
76
|
+
function bytesToHex(bytes) {
|
|
77
|
+
abytes(bytes);
|
|
78
|
+
if (hasHexBuiltin)
|
|
79
|
+
return bytes.toHex();
|
|
80
|
+
let hex = "";
|
|
81
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
82
|
+
hex += hexes[bytes[i]];
|
|
83
|
+
}
|
|
84
|
+
return hex;
|
|
85
|
+
}
|
|
86
|
+
var asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
|
|
87
|
+
function asciiToBase16(ch) {
|
|
88
|
+
if (ch >= asciis._0 && ch <= asciis._9)
|
|
89
|
+
return ch - asciis._0;
|
|
90
|
+
if (ch >= asciis.A && ch <= asciis.F)
|
|
91
|
+
return ch - (asciis.A - 10);
|
|
92
|
+
if (ch >= asciis.a && ch <= asciis.f)
|
|
93
|
+
return ch - (asciis.a - 10);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
function hexToBytes(hex) {
|
|
97
|
+
if (typeof hex !== "string")
|
|
98
|
+
throw new Error("hex string expected, got " + typeof hex);
|
|
99
|
+
if (hasHexBuiltin)
|
|
100
|
+
return Uint8Array.fromHex(hex);
|
|
101
|
+
const hl = hex.length;
|
|
102
|
+
const al = hl / 2;
|
|
103
|
+
if (hl % 2)
|
|
104
|
+
throw new Error("hex string expected, got unpadded hex of length " + hl);
|
|
105
|
+
const array = new Uint8Array(al);
|
|
106
|
+
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
|
107
|
+
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
|
108
|
+
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
|
|
109
|
+
if (n1 === void 0 || n2 === void 0) {
|
|
110
|
+
const char = hex[hi] + hex[hi + 1];
|
|
111
|
+
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
|
|
112
|
+
}
|
|
113
|
+
array[ai] = n1 * 16 + n2;
|
|
114
|
+
}
|
|
115
|
+
return array;
|
|
116
|
+
}
|
|
117
|
+
var nextTick = async () => {
|
|
118
|
+
};
|
|
119
|
+
async function asyncLoop(iters, tick, cb) {
|
|
120
|
+
let ts = Date.now();
|
|
121
|
+
for (let i = 0; i < iters; i++) {
|
|
122
|
+
cb(i);
|
|
123
|
+
const diff = Date.now() - ts;
|
|
124
|
+
if (diff >= 0 && diff < tick)
|
|
125
|
+
continue;
|
|
126
|
+
await nextTick();
|
|
127
|
+
ts += diff;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function utf8ToBytes(str) {
|
|
131
|
+
if (typeof str !== "string")
|
|
132
|
+
throw new Error("string expected");
|
|
133
|
+
return new Uint8Array(new TextEncoder().encode(str));
|
|
134
|
+
}
|
|
135
|
+
function bytesToUtf8(bytes) {
|
|
136
|
+
return new TextDecoder().decode(bytes);
|
|
137
|
+
}
|
|
138
|
+
function toBytes(data) {
|
|
139
|
+
if (typeof data === "string")
|
|
140
|
+
data = utf8ToBytes(data);
|
|
141
|
+
abytes(data);
|
|
142
|
+
return data;
|
|
143
|
+
}
|
|
144
|
+
function kdfInputToBytes(data) {
|
|
145
|
+
if (typeof data === "string")
|
|
146
|
+
data = utf8ToBytes(data);
|
|
147
|
+
abytes(data);
|
|
148
|
+
return data;
|
|
149
|
+
}
|
|
150
|
+
function concatBytes(...arrays) {
|
|
151
|
+
let sum = 0;
|
|
152
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
153
|
+
const a = arrays[i];
|
|
154
|
+
abytes(a);
|
|
155
|
+
sum += a.length;
|
|
156
|
+
}
|
|
157
|
+
const res = new Uint8Array(sum);
|
|
158
|
+
for (let i = 0, pad = 0; i < arrays.length; i++) {
|
|
159
|
+
const a = arrays[i];
|
|
160
|
+
res.set(a, pad);
|
|
161
|
+
pad += a.length;
|
|
162
|
+
}
|
|
163
|
+
return res;
|
|
164
|
+
}
|
|
165
|
+
function checkOpts(defaults, opts) {
|
|
166
|
+
if (opts !== void 0 && {}.toString.call(opts) !== "[object Object]")
|
|
167
|
+
throw new Error("options should be object or undefined");
|
|
168
|
+
const merged = Object.assign(defaults, opts);
|
|
169
|
+
return merged;
|
|
170
|
+
}
|
|
171
|
+
var Hash = class {
|
|
172
|
+
};
|
|
173
|
+
function createHasher(hashCons) {
|
|
174
|
+
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
|
|
175
|
+
const tmp = hashCons();
|
|
176
|
+
hashC.outputLen = tmp.outputLen;
|
|
177
|
+
hashC.blockLen = tmp.blockLen;
|
|
178
|
+
hashC.create = () => hashCons();
|
|
179
|
+
return hashC;
|
|
180
|
+
}
|
|
181
|
+
function createOptHasher(hashCons) {
|
|
182
|
+
const hashC = (msg, opts) => hashCons(opts).update(toBytes(msg)).digest();
|
|
183
|
+
const tmp = hashCons({});
|
|
184
|
+
hashC.outputLen = tmp.outputLen;
|
|
185
|
+
hashC.blockLen = tmp.blockLen;
|
|
186
|
+
hashC.create = (opts) => hashCons(opts);
|
|
187
|
+
return hashC;
|
|
188
|
+
}
|
|
189
|
+
function createXOFer(hashCons) {
|
|
190
|
+
const hashC = (msg, opts) => hashCons(opts).update(toBytes(msg)).digest();
|
|
191
|
+
const tmp = hashCons({});
|
|
192
|
+
hashC.outputLen = tmp.outputLen;
|
|
193
|
+
hashC.blockLen = tmp.blockLen;
|
|
194
|
+
hashC.create = (opts) => hashCons(opts);
|
|
195
|
+
return hashC;
|
|
196
|
+
}
|
|
197
|
+
var wrapConstructor = createHasher;
|
|
198
|
+
var wrapConstructorWithOpts = createOptHasher;
|
|
199
|
+
var wrapXOFConstructorWithOpts = createXOFer;
|
|
200
|
+
function randomBytes(bytesLength = 32) {
|
|
201
|
+
if (crypto && typeof crypto.getRandomValues === "function") {
|
|
202
|
+
return crypto.getRandomValues(new Uint8Array(bytesLength));
|
|
203
|
+
}
|
|
204
|
+
if (crypto && typeof crypto.randomBytes === "function") {
|
|
205
|
+
return Uint8Array.from(crypto.randomBytes(bytesLength));
|
|
206
|
+
}
|
|
207
|
+
throw new Error("crypto.getRandomValues must be defined");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export {
|
|
211
|
+
isBytes,
|
|
212
|
+
anumber,
|
|
213
|
+
abytes,
|
|
214
|
+
ahash,
|
|
215
|
+
aexists,
|
|
216
|
+
aoutput,
|
|
217
|
+
u8,
|
|
218
|
+
u32,
|
|
219
|
+
clean,
|
|
220
|
+
createView,
|
|
221
|
+
rotr,
|
|
222
|
+
rotl,
|
|
223
|
+
isLE,
|
|
224
|
+
byteSwap,
|
|
225
|
+
swap8IfBE,
|
|
226
|
+
byteSwapIfBE,
|
|
227
|
+
byteSwap32,
|
|
228
|
+
swap32IfBE,
|
|
229
|
+
bytesToHex,
|
|
230
|
+
hexToBytes,
|
|
231
|
+
nextTick,
|
|
232
|
+
asyncLoop,
|
|
233
|
+
utf8ToBytes,
|
|
234
|
+
bytesToUtf8,
|
|
235
|
+
toBytes,
|
|
236
|
+
kdfInputToBytes,
|
|
237
|
+
concatBytes,
|
|
238
|
+
checkOpts,
|
|
239
|
+
Hash,
|
|
240
|
+
createHasher,
|
|
241
|
+
createOptHasher,
|
|
242
|
+
createXOFer,
|
|
243
|
+
wrapConstructor,
|
|
244
|
+
wrapConstructorWithOpts,
|
|
245
|
+
wrapXOFConstructorWithOpts,
|
|
246
|
+
randomBytes
|
|
247
|
+
};
|
|
248
|
+
/*! Bundled license information:
|
|
249
|
+
|
|
250
|
+
@noble/hashes/esm/utils.js:
|
|
251
|
+
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
252
|
+
*/
|