neozip-cli 0.90.0 → 0.95.1
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/AGENTS.md +93 -0
- package/CHANGELOG.md +70 -1
- package/DOCUMENTATION.md +22 -30
- package/README.md +214 -48
- package/dist/src/account/account-state.js +95 -0
- package/dist/src/account/format-account-status.js +62 -0
- package/dist/src/account/identity-provision.js +79 -0
- package/dist/src/account/identity-wrap.js +106 -0
- package/dist/src/account/profile-crypto.js +85 -0
- package/dist/src/account/profile-store.js +129 -0
- package/dist/src/account/require-account.js +32 -0
- package/dist/src/account/token-service-funding.js +151 -0
- package/dist/src/account/token-service-identity.js +488 -0
- package/dist/src/account/types.js +3 -0
- package/dist/src/account/wallet-evm.js +46 -0
- package/dist/src/account/wallet-setup.js +33 -0
- package/dist/src/archive/crypto-self.js +117 -0
- package/dist/src/archive/identity-key.js +217 -0
- package/dist/src/archive/recipient-lookup.js +61 -0
- package/dist/src/cli/output.js +100 -0
- package/dist/src/cli/params.js +122 -0
- package/dist/src/cli/schema.js +186 -0
- package/dist/src/cli/validate.js +119 -0
- package/dist/src/commands/mintTimestampProof.js +26 -14
- package/dist/src/commands/verifyEmail.js +9 -9
- package/dist/src/config/ConfigSetup.js +82 -423
- package/dist/src/config/ConfigStore.js +0 -33
- package/dist/src/connect/command.js +364 -0
- package/dist/src/connection/bootstrap.js +50 -0
- package/dist/src/connection/cli-guidance.js +101 -0
- package/dist/src/connection/cli-prefs.js +180 -0
- package/dist/src/connection/cli-settings.js +140 -0
- package/dist/src/connection/cli-types.js +14 -0
- package/dist/src/connection/coordinator.js +83 -0
- package/dist/src/connection/credentials.js +33 -0
- package/dist/src/connection/crypto.js +96 -0
- package/dist/src/connection/dump.js +117 -0
- package/dist/src/connection/funding.js +187 -0
- package/dist/src/connection/incomplete-setup.js +89 -0
- package/dist/src/connection/interactive.js +871 -0
- package/dist/src/connection/legacy-profile-reader.js +87 -0
- package/dist/src/connection/magic-link.js +142 -0
- package/dist/src/connection/migrate.js +115 -0
- package/dist/src/connection/onboarding.js +616 -0
- package/dist/src/connection/origin.js +69 -0
- package/dist/src/connection/phase.js +101 -0
- package/dist/src/connection/phone.js +26 -0
- package/dist/src/connection/promote-active.js +56 -0
- package/dist/src/connection/reset.js +56 -0
- package/dist/src/connection/status-report.js +52 -0
- package/dist/src/connection/store.js +406 -0
- package/dist/src/connection/token-auth.js +44 -0
- package/dist/src/connection/types.js +3 -0
- package/dist/src/connection/wallet-json-migration.js +155 -0
- package/dist/src/connection/wallet-login.js +65 -0
- package/dist/src/connection/wallet-setup.js +83 -0
- package/dist/src/constants/wallet-identity.js +14 -0
- package/dist/src/exit-codes.js +54 -10
- package/dist/src/neolist.js +93 -9
- package/dist/src/neounzip.js +217 -59
- package/dist/src/neozip/blockchain.js +18 -18
- package/dist/src/neozip/createZip.js +114 -91
- package/dist/src/neozip/upgradeZip.js +14 -11
- package/dist/src/neozip.js +252 -75
- package/dist/src/skills/command.js +256 -0
- package/dist/src/skills/locate.js +99 -0
- package/dist/src/util/mask.js +34 -0
- package/dist/src/util/token-service-fetch.js +26 -0
- package/env.example +18 -85
- package/package.json +89 -82
- package/skills/neozip-connect/SKILL.md +95 -0
- package/skills/neozip-create/SKILL.md +57 -0
- package/skills/neozip-extract/SKILL.md +58 -0
- package/skills/neozip-legacy/SKILL.md +48 -0
- package/skills/neozip-list/SKILL.md +56 -0
- package/skills/neozip-shared/SKILL.md +60 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.computeAccountPhase = computeAccountPhase;
|
|
4
|
+
exports.buildAccountStatusReport = buildAccountStatusReport;
|
|
5
|
+
const token_service_1 = require("neozip-blockchain/token-service");
|
|
6
|
+
const mask_1 = require("../util/mask");
|
|
7
|
+
const profile_store_1 = require("./profile-store");
|
|
8
|
+
const token_auth_1 = require("../connection/token-auth");
|
|
9
|
+
function nextStepsForPhase(phase) {
|
|
10
|
+
switch (phase) {
|
|
11
|
+
case "no_profile":
|
|
12
|
+
return (0, profile_store_1.listProfiles)().length > 0
|
|
13
|
+
? ["account_select", "account_list", "account_create"]
|
|
14
|
+
: ["account_create", "account_list"];
|
|
15
|
+
case "email_unverified":
|
|
16
|
+
return ["account_register_email", "account_verify_email"];
|
|
17
|
+
case "no_wallet":
|
|
18
|
+
return ["account_create_wallet", "account_import_wallet"];
|
|
19
|
+
case "wallet_unlinked":
|
|
20
|
+
return ["account_link_wallet"];
|
|
21
|
+
case "identity_missing":
|
|
22
|
+
return ["account_provision_identity"];
|
|
23
|
+
case "ready":
|
|
24
|
+
return ["account_logout"];
|
|
25
|
+
case "degraded":
|
|
26
|
+
return ["account_status"];
|
|
27
|
+
default:
|
|
28
|
+
return ["account_status"];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function computeAccountPhase() {
|
|
32
|
+
const profileId = (0, profile_store_1.getActiveProfileId)();
|
|
33
|
+
if (!profileId) {
|
|
34
|
+
return "no_profile";
|
|
35
|
+
}
|
|
36
|
+
const profile = (0, profile_store_1.getActiveProfile)();
|
|
37
|
+
const secrets = (0, profile_store_1.readActiveSecrets)();
|
|
38
|
+
if (!profile || !secrets)
|
|
39
|
+
return "no_profile";
|
|
40
|
+
if (!secrets.accessToken || !profile.emailVerified) {
|
|
41
|
+
return "email_unverified";
|
|
42
|
+
}
|
|
43
|
+
if (!secrets.evmPrivateKey || !profile.evmAddress) {
|
|
44
|
+
return "no_wallet";
|
|
45
|
+
}
|
|
46
|
+
if (!profile.walletId || profile.linkId == null) {
|
|
47
|
+
return "wallet_unlinked";
|
|
48
|
+
}
|
|
49
|
+
if (!profile.identityKeyId) {
|
|
50
|
+
return "identity_missing";
|
|
51
|
+
}
|
|
52
|
+
return "ready";
|
|
53
|
+
}
|
|
54
|
+
async function buildAccountStatusReport(options) {
|
|
55
|
+
const profile = (0, profile_store_1.getActiveProfile)();
|
|
56
|
+
const secrets = (0, profile_store_1.readActiveSecrets)();
|
|
57
|
+
const phase = computeAccountPhase();
|
|
58
|
+
const tokenExpiresAt = secrets?.accessTokenExpiresAt ?? null;
|
|
59
|
+
const tokenExpired = Boolean(secrets?.accessToken) && (0, token_auth_1.isAccessTokenExpired)(secrets);
|
|
60
|
+
const tokenServiceUrl = (0, token_service_1.getTokenServiceUrl)({
|
|
61
|
+
serverUrl: profile?.tokenServiceUrl || undefined,
|
|
62
|
+
});
|
|
63
|
+
let tokenServiceReachable = null;
|
|
64
|
+
if (options?.probeTokenService !== false) {
|
|
65
|
+
try {
|
|
66
|
+
tokenServiceReachable = await (0, token_service_1.fetchCoordinatorConfig)(tokenServiceUrl);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
tokenServiceReachable = false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const nextSteps = nextStepsForPhase(tokenServiceReachable === false && phase !== "ready" ? "degraded" : phase);
|
|
73
|
+
const reloadRequired = phase === "ready" &&
|
|
74
|
+
Boolean(profile &&
|
|
75
|
+
(!process.env.NEOZIP_TOKEN_SERVICE_ACCESS_TOKEN ||
|
|
76
|
+
!process.env.NEOZIP_WALLET_PASSKEY));
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
phase: tokenServiceReachable === false && phase !== "ready" ? "degraded" : phase,
|
|
80
|
+
activeProfileId: (0, profile_store_1.getActiveProfileId)(),
|
|
81
|
+
profile: profile
|
|
82
|
+
? {
|
|
83
|
+
...profile,
|
|
84
|
+
email: profile.email ? (0, mask_1.maskEmail)(profile.email) : null,
|
|
85
|
+
}
|
|
86
|
+
: null,
|
|
87
|
+
tokenServiceReachable,
|
|
88
|
+
tokenServiceUrl,
|
|
89
|
+
tokenExpiresAt,
|
|
90
|
+
tokenExpired,
|
|
91
|
+
nextSteps,
|
|
92
|
+
reloadRequired,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=account-state.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatAccountStatusText = formatAccountStatusText;
|
|
4
|
+
function formatExpiry(expiresAt) {
|
|
5
|
+
const deltaMs = expiresAt - Date.now();
|
|
6
|
+
const abs = Math.abs(deltaMs);
|
|
7
|
+
const minutes = Math.round(abs / 60000);
|
|
8
|
+
const hours = Math.round(abs / 3600000);
|
|
9
|
+
const days = Math.round(abs / 86400000);
|
|
10
|
+
let rel;
|
|
11
|
+
if (abs < 3600000)
|
|
12
|
+
rel = `${minutes} min`;
|
|
13
|
+
else if (abs < 86400000)
|
|
14
|
+
rel = `${hours} hr`;
|
|
15
|
+
else
|
|
16
|
+
rel = `${days} day${days === 1 ? "" : "s"}`;
|
|
17
|
+
const when = new Date(expiresAt).toISOString();
|
|
18
|
+
return deltaMs >= 0 ? `in ${rel} (${when})` : `${rel} ago (${when})`;
|
|
19
|
+
}
|
|
20
|
+
function formatAccountStatusText(report) {
|
|
21
|
+
const lines = [];
|
|
22
|
+
lines.push("NeoZip account status");
|
|
23
|
+
lines.push(`Phase: ${report.phase}`);
|
|
24
|
+
lines.push(`Token Service: ${report.tokenServiceUrl}`);
|
|
25
|
+
if (report.tokenServiceReachable != null) {
|
|
26
|
+
lines.push(`Token Service reachable: ${report.tokenServiceReachable ? "yes" : "no"}`);
|
|
27
|
+
}
|
|
28
|
+
if (report.tokenExpired) {
|
|
29
|
+
lines.push("Access token: EXPIRED — run neozip connect refresh");
|
|
30
|
+
}
|
|
31
|
+
else if (report.tokenExpiresAt != null) {
|
|
32
|
+
lines.push(`Access token: valid (expires ${formatExpiry(report.tokenExpiresAt)})`);
|
|
33
|
+
}
|
|
34
|
+
if (report.activeProfileId) {
|
|
35
|
+
lines.push(`Active profile: ${report.activeProfileId}`);
|
|
36
|
+
}
|
|
37
|
+
if (report.profile) {
|
|
38
|
+
lines.push(`Label: ${report.profile.label}`);
|
|
39
|
+
if (report.profile.email)
|
|
40
|
+
lines.push(`Email: ${report.profile.email}`);
|
|
41
|
+
if (report.profile.evmAddress) {
|
|
42
|
+
lines.push(`EVM address: ${report.profile.evmAddress}`);
|
|
43
|
+
}
|
|
44
|
+
if (report.profile.walletId != null) {
|
|
45
|
+
lines.push(`Wallet ID: ${report.profile.walletId}`);
|
|
46
|
+
}
|
|
47
|
+
if (report.profile.identityKeyId != null) {
|
|
48
|
+
lines.push(`Identity key ID: ${report.profile.identityKeyId}`);
|
|
49
|
+
}
|
|
50
|
+
if (report.profile.x25519Fingerprint) {
|
|
51
|
+
lines.push(`X25519 fingerprint: ${report.profile.x25519Fingerprint}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (report.nextSteps.length) {
|
|
55
|
+
lines.push(`Next steps: ${report.nextSteps.join(", ")}`);
|
|
56
|
+
}
|
|
57
|
+
if (report.reloadRequired) {
|
|
58
|
+
lines.push("Reload MCP in Cursor so the active connection credentials are loaded into this session.");
|
|
59
|
+
}
|
|
60
|
+
return lines.join("\n");
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=format-account-status.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.provisionWalletIdentityKey = provisionWalletIdentityKey;
|
|
4
|
+
exports.refreshIdentityFromCryptoSelf = refreshIdentityFromCryptoSelf;
|
|
5
|
+
const identity_key_1 = require("../archive/identity-key");
|
|
6
|
+
const crypto_self_1 = require("../archive/crypto-self");
|
|
7
|
+
const identity_wrap_1 = require("./identity-wrap");
|
|
8
|
+
const token_service_1 = require("neozip-blockchain/token-service");
|
|
9
|
+
const wallet_evm_1 = require("./wallet-evm");
|
|
10
|
+
async function provisionWalletIdentityKey(params) {
|
|
11
|
+
const existing = await (0, token_service_1.getIdentityKeyBundle)(params.baseUrl, params.accessToken, params.walletId);
|
|
12
|
+
if (existing.found) {
|
|
13
|
+
return {
|
|
14
|
+
identityKeyId: existing.identityKeyId,
|
|
15
|
+
x25519PublicKey: existing.x25519PublicKey,
|
|
16
|
+
provisioned: false,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const eoaPriv = (0, wallet_evm_1.rawEoaBytes)(params.evmPrivateKey);
|
|
20
|
+
try {
|
|
21
|
+
const wrap = (0, identity_wrap_1.wrapNewX25519Keypair)({
|
|
22
|
+
rawEoaPrivBytes: eoaPriv,
|
|
23
|
+
evmAddress: params.evmAddress,
|
|
24
|
+
});
|
|
25
|
+
const bundleBody = {
|
|
26
|
+
x25519PublicKeyB64: wrap.x25519PublicKeyB64,
|
|
27
|
+
...wrap.bundle,
|
|
28
|
+
};
|
|
29
|
+
const challenge = await (0, token_service_1.requestIdentityKeyInitChallenge)(params.baseUrl, params.accessToken, params.walletId, bundleBody);
|
|
30
|
+
const expectedMessage = (0, identity_wrap_1.buildIdentityKeyInitMessage)({
|
|
31
|
+
walletId: params.walletId,
|
|
32
|
+
challengeId: challenge.challengeId,
|
|
33
|
+
evmAddress: params.evmAddress,
|
|
34
|
+
formatVersion: wrap.bundle.wrapFormatVersion,
|
|
35
|
+
x25519PublicKeyB64: wrap.x25519PublicKeyB64,
|
|
36
|
+
wrappedSha256Hex: wrap.wrappedSha256Hex,
|
|
37
|
+
});
|
|
38
|
+
if (challenge.message !== expectedMessage) {
|
|
39
|
+
throw new identity_key_1.IdentityKeyTamperError("Server init message does not match canonical form expected by this client.");
|
|
40
|
+
}
|
|
41
|
+
const evmSignature = await (0, wallet_evm_1.signEvmMessage)(params.evmPrivateKey, challenge.message);
|
|
42
|
+
try {
|
|
43
|
+
const completed = await (0, token_service_1.completeIdentityKeyInit)(params.baseUrl, params.accessToken, params.walletId, bundleBody, challenge.challengeId, evmSignature);
|
|
44
|
+
return {
|
|
45
|
+
identityKeyId: completed.identityKeyId,
|
|
46
|
+
x25519PublicKey: completed.x25519PublicKey,
|
|
47
|
+
provisioned: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (err instanceof token_service_1.IdentityKeyConflictError) {
|
|
52
|
+
const reloaded = await (0, token_service_1.getIdentityKeyBundle)(params.baseUrl, params.accessToken, params.walletId);
|
|
53
|
+
if (reloaded.found) {
|
|
54
|
+
return {
|
|
55
|
+
identityKeyId: reloaded.identityKeyId,
|
|
56
|
+
x25519PublicKey: reloaded.x25519PublicKey,
|
|
57
|
+
provisioned: false,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
eoaPriv.fill(0);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Sync profile metadata with live /crypto/self when token is available. */
|
|
69
|
+
async function refreshIdentityFromCryptoSelf(config) {
|
|
70
|
+
const self = await (0, crypto_self_1.fetchCryptoSelf)(config);
|
|
71
|
+
if (!self.ok) {
|
|
72
|
+
return { identityKeyId: null, walletId: null };
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
identityKeyId: self.data.identityKeyId,
|
|
76
|
+
walletId: self.data.walletId,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=identity-provision.js.map
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.buildIdentityKeyInitMessage = buildIdentityKeyInitMessage;
|
|
37
|
+
exports.wrapNewX25519Keypair = wrapNewX25519Keypair;
|
|
38
|
+
const crypto = __importStar(require("node:crypto"));
|
|
39
|
+
const wallet_identity_1 = require("../constants/wallet-identity");
|
|
40
|
+
function buildCanonicalAad(params) {
|
|
41
|
+
const lowerAddr = params.evmAddress.toLowerCase();
|
|
42
|
+
const addrBytes = Buffer.from(lowerAddr, "ascii");
|
|
43
|
+
return Buffer.concat([
|
|
44
|
+
addrBytes,
|
|
45
|
+
Buffer.from([wallet_identity_1.WRAP_FORMAT_VERSION]),
|
|
46
|
+
params.x25519SpkiDer,
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
function deriveKek(rawEoaPrivBytes, saltB64) {
|
|
50
|
+
const salt = Buffer.from(saltB64, "base64");
|
|
51
|
+
if (salt.length !== wallet_identity_1.WRAP_KDF_SALT_LEN) {
|
|
52
|
+
throw new Error(`Wrap KDF salt must be ${wallet_identity_1.WRAP_KDF_SALT_LEN} bytes`);
|
|
53
|
+
}
|
|
54
|
+
return Buffer.from(crypto.hkdfSync("sha256", rawEoaPrivBytes, salt, wallet_identity_1.WRAP_KDF_INFO, 32));
|
|
55
|
+
}
|
|
56
|
+
function sha256Hex(buf) {
|
|
57
|
+
return crypto.createHash("sha256").update(buf).digest("hex");
|
|
58
|
+
}
|
|
59
|
+
function buildIdentityKeyInitMessage(params) {
|
|
60
|
+
return [
|
|
61
|
+
"NeoZip Token Service identity key init",
|
|
62
|
+
`walletId:${params.walletId}`,
|
|
63
|
+
`challenge:${params.challengeId}`,
|
|
64
|
+
`address:${params.evmAddress.toLowerCase()}`,
|
|
65
|
+
`formatVersion:${params.formatVersion}`,
|
|
66
|
+
`x25519:${params.x25519PublicKeyB64}`,
|
|
67
|
+
`wrappedSha256:${params.wrappedSha256Hex}`,
|
|
68
|
+
].join("\n");
|
|
69
|
+
}
|
|
70
|
+
function wrapNewX25519Keypair(params) {
|
|
71
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("x25519");
|
|
72
|
+
const spkiDer = publicKey.export({ type: "spki", format: "der" });
|
|
73
|
+
const pkcs8Der = privateKey.export({ type: "pkcs8", format: "der" });
|
|
74
|
+
const rawPriv = pkcs8Der.subarray(pkcs8Der.length - 32);
|
|
75
|
+
const saltB64 = crypto.randomBytes(wallet_identity_1.WRAP_KDF_SALT_LEN).toString("base64");
|
|
76
|
+
const ivB64 = crypto.randomBytes(wallet_identity_1.WRAP_IV_LEN).toString("base64");
|
|
77
|
+
const aad = buildCanonicalAad({
|
|
78
|
+
evmAddress: params.evmAddress,
|
|
79
|
+
x25519SpkiDer: spkiDer,
|
|
80
|
+
});
|
|
81
|
+
const kek = deriveKek(params.rawEoaPrivBytes, saltB64);
|
|
82
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
83
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", kek, iv);
|
|
84
|
+
cipher.setAAD(aad);
|
|
85
|
+
const ct = Buffer.concat([cipher.update(rawPriv), cipher.final()]);
|
|
86
|
+
const tag = cipher.getAuthTag();
|
|
87
|
+
const wrapped = Buffer.concat([ct, tag]);
|
|
88
|
+
kek.fill(0);
|
|
89
|
+
rawPriv.fill(0);
|
|
90
|
+
pkcs8Der.fill(0);
|
|
91
|
+
const bundle = {
|
|
92
|
+
wrappedPrivateKeyB64: wrapped.toString("base64"),
|
|
93
|
+
wrapFormatVersion: wallet_identity_1.WRAP_FORMAT_VERSION,
|
|
94
|
+
wrapKdfInfo: wallet_identity_1.WRAP_KDF_INFO,
|
|
95
|
+
wrapKdfSaltB64: saltB64,
|
|
96
|
+
wrapAead: wallet_identity_1.WRAP_AEAD,
|
|
97
|
+
wrapIvB64: ivB64,
|
|
98
|
+
wrapAadB64: aad.toString("base64"),
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
bundle,
|
|
102
|
+
x25519PublicKeyB64: spkiDer.toString("base64"),
|
|
103
|
+
wrappedSha256Hex: sha256Hex(wrapped),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=identity-wrap.js.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.deriveProfileKey = deriveProfileKey;
|
|
37
|
+
exports.encryptJson = encryptJson;
|
|
38
|
+
exports.decryptJson = decryptJson;
|
|
39
|
+
const crypto = __importStar(require("node:crypto"));
|
|
40
|
+
const os = __importStar(require("node:os"));
|
|
41
|
+
const PROFILE_KDF_INFO = "NeoZip/McpProfileSecrets/v1";
|
|
42
|
+
const PROFILE_KDF_SALT = Buffer.from("NeoZipMcpProfileStoreSalt-v1", "utf8");
|
|
43
|
+
function deriveProfileKey() {
|
|
44
|
+
const passphrase = process.env.NEOZIP_UNLOCK_PASSPHRASE?.trim() ||
|
|
45
|
+
`${os.hostname()}:${os.userInfo().username}:neozip-mcp-profile`;
|
|
46
|
+
const okm = crypto.hkdfSync("sha256", Buffer.from(passphrase, "utf8"), PROFILE_KDF_SALT, PROFILE_KDF_INFO, 32);
|
|
47
|
+
return Buffer.from(okm);
|
|
48
|
+
}
|
|
49
|
+
function encryptJson(payload) {
|
|
50
|
+
const key = deriveProfileKey();
|
|
51
|
+
const iv = crypto.randomBytes(12);
|
|
52
|
+
const plaintext = Buffer.from(JSON.stringify(payload), "utf8");
|
|
53
|
+
try {
|
|
54
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
|
55
|
+
const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
56
|
+
const tag = cipher.getAuthTag();
|
|
57
|
+
return JSON.stringify({
|
|
58
|
+
v: 1,
|
|
59
|
+
iv: iv.toString("base64"),
|
|
60
|
+
tag: tag.toString("base64"),
|
|
61
|
+
data: ct.toString("base64"),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
key.fill(0);
|
|
66
|
+
plaintext.fill(0);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function decryptJson(encrypted) {
|
|
70
|
+
const key = deriveProfileKey();
|
|
71
|
+
const parsed = JSON.parse(encrypted);
|
|
72
|
+
const iv = Buffer.from(parsed.iv, "base64");
|
|
73
|
+
const tag = Buffer.from(parsed.tag, "base64");
|
|
74
|
+
const ct = Buffer.from(parsed.data, "base64");
|
|
75
|
+
try {
|
|
76
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
|
|
77
|
+
decipher.setAuthTag(tag);
|
|
78
|
+
const pt = Buffer.concat([decipher.update(ct), decipher.final()]);
|
|
79
|
+
return JSON.parse(pt.toString("utf8"));
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
key.fill(0);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=profile-crypto.js.map
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.savePhoneVerified = exports.saveIdentityProvision = exports.saveWalletLink = exports.saveEvmWallet = exports.saveAccessToken = void 0;
|
|
4
|
+
exports.getMcpProfileDir = getMcpProfileDir;
|
|
5
|
+
exports.listProfiles = listProfiles;
|
|
6
|
+
exports.getActiveProfileId = getActiveProfileId;
|
|
7
|
+
exports.getActiveProfile = getActiveProfile;
|
|
8
|
+
exports.selectProfile = selectProfile;
|
|
9
|
+
exports.createProfile = createProfile;
|
|
10
|
+
exports.updateProfile = updateProfile;
|
|
11
|
+
exports.removeProfile = removeProfile;
|
|
12
|
+
exports.readSecrets = readSecrets;
|
|
13
|
+
exports.readActiveSecrets = readActiveSecrets;
|
|
14
|
+
exports.logoutProfile = logoutProfile;
|
|
15
|
+
exports.clearProfileCredentialsFromEnv = clearProfileCredentialsFromEnv;
|
|
16
|
+
exports.applyActiveProfileToEnv = applyActiveProfileToEnv;
|
|
17
|
+
const store_1 = require("../connection/store");
|
|
18
|
+
Object.defineProperty(exports, "saveAccessToken", { enumerable: true, get: function () { return store_1.saveAccessToken; } });
|
|
19
|
+
Object.defineProperty(exports, "saveEvmWallet", { enumerable: true, get: function () { return store_1.saveEvmWallet; } });
|
|
20
|
+
Object.defineProperty(exports, "saveIdentityProvision", { enumerable: true, get: function () { return store_1.saveIdentityProvision; } });
|
|
21
|
+
Object.defineProperty(exports, "savePhoneVerified", { enumerable: true, get: function () { return store_1.savePhoneVerified; } });
|
|
22
|
+
Object.defineProperty(exports, "saveWalletLink", { enumerable: true, get: function () { return store_1.saveWalletLink; } });
|
|
23
|
+
const migrate_1 = require("../connection/migrate");
|
|
24
|
+
function getMcpProfileDir() {
|
|
25
|
+
return (0, store_1.getConnectionDir)();
|
|
26
|
+
}
|
|
27
|
+
function ensureMigrated() {
|
|
28
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)()) {
|
|
29
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function toProfile(meta) {
|
|
33
|
+
if (!meta)
|
|
34
|
+
return null;
|
|
35
|
+
return {
|
|
36
|
+
id: meta.id,
|
|
37
|
+
label: meta.label,
|
|
38
|
+
tokenServiceUrl: meta.tokenServiceOrigin,
|
|
39
|
+
email: meta.email,
|
|
40
|
+
emailVerified: meta.emailVerified,
|
|
41
|
+
evmAddress: meta.evmAddress,
|
|
42
|
+
walletId: meta.walletId,
|
|
43
|
+
linkId: meta.linkId,
|
|
44
|
+
identityKeyId: meta.identityKeyId,
|
|
45
|
+
x25519Fingerprint: meta.x25519Fingerprint,
|
|
46
|
+
createdAt: meta.createdAt,
|
|
47
|
+
updatedAt: meta.updatedAt,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function toSecrets(secrets) {
|
|
51
|
+
if (!secrets)
|
|
52
|
+
return null;
|
|
53
|
+
return {
|
|
54
|
+
accessToken: secrets.accessToken,
|
|
55
|
+
evmPrivateKey: secrets.evmPrivateKeyHex,
|
|
56
|
+
accessTokenObtainedAt: secrets.accessTokenObtainedAt,
|
|
57
|
+
accessTokenExpiresAt: secrets.accessTokenExpiresAt,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function listProfiles() {
|
|
61
|
+
ensureMigrated();
|
|
62
|
+
return (0, store_1.listConnections)().map((c) => ({
|
|
63
|
+
id: c.id,
|
|
64
|
+
label: c.label,
|
|
65
|
+
tokenServiceUrl: c.tokenServiceOrigin,
|
|
66
|
+
email: c.email,
|
|
67
|
+
emailVerified: c.emailVerified,
|
|
68
|
+
evmAddress: c.evmAddress,
|
|
69
|
+
walletId: c.walletId,
|
|
70
|
+
linkId: c.linkId,
|
|
71
|
+
identityKeyId: c.identityKeyId,
|
|
72
|
+
x25519Fingerprint: c.x25519Fingerprint,
|
|
73
|
+
createdAt: c.createdAt,
|
|
74
|
+
updatedAt: c.updatedAt,
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
function getActiveProfileId() {
|
|
78
|
+
ensureMigrated();
|
|
79
|
+
return (0, store_1.getActiveConnectionId)();
|
|
80
|
+
}
|
|
81
|
+
function getActiveProfile() {
|
|
82
|
+
ensureMigrated();
|
|
83
|
+
return toProfile((0, store_1.getActiveConnection)());
|
|
84
|
+
}
|
|
85
|
+
function selectProfile(profileId) {
|
|
86
|
+
ensureMigrated();
|
|
87
|
+
return toProfile((0, store_1.selectConnection)(profileId));
|
|
88
|
+
}
|
|
89
|
+
function createProfile(input) {
|
|
90
|
+
ensureMigrated();
|
|
91
|
+
return toProfile((0, store_1.createConnection)({ label: input.label, tokenServiceUrl: input.tokenServiceUrl }));
|
|
92
|
+
}
|
|
93
|
+
function updateProfile(profileId, patch) {
|
|
94
|
+
ensureMigrated();
|
|
95
|
+
const mapped = { ...patch };
|
|
96
|
+
if (patch.tokenServiceUrl) {
|
|
97
|
+
mapped.tokenServiceOrigin = patch.tokenServiceUrl;
|
|
98
|
+
delete mapped.tokenServiceUrl;
|
|
99
|
+
}
|
|
100
|
+
return toProfile((0, store_1.updateConnection)(profileId, mapped));
|
|
101
|
+
}
|
|
102
|
+
function removeProfile(_profileId, confirm) {
|
|
103
|
+
if (!confirm) {
|
|
104
|
+
throw new Error("Set confirm: true to delete the profile and its secrets.");
|
|
105
|
+
}
|
|
106
|
+
throw new Error("Profile removal via account_remove is deprecated. Use neozip connect logout.");
|
|
107
|
+
}
|
|
108
|
+
function readSecrets(profileId) {
|
|
109
|
+
ensureMigrated();
|
|
110
|
+
return toSecrets((0, store_1.readConnectionSecrets)(profileId));
|
|
111
|
+
}
|
|
112
|
+
function readActiveSecrets() {
|
|
113
|
+
ensureMigrated();
|
|
114
|
+
return toSecrets((0, store_1.readActiveConnectionSecrets)());
|
|
115
|
+
}
|
|
116
|
+
function logoutProfile(profileId) {
|
|
117
|
+
ensureMigrated();
|
|
118
|
+
const out = (0, store_1.logoutConnection)(profileId);
|
|
119
|
+
return { ...out, profileId: out.connectionId };
|
|
120
|
+
}
|
|
121
|
+
function clearProfileCredentialsFromEnv() {
|
|
122
|
+
(0, store_1.clearConnectionCredentialsFromEnv)();
|
|
123
|
+
}
|
|
124
|
+
function applyActiveProfileToEnv() {
|
|
125
|
+
ensureMigrated();
|
|
126
|
+
const out = (0, store_1.applyActiveConnectionToEnv)();
|
|
127
|
+
return { applied: out.applied, profileId: out.connectionId };
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=profile-store.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requireAccountReady = requireAccountReady;
|
|
4
|
+
const phase_1 = require("../connection/phase");
|
|
5
|
+
const store_1 = require("../connection/store");
|
|
6
|
+
const token_auth_1 = require("../connection/token-auth");
|
|
7
|
+
async function requireAccountReady(context) {
|
|
8
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
9
|
+
const meta = (0, store_1.getActiveConnection)();
|
|
10
|
+
const secrets = (0, store_1.readActiveConnectionSecrets)();
|
|
11
|
+
if (secrets?.accessToken?.trim() && (0, token_auth_1.isAccessTokenExpired)(secrets)) {
|
|
12
|
+
return [
|
|
13
|
+
`${context} requires a valid Token Service access token.`,
|
|
14
|
+
(0, token_auth_1.formatTokenReauthGuidance)(meta?.email),
|
|
15
|
+
].join("\n\n");
|
|
16
|
+
}
|
|
17
|
+
if (phase !== "ready") {
|
|
18
|
+
const nextCmd = (0, phase_1.nextConnectCommand)(phase, {
|
|
19
|
+
email: meta?.email,
|
|
20
|
+
phoneE164: meta?.phoneE164,
|
|
21
|
+
});
|
|
22
|
+
const parts = [
|
|
23
|
+
`${context} requires a fully initialized NeoZip account (phase: ${phase}).`,
|
|
24
|
+
];
|
|
25
|
+
if (nextCmd)
|
|
26
|
+
parts.push(`Run: ${nextCmd}`);
|
|
27
|
+
parts.push("Reload MCP after setup so credentials load into this session.");
|
|
28
|
+
return parts.join(" ");
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=require-account.js.map
|