neozip-mcp 0.1.0-beta
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/.cursor/mcp.json.global.example +10 -0
- package/CHANGELOG.md +16 -0
- package/DOCUMENTATION.md +40 -0
- package/LICENSE +16 -0
- package/README.md +223 -0
- package/SECURITY.md +37 -0
- package/dist/account/account-state.js +86 -0
- package/dist/account/format-account-status.js +37 -0
- package/dist/account/identity-provision.js +75 -0
- package/dist/account/identity-wrap.js +69 -0
- package/dist/account/profile-crypto.js +47 -0
- package/dist/account/profile-store.js +108 -0
- package/dist/account/require-account.js +29 -0
- package/dist/account/token-service-identity.js +395 -0
- package/dist/account/types.js +2 -0
- package/dist/account/wallet-evm.js +39 -0
- package/dist/archive/blockchain-status.js +303 -0
- package/dist/archive/crypto-self.js +114 -0
- package/dist/archive/detect-text.js +56 -0
- package/dist/archive/embed-metadata.js +283 -0
- package/dist/archive/encryption.js +166 -0
- package/dist/archive/extract-entry-buffer.js +18 -0
- package/dist/archive/find-entry.js +21 -0
- package/dist/archive/grep-content.js +141 -0
- package/dist/archive/identity-key.js +176 -0
- package/dist/archive/manifest.js +55 -0
- package/dist/archive/merkle.js +31 -0
- package/dist/archive/metadata-paths.js +14 -0
- package/dist/archive/mint-archive.js +61 -0
- package/dist/archive/open-archive.js +23 -0
- package/dist/archive/read-entry-buffer.js +11 -0
- package/dist/archive/read-entry-content.js +51 -0
- package/dist/archive/recipient-access.js +26 -0
- package/dist/archive/recipient-decrypt.js +21 -0
- package/dist/archive/recipient-lookup.js +55 -0
- package/dist/archive/timestamp-network.js +54 -0
- package/dist/config/capabilities.js +37 -0
- package/dist/config/index.js +74 -0
- package/dist/connect-cli.js +312 -0
- package/dist/connection/coordinator.js +74 -0
- package/dist/connection/credentials.js +29 -0
- package/dist/connection/crypto.js +56 -0
- package/dist/connection/dump.js +79 -0
- package/dist/connection/incomplete-setup.js +81 -0
- package/dist/connection/interactive.js +814 -0
- package/dist/connection/legacy-profile-reader.js +47 -0
- package/dist/connection/magic-link.js +138 -0
- package/dist/connection/migrate.js +76 -0
- package/dist/connection/onboarding.js +524 -0
- package/dist/connection/origin.js +63 -0
- package/dist/connection/phase.js +93 -0
- package/dist/connection/phone.js +20 -0
- package/dist/connection/promote-active.js +53 -0
- package/dist/connection/reset.js +20 -0
- package/dist/connection/setup-guidance.js +154 -0
- package/dist/connection/status-report.js +40 -0
- package/dist/connection/store.js +352 -0
- package/dist/connection/token-auth.js +42 -0
- package/dist/connection/types.js +2 -0
- package/dist/connection/wallet-setup.js +70 -0
- package/dist/constants/wallet-identity.js +11 -0
- package/dist/index.js +47 -0
- package/dist/load-env.js +16 -0
- package/dist/neozipkit-node.js +11 -0
- package/dist/register/resources.js +14 -0
- package/dist/register/tools.js +77 -0
- package/dist/resources/zip-resource.js +40 -0
- package/dist/resources/zip-uri.js +23 -0
- package/dist/security/auth.js +28 -0
- package/dist/security/capabilities.js +85 -0
- package/dist/security/rate-limiter.js +43 -0
- package/dist/security/resource-limiter.js +44 -0
- package/dist/security/sandbox.js +61 -0
- package/dist/server.js +32 -0
- package/dist/startup-account-gate.js +101 -0
- package/dist/startup-summary.js +40 -0
- package/dist/token-service/require-configured.js +23 -0
- package/dist/tools/account.js +504 -0
- package/dist/tools/compress.js +237 -0
- package/dist/tools/connect-status.js +143 -0
- package/dist/tools/extract.js +62 -0
- package/dist/tools/grep-entries.js +42 -0
- package/dist/tools/identity-status.js +157 -0
- package/dist/tools/info.js +147 -0
- package/dist/tools/list.js +118 -0
- package/dist/tools/lookup-recipient.js +37 -0
- package/dist/tools/mint.js +41 -0
- package/dist/tools/read-entry.js +35 -0
- package/dist/tools/search-entries.js +71 -0
- package/dist/tools/stamp.js +60 -0
- package/dist/tools/test.js +90 -0
- package/dist/tools/token-service-account.js +143 -0
- package/dist/tools/upgrade.js +60 -0
- package/dist/tools/verify.js +75 -0
- package/dist/tools/wallet-config-status.js +119 -0
- package/dist/tools/wallet-info.js +64 -0
- package/dist/translators/index.js +106 -0
- package/dist/types/index.js +7 -0
- package/dist/util/mask.js +30 -0
- package/dist/util/token-service-fetch.js +23 -0
- package/dist/vendor/neozipkit-pro.js +3 -0
- package/docs/NEOZIP_CONNECTION_STORE.md +238 -0
- package/docs/NEOZIP_CONNECT_CLI.md +185 -0
- package/docs/OPERATIONS.md +992 -0
- package/docs/examples/CLAUDE.md.example +22 -0
- package/docs/examples/claude/skills/neozip-mcp/SKILL.md +54 -0
- package/docs/examples/claude/skills/neozip-notarization/SKILL.md +75 -0
- package/docs/examples/mcp.json.claude.example +11 -0
- package/docs/examples/neozip-mcp-cursor-rule.mdc +31 -0
- package/docs/installation-guides/INSTALL_CLAUDE_CODE.md +286 -0
- package/docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md +301 -0
- package/docs/installation-guides/README.md +76 -0
- package/package.json +99 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Release notes for [neozip-mcp](https://www.npmjs.com/package/neozip-mcp).
|
|
4
|
+
|
|
5
|
+
## 0.1.0-beta (2026-06-26)
|
|
6
|
+
|
|
7
|
+
First npm release (**beta**).
|
|
8
|
+
|
|
9
|
+
- MCP stdio server with ZIP tools (`compress`, `extract`, `list`, `info`, `test`, `read_entry`, `search_entries`, `grep_entries`) and `zip://` resources
|
|
10
|
+
- Blockchain notarization tools (`stamp`, `mint`, `verify`, `upgrade_timestamped`, `wallet_info`)
|
|
11
|
+
- NeoZip Token Service integration via **`neozip-connect`** CLI and account tools
|
|
12
|
+
- Recipient encryption (Token Service X25519) bundled at build time — no GitHub Packages install required at runtime
|
|
13
|
+
- Path sandboxing, capability scoping, rate limiting, and resource limits
|
|
14
|
+
- Shipped docs, Claude Code install guides, and example agent skills under `docs/examples/claude/skills/`
|
|
15
|
+
|
|
16
|
+
See [README.md](README.md) and [docs/OPERATIONS.md](docs/OPERATIONS.md) for setup and tool reference.
|
package/DOCUMENTATION.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# NeoZip MCP documentation
|
|
2
|
+
|
|
3
|
+
Documentation shipped with the [neozip-mcp](https://www.npmjs.com/package/neozip-mcp) npm package (**beta** — install with `npm install -g neozip-mcp@beta`).
|
|
4
|
+
|
|
5
|
+
## Getting started
|
|
6
|
+
|
|
7
|
+
| Document | Description |
|
|
8
|
+
|----------|-------------|
|
|
9
|
+
| [README.md](README.md) | Installation, MCP host setup, environment variables |
|
|
10
|
+
| [CHANGELOG.md](CHANGELOG.md) | Version history and release notes |
|
|
11
|
+
| [SECURITY.md](SECURITY.md) | Security considerations and vulnerability reporting |
|
|
12
|
+
|
|
13
|
+
## Tool reference
|
|
14
|
+
|
|
15
|
+
| Document | Description |
|
|
16
|
+
|----------|-------------|
|
|
17
|
+
| [docs/OPERATIONS.md](docs/OPERATIONS.md) | Full MCP tool and parameter reference |
|
|
18
|
+
| [docs/NEOZIP_CONNECT_CLI.md](docs/NEOZIP_CONNECT_CLI.md) | `neozip-connect` account setup CLI |
|
|
19
|
+
| [docs/NEOZIP_CONNECTION_STORE.md](docs/NEOZIP_CONNECTION_STORE.md) | Connection store layout (`~/.neozip/connection/`) |
|
|
20
|
+
|
|
21
|
+
## MCP host installation
|
|
22
|
+
|
|
23
|
+
| Document | Description |
|
|
24
|
+
|----------|-------------|
|
|
25
|
+
| [docs/installation-guides/README.md](docs/installation-guides/README.md) | Index of host guides |
|
|
26
|
+
| [docs/installation-guides/INSTALL_CLAUDE_CODE.md](docs/installation-guides/INSTALL_CLAUDE_CODE.md) | Claude Code (user scope) |
|
|
27
|
+
| [docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md](docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md) | Claude Code workspace (`.mcp.json`) |
|
|
28
|
+
|
|
29
|
+
## Examples (in package)
|
|
30
|
+
|
|
31
|
+
| Path | Description |
|
|
32
|
+
|------|-------------|
|
|
33
|
+
| [docs/examples/mcp.json.claude.example](docs/examples/mcp.json.claude.example) | Claude Code `.mcp.json` template |
|
|
34
|
+
| [docs/examples/claude/skills/](docs/examples/claude/skills/) | Agent skills for archives and notarization |
|
|
35
|
+
| [.cursor/mcp.json.global.example](.cursor/mcp.json.global.example) | Cursor global MCP config template |
|
|
36
|
+
|
|
37
|
+
## Support
|
|
38
|
+
|
|
39
|
+
- **GitHub Issues:** [NeoWareInc/neozip-support](https://github.com/NeoWareInc/neozip-support/issues)
|
|
40
|
+
- **Email:** [support@neozip.io](mailto:support@neozip.io)
|
package/LICENSE
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Copyright (c) 2026 NeoWare, Inc. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and associated documentation files (the "Software") are
|
|
4
|
+
proprietary to NeoWare, Inc. The Software is provided only to authorized
|
|
5
|
+
recipients for internal use.
|
|
6
|
+
|
|
7
|
+
No license is granted to copy, modify, merge, publish, distribute,
|
|
8
|
+
sublicense, or sell copies of the Software except as expressly authorized
|
|
9
|
+
in writing by NeoWare, Inc.
|
|
10
|
+
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
12
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
13
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
14
|
+
NEOWARE, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
15
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
16
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# neozip-mcp
|
|
2
|
+
|
|
3
|
+
> MCP server for ZIP archives, blockchain notarization, and AI agent integration — powered by [neozipkit](https://www.npmjs.com/package/neozipkit) and [neozip-blockchain](https://www.npmjs.com/package/neozip-blockchain)
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/neozip-mcp)
|
|
6
|
+
[](https://nodejs.org/)
|
|
7
|
+
|
|
8
|
+
> **Beta version warning:** NeoZip MCP is currently in **beta** status. This means:
|
|
9
|
+
> - The MCP tool surface and CLI may change in future releases
|
|
10
|
+
> - Some features may be incomplete or experimental
|
|
11
|
+
> - Breaking changes may occur before the stable release
|
|
12
|
+
> - Use in production with caution and thorough testing
|
|
13
|
+
>
|
|
14
|
+
> Install the beta channel: `npm install -g neozip-mcp@beta`. Report issues on [GitHub](https://github.com/NeoWareInc/neozip-support/issues) or email [support@neozip.io](mailto:support@neozip.io).
|
|
15
|
+
|
|
16
|
+
## Release notice
|
|
17
|
+
|
|
18
|
+
**Current version: v0.1.0-beta.** See [CHANGELOG.md](CHANGELOG.md) for details.
|
|
19
|
+
|
|
20
|
+
- **API stability:** MCP tool names and parameters may change before a stable release
|
|
21
|
+
- **Testing:** Test thoroughly in your MCP host before production use
|
|
22
|
+
- **Feedback:** Report issues via [GitHub Issues](https://github.com/NeoWareInc/neozip-support/issues) or email [support@neozip.io](mailto:support@neozip.io)
|
|
23
|
+
- **License:** Proprietary — NeoWare, Inc. See [LICENSE](LICENSE)
|
|
24
|
+
|
|
25
|
+
## Overview
|
|
26
|
+
|
|
27
|
+
NeoZip MCP is a local stdio MCP server for AI coding agents (Claude Code, Cursor, and other MCP hosts). It exposes ZIP operations, blockchain notarization, and NeoZip Token Service tools to the agent — no repository checkout required.
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
### ZIP Operations
|
|
32
|
+
- **compress** -- Create ZIP archives (default: Zstandard). Options: `recipientEmails` (Token Service public-key encryption via `META-INF/ACCESS.NZIP`), `password` + `encryptionMethod`, `timestamp`, `tokenize`. SHA-256 is auto-enabled for timestamped/tokenized archives.
|
|
33
|
+
- **extract** -- Extract ZIP files to directories (password-protected archives supported)
|
|
34
|
+
- **list** -- List ZIP archive contents (text or JSON manifest)
|
|
35
|
+
- **info** -- Get detailed ZIP metadata (sizes, ratios, merkle root)
|
|
36
|
+
- **test** -- Test ZIP integrity per entry
|
|
37
|
+
- **read_entry** -- Read a single file inside an archive with pagination (optional `options.password` for encrypted entries)
|
|
38
|
+
- **search_entries** -- Search archive entry names by keyword or regex
|
|
39
|
+
- **grep_entries** -- Search file contents inside an archive for text or regex matches (no extraction)
|
|
40
|
+
|
|
41
|
+
### MCP Resources
|
|
42
|
+
- **zip://** -- Direct access to archive manifests and entry contents as MCP resources
|
|
43
|
+
|
|
44
|
+
See [docs/OPERATIONS.md](docs/OPERATIONS.md) for full parameter reference.
|
|
45
|
+
|
|
46
|
+
### NeoZip Token Service
|
|
47
|
+
Account, identity, and recipient-key tools that talk to the NeoZip Token Service (configured via `neozip-connect`); they do not operate on ZIP archives directly.
|
|
48
|
+
- **connect_status** -- Fast neozip-connect readiness: phase, compress option readiness, next terminal command (no secrets, no network)
|
|
49
|
+
- **token_service_status** -- Check Token Service email verification status
|
|
50
|
+
- **token_service_register** -- Register email and send verification code (requires `blockchain`)
|
|
51
|
+
- **token_service_verify** -- Verify email with 6-digit code (requires `blockchain`)
|
|
52
|
+
- **lookup_recipient** -- Resolve a recipient's Token Service X25519 public key by email before encrypting
|
|
53
|
+
- **identity_status** -- Token Service `/crypto/self` identity provisioning (Bearer token in env)
|
|
54
|
+
- **wallet_config_status** -- Diagnose credential sources and readiness (no secrets)
|
|
55
|
+
|
|
56
|
+
### Blockchain Operations
|
|
57
|
+
- **mint** -- Mint ZIP hash as NFT on Base network
|
|
58
|
+
- **verify** -- Verify token authenticity against blockchain
|
|
59
|
+
- **stamp** -- Submit ZIP merkle root to the NeoZip Token Service for timestamping
|
|
60
|
+
- **upgrade_timestamped** -- Upgrade pending timestamp to confirmed (`META-INF/TIMESTAMP.NZIP`)
|
|
61
|
+
- **wallet_info** -- View wallet and network status (address, balance)
|
|
62
|
+
|
|
63
|
+
### Security
|
|
64
|
+
- **Path sandboxing** -- Allowlist-based directory restrictions with symlink and traversal prevention
|
|
65
|
+
- **Capability scoping** -- Enable/disable tool groups (zip, blockchain, readonly)
|
|
66
|
+
- **Rate limiting** -- Token-bucket rate limiting per tool
|
|
67
|
+
- **Resource limiting** -- Max file size, entry count, and operation timeouts
|
|
68
|
+
- **Authentication** -- Wallet key sourcing and optional API key
|
|
69
|
+
|
|
70
|
+
## Installation
|
|
71
|
+
|
|
72
|
+
### Prerequisites
|
|
73
|
+
|
|
74
|
+
- Node.js 20.0.0 or higher
|
|
75
|
+
- npm or pnpm
|
|
76
|
+
|
|
77
|
+
### Install from npm (beta)
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm install -g neozip-mcp@beta
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
After installation:
|
|
84
|
+
|
|
85
|
+
| Command | Purpose |
|
|
86
|
+
|---------|---------|
|
|
87
|
+
| `neozip-mcp` | MCP server (your host spawns this) |
|
|
88
|
+
| `neozip-connect` | Interactive account setup |
|
|
89
|
+
|
|
90
|
+
### Verify installation
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
which neozip-mcp
|
|
94
|
+
which neozip-connect
|
|
95
|
+
neozip-connect status
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Install in MCP hosts
|
|
99
|
+
|
|
100
|
+
| Host | Guide |
|
|
101
|
+
|------|-------|
|
|
102
|
+
| **Claude Code** (user/local scope) | [docs/installation-guides/INSTALL_CLAUDE_CODE.md](docs/installation-guides/INSTALL_CLAUDE_CODE.md) |
|
|
103
|
+
| **Claude Code workspace** (project `.mcp.json`) | [docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md](docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md) |
|
|
104
|
+
| **Cursor** | Quick start below |
|
|
105
|
+
|
|
106
|
+
Full index: [docs/installation-guides/README.md](docs/installation-guides/README.md)
|
|
107
|
+
|
|
108
|
+
## Claude Code setup
|
|
109
|
+
|
|
110
|
+
1. Install from npm (see above).
|
|
111
|
+
2. Register MCP — user scope (all projects):
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
claude mcp add-json neozip-mcp \
|
|
115
|
+
'{"type":"stdio","command":"neozip-mcp","env":{"NEOZIP_MCP_SANDBOX_PATHS":"${CLAUDE_PROJECT_DIR:-.},${HOME}"}}' \
|
|
116
|
+
--scope user
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
For team repos, copy [`docs/examples/mcp.json.claude.example`](docs/examples/mcp.json.claude.example) to `.mcp.json` — see [INSTALL_CLAUDE_WORKSPACE.md](docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md).
|
|
120
|
+
|
|
121
|
+
3. **Agent skills (recommended)** — copy from the package:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pkg="$(npm root -g)/neozip-mcp"
|
|
125
|
+
mkdir -p ~/.claude/skills/neozip-mcp ~/.claude/skills/neozip-notarization
|
|
126
|
+
cp "$pkg/docs/examples/claude/skills/neozip-mcp/SKILL.md" ~/.claude/skills/neozip-mcp/
|
|
127
|
+
cp "$pkg/docs/examples/claude/skills/neozip-notarization/SKILL.md" ~/.claude/skills/neozip-notarization/
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Workspace teams: `cp -R node_modules/neozip-mcp/docs/examples/claude/skills .claude/` and commit.
|
|
131
|
+
|
|
132
|
+
4. Optional always-on memory: copy [`docs/examples/CLAUDE.md.example`](docs/examples/CLAUDE.md.example) to `CLAUDE.md`.
|
|
133
|
+
|
|
134
|
+
5. For tokenize/timestamp/encryption: run **`neozip-connect`** once, then start a new Claude Code session.
|
|
135
|
+
|
|
136
|
+
Full guide: [docs/installation-guides/INSTALL_CLAUDE_CODE.md](docs/installation-guides/INSTALL_CLAUDE_CODE.md)
|
|
137
|
+
|
|
138
|
+
## Cursor setup
|
|
139
|
+
|
|
140
|
+
1. Install from npm (see above).
|
|
141
|
+
2. Copy [`.cursor/mcp.json.global.example`](.cursor/mcp.json.global.example) to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in your project).
|
|
142
|
+
3. Optional agent steering (pick one):
|
|
143
|
+
- **Skills:** copy [`docs/examples/claude/skills/neozip-mcp/`](docs/examples/claude/skills/neozip-mcp/) to `~/.cursor/skills/neozip-mcp/` (archives), and [`docs/examples/claude/skills/neozip-notarization/`](docs/examples/claude/skills/neozip-notarization/) to `~/.cursor/skills/neozip-notarization/` (tokenize/timestamp/verify + recipient encryption)
|
|
144
|
+
- **Cursor rule:** copy [docs/examples/neozip-mcp-cursor-rule.mdc](docs/examples/neozip-mcp-cursor-rule.mdc) to `~/.cursor/rules/neozip-mcp.mdc`
|
|
145
|
+
4. For tokenize/timestamp/encryption: run **`neozip-connect`** once, then reload MCP in Cursor Settings.
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"mcpServers": {
|
|
150
|
+
"neozip-mcp": {
|
|
151
|
+
"command": "neozip-mcp",
|
|
152
|
+
"env": {
|
|
153
|
+
"NEOZIP_MCP_SANDBOX_PATHS": "${workspaceFolder},${userHome}"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Capabilities default to **`auto`**: `zip,blockchain,readonly` after `neozip-connect` reaches `phase: ready`, otherwise `zip,readonly`. Set `NEOZIP_MCP_CAPABILITIES` explicitly to override (e.g. `zip` for ZIP-only). See [docs/OPERATIONS.md](docs/OPERATIONS.md) for every tool and option.
|
|
161
|
+
|
|
162
|
+
Connection secrets use **machine-local encryption** in `~/.neozip/connection/`. Optionally set `NEOZIP_UNLOCK_PASSPHRASE` if you use a custom passphrase.
|
|
163
|
+
|
|
164
|
+
## Configuration
|
|
165
|
+
|
|
166
|
+
### Environment Variables
|
|
167
|
+
|
|
168
|
+
| Variable | Default | Description |
|
|
169
|
+
|----------|---------|-------------|
|
|
170
|
+
| `NEOZIP_MCP_CAPABILITIES` | `auto` | Tool groups: `zip`, `blockchain`, `readonly`, `account`, or `auto` (default). `auto` → `zip,blockchain,readonly` when connect is `phase: ready` with a valid token; otherwise `zip,readonly` |
|
|
171
|
+
| `NEOZIP_MCP_REQUIRE_ACCOUNT` | on when `account` or `blockchain` cap | Exit at startup if connection not `phase: ready` or token expired (`false` to disable) |
|
|
172
|
+
| `NEOZIP_UNLOCK_PASSPHRASE` | machine-local key | Optional custom passphrase for `~/.neozip/connection/` (default: hostname + username on this machine) |
|
|
173
|
+
| `NEOZIP_MCP_STARTUP_SUMMARY` | on | Log wallet/account summary to stderr on start |
|
|
174
|
+
| `NEOZIP_MCP_SANDBOX_PATHS` | cwd, home | Comma-separated allowed directories |
|
|
175
|
+
| `NEOZIP_MCP_RATE_LIMIT` | `60` | Requests per minute (ZIP tools) |
|
|
176
|
+
| `NEOZIP_MCP_BLOCKCHAIN_RATE_LIMIT` | `10` | Requests per minute (blockchain tools) |
|
|
177
|
+
| `NEOZIP_MCP_MAX_FILE_SIZE` | `524288000` | Max file size in bytes (500 MB) |
|
|
178
|
+
| `NEOZIP_MCP_MAX_ENTRIES` | `10000` | Max ZIP entries |
|
|
179
|
+
| `NEOZIP_MCP_TIMEOUT` | `300` | Operation timeout in seconds |
|
|
180
|
+
| `NEOZIP_MCP_DEFAULT_MAX_CHARS` | `10000` | Default read size for `read_entry` |
|
|
181
|
+
| `NEOZIP_MCP_MAX_READ_CHARS` | `100000` | Hard cap on `read_entry` output |
|
|
182
|
+
| `NEOZIP_MCP_GREP_MAX_MATCHES` | `100` | Default max matches for `grep_entries` |
|
|
183
|
+
| `NEOZIP_MCP_GREP_MAX_SNIPPET_CHARS` | `200` | Max snippet length per grep match |
|
|
184
|
+
| `NEOZIP_MCP_GREP_MAX_FILE_BYTES` | `1048576` | Skip grepping entries larger than this (bytes) |
|
|
185
|
+
| `NEOZIP_MCP_API_KEY` | -- | Optional API key for access control |
|
|
186
|
+
| `NEOZIP_NETWORK` | `base-sepolia` | Blockchain network for tokenize/mint |
|
|
187
|
+
| `NEOZIP_TOKEN_SERVICE_INFO_URL` | `{profile URL}/info` | Link shown when Token Service setup is required |
|
|
188
|
+
| `NEOZIP_IDENTITY_PRIVATE_KEY_HEX` | -- | Optional X25519 private key (hex) for opening recipient-encrypted archives (MCP env only) |
|
|
189
|
+
|
|
190
|
+
Token Service email, access token, wallet key, and service URL come from **`neozip-connect`** (`~/.neozip/connection/`), not MCP env or NeoZip Desktop `wallet.json`.
|
|
191
|
+
|
|
192
|
+
## Documentation
|
|
193
|
+
|
|
194
|
+
The following documentation is included with this package:
|
|
195
|
+
|
|
196
|
+
- **[README.md](README.md)** — Installation, MCP host setup, configuration
|
|
197
|
+
- **[DOCUMENTATION.md](DOCUMENTATION.md)** — Documentation index
|
|
198
|
+
- **[CHANGELOG.md](CHANGELOG.md)** — Version history
|
|
199
|
+
- **[SECURITY.md](SECURITY.md)** — Security considerations
|
|
200
|
+
- **[docs/OPERATIONS.md](docs/OPERATIONS.md)** — Full MCP tool reference
|
|
201
|
+
|
|
202
|
+
## Publishing (npm)
|
|
203
|
+
|
|
204
|
+
The published tarball includes **`dist/`**, **`docs/`**, **`README.md`**, **`LICENSE`**, **`CHANGELOG.md`**, **`DOCUMENTATION.md`**, and **`SECURITY.md`** only. Preview with **`pnpm pack:dry-run`**.
|
|
205
|
+
|
|
206
|
+
Maintainers: see the [PUBLISHING.md](https://github.com/NeoWareInc/neozip-mcp/blob/main/docs-dev/PUBLISHING.md) guide in the GitHub repository.
|
|
207
|
+
|
|
208
|
+
## Contributing
|
|
209
|
+
|
|
210
|
+
We welcome feedback and bug reports:
|
|
211
|
+
|
|
212
|
+
1. **Report issues:** [GitHub Issues](https://github.com/NeoWareInc/neozip-support/issues) or [support@neozip.io](mailto:support@neozip.io)
|
|
213
|
+
2. **Test and provide feedback:** Help us improve by testing in your MCP host
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
Proprietary — NeoWare, Inc. All rights reserved. See [LICENSE](LICENSE).
|
|
218
|
+
|
|
219
|
+
## Support
|
|
220
|
+
|
|
221
|
+
- **GitHub Issues:** [NeoWareInc/neozip-support](https://github.com/NeoWareInc/neozip-support/issues)
|
|
222
|
+
- **Email:** [support@neozip.io](mailto:support@neozip.io)
|
|
223
|
+
- **Documentation:** [DOCUMENTATION.md](DOCUMENTATION.md)
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
Security considerations for **neozip-mcp** and how to report vulnerabilities.
|
|
4
|
+
|
|
5
|
+
## Scope of this package
|
|
6
|
+
|
|
7
|
+
**neozip-mcp** is a local MCP (stdio) server. It reads and writes ZIP archives within configured sandbox paths, optionally talks to the NeoZip Token Service and Base network, and stores account credentials in `~/.neozip/connection/` (machine-local encryption).
|
|
8
|
+
|
|
9
|
+
ZIP format handling uses [neozipkit](https://www.npmjs.com/package/neozipkit). On-chain operations use [neozip-blockchain](https://www.npmjs.com/package/neozip-blockchain). See those packages for library-level crypto and archive security.
|
|
10
|
+
|
|
11
|
+
## MCP host configuration
|
|
12
|
+
|
|
13
|
+
- **Sandbox paths** — Set `NEOZIP_MCP_SANDBOX_PATHS` to the smallest directory set the agent needs. The server rejects paths outside the allowlist.
|
|
14
|
+
- **Capabilities** — Default `auto` enables blockchain tools only after `neozip-connect` reaches `phase: ready`. Use `NEOZIP_MCP_CAPABILITIES=zip,readonly` for ZIP-only hosts.
|
|
15
|
+
- **Secrets in env** — Do not put wallet keys, Token Service tokens, or archive passwords in MCP `env` blocks committed to git. Use `neozip-connect` for account secrets; pass archive passwords per tool call when needed.
|
|
16
|
+
|
|
17
|
+
## Connection store
|
|
18
|
+
|
|
19
|
+
- Credentials live under `~/.neozip/connection/` and are encrypted with a machine-local key (hostname + username by default, or `NEOZIP_UNLOCK_PASSPHRASE`).
|
|
20
|
+
- Treat this directory like SSH keys: restrict filesystem permissions and do not copy it to shared machines without understanding the risk.
|
|
21
|
+
|
|
22
|
+
## General practices
|
|
23
|
+
|
|
24
|
+
- **Dependencies** — Run `pnpm audit` (or `npm audit`) before release; address high/critical issues.
|
|
25
|
+
- **Published tarball** — Recipient encryption code is bundled into `dist/vendor/neozipkit-pro.js` at build time; the published package does not require `@neowareinc/neozipkit-pro` at install time.
|
|
26
|
+
- **Inputs** — The server validates paths via `PathSandbox`; still avoid pointing sandbox paths at sensitive system directories unless required.
|
|
27
|
+
|
|
28
|
+
## Reporting a vulnerability
|
|
29
|
+
|
|
30
|
+
1. **Do not** open a public GitHub issue for security bugs.
|
|
31
|
+
2. Report privately via [GitHub Security Advisories](https://github.com/NeoWareInc/neozip-mcp/security/advisories) for this repository, or email [support@neozip.io](mailto:support@neozip.io).
|
|
32
|
+
3. Allow time for a fix before public disclosure.
|
|
33
|
+
|
|
34
|
+
## References
|
|
35
|
+
|
|
36
|
+
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
|
37
|
+
- [Model Context Protocol security best practices](https://modelcontextprotocol.io/)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { getTokenServiceUrl } from "neozip-blockchain/token-service";
|
|
2
|
+
import { maskEmail } from "../util/mask.js";
|
|
3
|
+
import { getActiveProfile, getActiveProfileId, listProfiles, readActiveSecrets, } from "./profile-store.js";
|
|
4
|
+
import { fetchCoordinatorConfig } from "./token-service-identity.js";
|
|
5
|
+
function nextStepsForPhase(phase) {
|
|
6
|
+
switch (phase) {
|
|
7
|
+
case "no_profile":
|
|
8
|
+
return listProfiles().length > 0
|
|
9
|
+
? ["account_select", "account_list", "account_create"]
|
|
10
|
+
: ["account_create", "account_list"];
|
|
11
|
+
case "email_unverified":
|
|
12
|
+
return ["account_register_email", "account_verify_email"];
|
|
13
|
+
case "no_wallet":
|
|
14
|
+
return ["account_create_wallet", "account_import_wallet"];
|
|
15
|
+
case "wallet_unlinked":
|
|
16
|
+
return ["account_link_wallet"];
|
|
17
|
+
case "identity_missing":
|
|
18
|
+
return ["account_provision_identity"];
|
|
19
|
+
case "ready":
|
|
20
|
+
return ["account_logout"];
|
|
21
|
+
case "degraded":
|
|
22
|
+
return ["account_status"];
|
|
23
|
+
default:
|
|
24
|
+
return ["account_status"];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function computeAccountPhase() {
|
|
28
|
+
const profileId = getActiveProfileId();
|
|
29
|
+
if (!profileId) {
|
|
30
|
+
return "no_profile";
|
|
31
|
+
}
|
|
32
|
+
const profile = getActiveProfile();
|
|
33
|
+
const secrets = readActiveSecrets();
|
|
34
|
+
if (!profile || !secrets)
|
|
35
|
+
return "no_profile";
|
|
36
|
+
if (!secrets.accessToken || !profile.emailVerified) {
|
|
37
|
+
return "email_unverified";
|
|
38
|
+
}
|
|
39
|
+
if (!secrets.evmPrivateKey || !profile.evmAddress) {
|
|
40
|
+
return "no_wallet";
|
|
41
|
+
}
|
|
42
|
+
if (!profile.walletId || profile.linkId == null) {
|
|
43
|
+
return "wallet_unlinked";
|
|
44
|
+
}
|
|
45
|
+
if (!profile.identityKeyId) {
|
|
46
|
+
return "identity_missing";
|
|
47
|
+
}
|
|
48
|
+
return "ready";
|
|
49
|
+
}
|
|
50
|
+
export async function buildAccountStatusReport(options) {
|
|
51
|
+
const profile = getActiveProfile();
|
|
52
|
+
const phase = computeAccountPhase();
|
|
53
|
+
const tokenServiceUrl = getTokenServiceUrl({
|
|
54
|
+
serverUrl: profile?.tokenServiceUrl || process.env.TOKEN_SERVICE_URL || undefined,
|
|
55
|
+
});
|
|
56
|
+
let tokenServiceReachable = null;
|
|
57
|
+
if (options?.probeTokenService !== false) {
|
|
58
|
+
try {
|
|
59
|
+
tokenServiceReachable = await fetchCoordinatorConfig(tokenServiceUrl);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
tokenServiceReachable = false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const nextSteps = nextStepsForPhase(tokenServiceReachable === false && phase !== "ready" ? "degraded" : phase);
|
|
66
|
+
const reloadRequired = phase === "ready" &&
|
|
67
|
+
Boolean(profile &&
|
|
68
|
+
(!process.env.NEOZIP_TOKEN_SERVICE_ACCESS_TOKEN ||
|
|
69
|
+
!process.env.NEOZIP_WALLET_PASSKEY));
|
|
70
|
+
return {
|
|
71
|
+
success: true,
|
|
72
|
+
phase: tokenServiceReachable === false && phase !== "ready" ? "degraded" : phase,
|
|
73
|
+
activeProfileId: getActiveProfileId(),
|
|
74
|
+
profile: profile
|
|
75
|
+
? {
|
|
76
|
+
...profile,
|
|
77
|
+
email: profile.email ? maskEmail(profile.email) : null,
|
|
78
|
+
}
|
|
79
|
+
: null,
|
|
80
|
+
tokenServiceReachable,
|
|
81
|
+
tokenServiceUrl,
|
|
82
|
+
nextSteps,
|
|
83
|
+
reloadRequired,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=account-state.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function formatAccountStatusText(report) {
|
|
2
|
+
const lines = [];
|
|
3
|
+
lines.push("NeoZip account status");
|
|
4
|
+
lines.push(`Phase: ${report.phase}`);
|
|
5
|
+
lines.push(`Token Service: ${report.tokenServiceUrl}`);
|
|
6
|
+
if (report.tokenServiceReachable != null) {
|
|
7
|
+
lines.push(`Token Service reachable: ${report.tokenServiceReachable ? "yes" : "no"}`);
|
|
8
|
+
}
|
|
9
|
+
if (report.activeProfileId) {
|
|
10
|
+
lines.push(`Active profile: ${report.activeProfileId}`);
|
|
11
|
+
}
|
|
12
|
+
if (report.profile) {
|
|
13
|
+
lines.push(`Label: ${report.profile.label}`);
|
|
14
|
+
if (report.profile.email)
|
|
15
|
+
lines.push(`Email: ${report.profile.email}`);
|
|
16
|
+
if (report.profile.evmAddress) {
|
|
17
|
+
lines.push(`EVM address: ${report.profile.evmAddress}`);
|
|
18
|
+
}
|
|
19
|
+
if (report.profile.walletId != null) {
|
|
20
|
+
lines.push(`Wallet ID: ${report.profile.walletId}`);
|
|
21
|
+
}
|
|
22
|
+
if (report.profile.identityKeyId != null) {
|
|
23
|
+
lines.push(`Identity key ID: ${report.profile.identityKeyId}`);
|
|
24
|
+
}
|
|
25
|
+
if (report.profile.x25519Fingerprint) {
|
|
26
|
+
lines.push(`X25519 fingerprint: ${report.profile.x25519Fingerprint}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (report.nextSteps.length) {
|
|
30
|
+
lines.push(`Next steps: ${report.nextSteps.join(", ")}`);
|
|
31
|
+
}
|
|
32
|
+
if (report.reloadRequired) {
|
|
33
|
+
lines.push("Reload MCP in Cursor so the active connection credentials are loaded into this session.");
|
|
34
|
+
}
|
|
35
|
+
return lines.join("\n");
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=format-account-status.js.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { IdentityKeyTamperError } from "../archive/identity-key.js";
|
|
2
|
+
import { fetchCryptoSelf } from "../archive/crypto-self.js";
|
|
3
|
+
import { buildIdentityKeyInitMessage, wrapNewX25519Keypair, } from "./identity-wrap.js";
|
|
4
|
+
import { IdentityKeyConflictError, completeIdentityKeyInit, getIdentityKeyBundle, requestIdentityKeyInitChallenge, } from "./token-service-identity.js";
|
|
5
|
+
import { rawEoaBytes, signEvmMessage } from "./wallet-evm.js";
|
|
6
|
+
export async function provisionWalletIdentityKey(params) {
|
|
7
|
+
const existing = await getIdentityKeyBundle(params.baseUrl, params.accessToken, params.walletId);
|
|
8
|
+
if (existing.found) {
|
|
9
|
+
return {
|
|
10
|
+
identityKeyId: existing.identityKeyId,
|
|
11
|
+
x25519PublicKey: existing.x25519PublicKey,
|
|
12
|
+
provisioned: false,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const eoaPriv = rawEoaBytes(params.evmPrivateKey);
|
|
16
|
+
try {
|
|
17
|
+
const wrap = wrapNewX25519Keypair({
|
|
18
|
+
rawEoaPrivBytes: eoaPriv,
|
|
19
|
+
evmAddress: params.evmAddress,
|
|
20
|
+
});
|
|
21
|
+
const bundleBody = {
|
|
22
|
+
x25519PublicKeyB64: wrap.x25519PublicKeyB64,
|
|
23
|
+
...wrap.bundle,
|
|
24
|
+
};
|
|
25
|
+
const challenge = await requestIdentityKeyInitChallenge(params.baseUrl, params.accessToken, params.walletId, bundleBody);
|
|
26
|
+
const expectedMessage = buildIdentityKeyInitMessage({
|
|
27
|
+
walletId: params.walletId,
|
|
28
|
+
challengeId: challenge.challengeId,
|
|
29
|
+
evmAddress: params.evmAddress,
|
|
30
|
+
formatVersion: wrap.bundle.wrapFormatVersion,
|
|
31
|
+
x25519PublicKeyB64: wrap.x25519PublicKeyB64,
|
|
32
|
+
wrappedSha256Hex: wrap.wrappedSha256Hex,
|
|
33
|
+
});
|
|
34
|
+
if (challenge.message !== expectedMessage) {
|
|
35
|
+
throw new IdentityKeyTamperError("Server init message does not match canonical form expected by this client.");
|
|
36
|
+
}
|
|
37
|
+
const evmSignature = await signEvmMessage(params.evmPrivateKey, challenge.message);
|
|
38
|
+
try {
|
|
39
|
+
const completed = await completeIdentityKeyInit(params.baseUrl, params.accessToken, params.walletId, bundleBody, challenge.challengeId, evmSignature);
|
|
40
|
+
return {
|
|
41
|
+
identityKeyId: completed.identityKeyId,
|
|
42
|
+
x25519PublicKey: completed.x25519PublicKey,
|
|
43
|
+
provisioned: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
if (err instanceof IdentityKeyConflictError) {
|
|
48
|
+
const reloaded = await getIdentityKeyBundle(params.baseUrl, params.accessToken, params.walletId);
|
|
49
|
+
if (reloaded.found) {
|
|
50
|
+
return {
|
|
51
|
+
identityKeyId: reloaded.identityKeyId,
|
|
52
|
+
x25519PublicKey: reloaded.x25519PublicKey,
|
|
53
|
+
provisioned: false,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
eoaPriv.fill(0);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Sync profile metadata with live /crypto/self when token is available. */
|
|
65
|
+
export async function refreshIdentityFromCryptoSelf(config) {
|
|
66
|
+
const self = await fetchCryptoSelf(config);
|
|
67
|
+
if (!self.ok) {
|
|
68
|
+
return { identityKeyId: null, walletId: null };
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
identityKeyId: self.data.identityKeyId,
|
|
72
|
+
walletId: self.data.walletId,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=identity-provision.js.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
import { WRAP_AEAD, WRAP_FORMAT_VERSION, WRAP_IV_LEN, WRAP_KDF_INFO, WRAP_KDF_SALT_LEN, } from "../constants/wallet-identity.js";
|
|
3
|
+
function buildCanonicalAad(params) {
|
|
4
|
+
const lowerAddr = params.evmAddress.toLowerCase();
|
|
5
|
+
const addrBytes = Buffer.from(lowerAddr, "ascii");
|
|
6
|
+
return Buffer.concat([
|
|
7
|
+
addrBytes,
|
|
8
|
+
Buffer.from([WRAP_FORMAT_VERSION]),
|
|
9
|
+
params.x25519SpkiDer,
|
|
10
|
+
]);
|
|
11
|
+
}
|
|
12
|
+
function deriveKek(rawEoaPrivBytes, saltB64) {
|
|
13
|
+
const salt = Buffer.from(saltB64, "base64");
|
|
14
|
+
if (salt.length !== WRAP_KDF_SALT_LEN) {
|
|
15
|
+
throw new Error(`Wrap KDF salt must be ${WRAP_KDF_SALT_LEN} bytes`);
|
|
16
|
+
}
|
|
17
|
+
return Buffer.from(crypto.hkdfSync("sha256", rawEoaPrivBytes, salt, WRAP_KDF_INFO, 32));
|
|
18
|
+
}
|
|
19
|
+
function sha256Hex(buf) {
|
|
20
|
+
return crypto.createHash("sha256").update(buf).digest("hex");
|
|
21
|
+
}
|
|
22
|
+
export function buildIdentityKeyInitMessage(params) {
|
|
23
|
+
return [
|
|
24
|
+
"NeoZip Token Service identity key init",
|
|
25
|
+
`walletId:${params.walletId}`,
|
|
26
|
+
`challenge:${params.challengeId}`,
|
|
27
|
+
`address:${params.evmAddress.toLowerCase()}`,
|
|
28
|
+
`formatVersion:${params.formatVersion}`,
|
|
29
|
+
`x25519:${params.x25519PublicKeyB64}`,
|
|
30
|
+
`wrappedSha256:${params.wrappedSha256Hex}`,
|
|
31
|
+
].join("\n");
|
|
32
|
+
}
|
|
33
|
+
export function wrapNewX25519Keypair(params) {
|
|
34
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("x25519");
|
|
35
|
+
const spkiDer = publicKey.export({ type: "spki", format: "der" });
|
|
36
|
+
const pkcs8Der = privateKey.export({ type: "pkcs8", format: "der" });
|
|
37
|
+
const rawPriv = pkcs8Der.subarray(pkcs8Der.length - 32);
|
|
38
|
+
const saltB64 = crypto.randomBytes(WRAP_KDF_SALT_LEN).toString("base64");
|
|
39
|
+
const ivB64 = crypto.randomBytes(WRAP_IV_LEN).toString("base64");
|
|
40
|
+
const aad = buildCanonicalAad({
|
|
41
|
+
evmAddress: params.evmAddress,
|
|
42
|
+
x25519SpkiDer: spkiDer,
|
|
43
|
+
});
|
|
44
|
+
const kek = deriveKek(params.rawEoaPrivBytes, saltB64);
|
|
45
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
46
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", kek, iv);
|
|
47
|
+
cipher.setAAD(aad);
|
|
48
|
+
const ct = Buffer.concat([cipher.update(rawPriv), cipher.final()]);
|
|
49
|
+
const tag = cipher.getAuthTag();
|
|
50
|
+
const wrapped = Buffer.concat([ct, tag]);
|
|
51
|
+
kek.fill(0);
|
|
52
|
+
rawPriv.fill(0);
|
|
53
|
+
pkcs8Der.fill(0);
|
|
54
|
+
const bundle = {
|
|
55
|
+
wrappedPrivateKeyB64: wrapped.toString("base64"),
|
|
56
|
+
wrapFormatVersion: WRAP_FORMAT_VERSION,
|
|
57
|
+
wrapKdfInfo: WRAP_KDF_INFO,
|
|
58
|
+
wrapKdfSaltB64: saltB64,
|
|
59
|
+
wrapAead: WRAP_AEAD,
|
|
60
|
+
wrapIvB64: ivB64,
|
|
61
|
+
wrapAadB64: aad.toString("base64"),
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
bundle,
|
|
65
|
+
x25519PublicKeyB64: spkiDer.toString("base64"),
|
|
66
|
+
wrappedSha256Hex: sha256Hex(wrapped),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=identity-wrap.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
const PROFILE_KDF_INFO = "NeoZip/McpProfileSecrets/v1";
|
|
4
|
+
const PROFILE_KDF_SALT = Buffer.from("NeoZipMcpProfileStoreSalt-v1", "utf8");
|
|
5
|
+
export function deriveProfileKey() {
|
|
6
|
+
const passphrase = process.env.NEOZIP_UNLOCK_PASSPHRASE?.trim() ||
|
|
7
|
+
`${os.hostname()}:${os.userInfo().username}:neozip-mcp-profile`;
|
|
8
|
+
const okm = crypto.hkdfSync("sha256", Buffer.from(passphrase, "utf8"), PROFILE_KDF_SALT, PROFILE_KDF_INFO, 32);
|
|
9
|
+
return Buffer.from(okm);
|
|
10
|
+
}
|
|
11
|
+
export function encryptJson(payload) {
|
|
12
|
+
const key = deriveProfileKey();
|
|
13
|
+
const iv = crypto.randomBytes(12);
|
|
14
|
+
const plaintext = Buffer.from(JSON.stringify(payload), "utf8");
|
|
15
|
+
try {
|
|
16
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
|
17
|
+
const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
18
|
+
const tag = cipher.getAuthTag();
|
|
19
|
+
return JSON.stringify({
|
|
20
|
+
v: 1,
|
|
21
|
+
iv: iv.toString("base64"),
|
|
22
|
+
tag: tag.toString("base64"),
|
|
23
|
+
data: ct.toString("base64"),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
key.fill(0);
|
|
28
|
+
plaintext.fill(0);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function decryptJson(encrypted) {
|
|
32
|
+
const key = deriveProfileKey();
|
|
33
|
+
const parsed = JSON.parse(encrypted);
|
|
34
|
+
const iv = Buffer.from(parsed.iv, "base64");
|
|
35
|
+
const tag = Buffer.from(parsed.tag, "base64");
|
|
36
|
+
const ct = Buffer.from(parsed.data, "base64");
|
|
37
|
+
try {
|
|
38
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
|
|
39
|
+
decipher.setAuthTag(tag);
|
|
40
|
+
const pt = Buffer.concat([decipher.update(ct), decipher.final()]);
|
|
41
|
+
return JSON.parse(pt.toString("utf8"));
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
key.fill(0);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=profile-crypto.js.map
|