@agentproto/secrets 0.2.6 → 1.0.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/dist/{chunk-Q6K3AT3V.mjs → chunk-2FHFW2AU.mjs} +3 -3
- package/dist/{chunk-Q6K3AT3V.mjs.map → chunk-2FHFW2AU.mjs.map} +1 -1
- package/dist/chunk-3YRYO6LK.mjs +222 -0
- package/dist/chunk-3YRYO6LK.mjs.map +1 -0
- package/dist/chunk-432SC3XS.mjs +100 -0
- package/dist/chunk-432SC3XS.mjs.map +1 -0
- package/dist/chunk-5HUHYBPR.mjs +69 -0
- package/dist/chunk-5HUHYBPR.mjs.map +1 -0
- package/dist/{chunk-NLZ5HXGO.mjs → chunk-7V6U6DII.mjs} +4 -4
- package/dist/{chunk-NLZ5HXGO.mjs.map → chunk-7V6U6DII.mjs.map} +1 -1
- package/dist/chunk-JNTDSOZQ.mjs +623 -0
- package/dist/chunk-JNTDSOZQ.mjs.map +1 -0
- package/dist/chunk-NQX3KBPW.mjs +50 -0
- package/dist/chunk-NQX3KBPW.mjs.map +1 -0
- package/dist/chunk-PCFPJ47T.mjs +28 -0
- package/dist/chunk-PCFPJ47T.mjs.map +1 -0
- package/dist/cli.mjs +10 -7
- package/dist/cli.mjs.map +1 -1
- package/dist/core-CIn0-z-Y.d.ts +42 -0
- package/dist/core-D8zVNPDb.d.ts +58 -0
- package/dist/identity/index.d.ts +25 -46
- package/dist/identity/index.mjs +76 -1
- package/dist/identity/index.mjs.map +1 -1
- package/dist/pairing/browser.d.ts +18 -0
- package/dist/pairing/browser.mjs +6 -0
- package/dist/pairing/browser.mjs.map +1 -0
- package/dist/pairing/index.d.ts +45 -440
- package/dist/pairing/index.mjs +33 -465
- package/dist/pairing/index.mjs.map +1 -1
- package/dist/provision/index.mjs +5 -2
- package/dist/provision/recipe/index.mjs +6 -3
- package/dist/seal/index.d.ts +21 -31
- package/dist/seal/index.mjs +4 -1
- package/dist/types-B2ZfEhsU.d.ts +57 -0
- package/dist/webcrypto-BU57p0_g.d.ts +652 -0
- package/package.json +8 -2
- package/dist/chunk-2DL6W33G.mjs +0 -126
- package/dist/chunk-2DL6W33G.mjs.map +0 -1
- package/dist/chunk-MVHOJPML.mjs +0 -132
- package/dist/chunk-MVHOJPML.mjs.map +0 -1
package/dist/identity/index.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { C as CryptoProvider } from '../types-B2ZfEhsU.js';
|
|
2
|
+
import { D as DaemonIdentity } from '../core-D8zVNPDb.js';
|
|
3
|
+
export { I as IDENTITY_VERSION, a as IdentityError, b as IdentityKeyPair } from '../core-D8zVNPDb.js';
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
6
|
* @agentproto/secrets/identity — the daemon's persistent cryptographic
|
|
3
7
|
* identity for E2E pairing (design: PAIRING / DESIGN §1).
|
|
@@ -14,52 +18,27 @@
|
|
|
14
18
|
* shape `@agentproto/secrets/seal` already uses, so the identity file travels
|
|
15
19
|
* as plain JSON and the seal box can consume the X25519 public half verbatim.
|
|
16
20
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
21
|
+
* The crypto (X25519, Ed25519, SHA-256) lives once in ./core.ts against a
|
|
22
|
+
* `CryptoProvider`; this Node entry defaults to `node:crypto` and adds the
|
|
23
|
+
* file-backed store. Everything is async (WebCrypto is) and takes an optional
|
|
24
|
+
* trailing `crypto` to override the provider. The private halves never leave
|
|
19
25
|
* the identity file (mode 0600) and are never logged.
|
|
20
26
|
*/
|
|
21
|
-
|
|
22
|
-
declare const IDENTITY_VERSION: 1;
|
|
23
|
-
/** Raised for every identity load/generate/sign/verify failure. The message
|
|
24
|
-
* is safe to surface — it never contains private key material. */
|
|
25
|
-
declare class IdentityError extends Error {
|
|
26
|
-
constructor(message: string);
|
|
27
|
-
}
|
|
28
|
-
/** One keypair, both halves base64-DER. Public = SPKI, private = PKCS8. */
|
|
29
|
-
interface IdentityKeyPair {
|
|
30
|
-
/** base64 DER (SPKI) public key — publishable. */
|
|
31
|
-
pub: string;
|
|
32
|
-
/** base64 DER (PKCS8) private key — secret. */
|
|
33
|
-
priv: string;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* A daemon's persistent identity. Serialized verbatim to
|
|
37
|
-
* `~/.agentproto/identity.json` (0600). The `x25519` public half is the key a
|
|
38
|
-
* client seals its hello to; the `ed25519` public half is the key a client
|
|
39
|
-
* verifies the daemon's transcript signature against. Both public halves are
|
|
40
|
-
* carried in the offer URL.
|
|
41
|
-
*/
|
|
42
|
-
interface DaemonIdentity {
|
|
43
|
-
v: typeof IDENTITY_VERSION;
|
|
44
|
-
/** Encryption / key-agreement keypair. */
|
|
45
|
-
x25519: IdentityKeyPair;
|
|
46
|
-
/** Signing / authenticity keypair. */
|
|
47
|
-
ed25519: IdentityKeyPair;
|
|
48
|
-
/** ISO-8601 creation timestamp. */
|
|
49
|
-
createdAt: string;
|
|
50
|
-
}
|
|
27
|
+
|
|
51
28
|
/**
|
|
52
29
|
* Mint a fresh daemon identity: one X25519 keypair (encryption) and one
|
|
53
30
|
* Ed25519 keypair (signing). Called lazily on first `pair offer`.
|
|
54
31
|
*/
|
|
55
|
-
declare function generateIdentity(): DaemonIdentity
|
|
32
|
+
declare function generateIdentity(crypto?: CryptoProvider): Promise<DaemonIdentity>;
|
|
56
33
|
/**
|
|
57
|
-
* Stable
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
34
|
+
* Stable identifier for a daemon, derived from its X25519 public key: the
|
|
35
|
+
* first 32 hex (128 bits) of `sha256(pub DER)`. It names the daemon's browser
|
|
36
|
+
* origin (`<fingerprint>.agentproto.cloud`), so it is long enough to resist a
|
|
37
|
+
* grind for a colliding key. `sealKeyId` in `@agentproto/secrets/seal` is its
|
|
38
|
+
* 16-hex prefix. Displayed everywhere a human confirms identity (offer QR,
|
|
39
|
+
* `pair accept`, `pair ls`). Not a secret.
|
|
61
40
|
*/
|
|
62
|
-
declare function identityFingerprint(x25519Pub: string): string
|
|
41
|
+
declare function identityFingerprint(x25519Pub: string, crypto?: CryptoProvider): Promise<string>;
|
|
63
42
|
/**
|
|
64
43
|
* Load the daemon identity from `filePath`, creating it on first use. The
|
|
65
44
|
* caller supplies the path (typically `~/.agentproto/identity.json`) so this
|
|
@@ -73,17 +52,17 @@ declare function identityFingerprint(x25519Pub: string): string;
|
|
|
73
52
|
*/
|
|
74
53
|
declare function loadOrCreateIdentity(filePath: string): Promise<DaemonIdentity>;
|
|
75
54
|
/**
|
|
76
|
-
* Sign a handshake transcript with the daemon's Ed25519 private key.
|
|
77
|
-
* base64 signature. `transcript` is the exact bytes both sides agree on
|
|
55
|
+
* Sign a handshake transcript with the daemon's Ed25519 private key. Resolves
|
|
56
|
+
* to a base64 signature. `transcript` is the exact bytes both sides agree on
|
|
78
57
|
* (`sha256(e_pub ‖ ct₀ ‖ d_e_pub)`); signing it — not the raw messages — is
|
|
79
58
|
* what binds the daemon's authenticity to the whole exchange.
|
|
80
59
|
*/
|
|
81
|
-
declare function signTranscript(ed25519Priv: string, transcript: Uint8Array): string
|
|
60
|
+
declare function signTranscript(ed25519Priv: string, transcript: Uint8Array, crypto?: CryptoProvider): Promise<string>;
|
|
82
61
|
/**
|
|
83
|
-
* Verify a transcript signature against a daemon's Ed25519 public key.
|
|
84
|
-
* a boolean — never
|
|
85
|
-
* key), so callers branch on the result rather than
|
|
62
|
+
* Verify a transcript signature against a daemon's Ed25519 public key. Resolves
|
|
63
|
+
* to a boolean — never rejects on a bad signature (only on a structurally
|
|
64
|
+
* invalid key), so callers branch on the result rather than an exception.
|
|
86
65
|
*/
|
|
87
|
-
declare function verifyTranscript(ed25519Pub: string, transcript: Uint8Array, signature: string): boolean
|
|
66
|
+
declare function verifyTranscript(ed25519Pub: string, transcript: Uint8Array, signature: string, crypto?: CryptoProvider): Promise<boolean>;
|
|
88
67
|
|
|
89
|
-
export {
|
|
68
|
+
export { CryptoProvider, DaemonIdentity, generateIdentity, identityFingerprint, loadOrCreateIdentity, signTranscript, verifyTranscript };
|
package/dist/identity/index.mjs
CHANGED
|
@@ -1,3 +1,78 @@
|
|
|
1
|
-
|
|
1
|
+
import { generateIdentity, identityFingerprint, IdentityError, signTranscript, verifyTranscript, IDENTITY_VERSION } from '../chunk-NQX3KBPW.mjs';
|
|
2
|
+
export { IDENTITY_VERSION, IdentityError } from '../chunk-NQX3KBPW.mjs';
|
|
3
|
+
import { nodeCryptoProvider } from '../chunk-5HUHYBPR.mjs';
|
|
4
|
+
import '../chunk-3YRYO6LK.mjs';
|
|
5
|
+
import { readFile, mkdir, writeFile, chmod, rename } from 'fs/promises';
|
|
6
|
+
import { dirname, join, basename } from 'path';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @agentproto/secrets v0.1.0-alpha
|
|
10
|
+
* AIP-19 SECRETS.md `defineSecrets` reference implementation.
|
|
11
|
+
*/
|
|
12
|
+
function generateIdentity2(crypto = nodeCryptoProvider) {
|
|
13
|
+
return generateIdentity(crypto);
|
|
14
|
+
}
|
|
15
|
+
function identityFingerprint2(x25519Pub, crypto = nodeCryptoProvider) {
|
|
16
|
+
return identityFingerprint(x25519Pub, crypto);
|
|
17
|
+
}
|
|
18
|
+
function isEnoent(err) {
|
|
19
|
+
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
20
|
+
}
|
|
21
|
+
function isRecord(v) {
|
|
22
|
+
return typeof v === "object" && v !== null;
|
|
23
|
+
}
|
|
24
|
+
function isKeyPair(kp) {
|
|
25
|
+
return isRecord(kp) && typeof kp["pub"] === "string" && typeof kp["priv"] === "string";
|
|
26
|
+
}
|
|
27
|
+
function isDaemonIdentity(value) {
|
|
28
|
+
if (!isRecord(value)) return false;
|
|
29
|
+
if (value["v"] !== IDENTITY_VERSION) return false;
|
|
30
|
+
if (typeof value["createdAt"] !== "string") return false;
|
|
31
|
+
return isKeyPair(value["x25519"]) && isKeyPair(value["ed25519"]);
|
|
32
|
+
}
|
|
33
|
+
async function loadOrCreateIdentity(filePath) {
|
|
34
|
+
try {
|
|
35
|
+
const raw = await readFile(filePath, "utf8");
|
|
36
|
+
let parsed;
|
|
37
|
+
try {
|
|
38
|
+
parsed = JSON.parse(raw);
|
|
39
|
+
} catch {
|
|
40
|
+
throw new IdentityError(
|
|
41
|
+
`identity file ${filePath} is not valid JSON \u2014 refusing to overwrite; move it aside to regenerate`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
if (!isDaemonIdentity(parsed)) {
|
|
45
|
+
throw new IdentityError(
|
|
46
|
+
`identity file ${filePath} is malformed or an unsupported version \u2014 refusing to overwrite; move it aside to regenerate`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return parsed;
|
|
50
|
+
} catch (err) {
|
|
51
|
+
if (!isEnoent(err)) throw err;
|
|
52
|
+
}
|
|
53
|
+
const identity = await generateIdentity2();
|
|
54
|
+
await persistIdentity(filePath, identity);
|
|
55
|
+
return identity;
|
|
56
|
+
}
|
|
57
|
+
async function persistIdentity(filePath, identity) {
|
|
58
|
+
const dir = dirname(filePath);
|
|
59
|
+
await mkdir(dir, { recursive: true });
|
|
60
|
+
const tmp = join(dir, `.${basename(filePath)}.tmp-${process.pid}`);
|
|
61
|
+
await writeFile(tmp, JSON.stringify(identity, null, 2) + "\n", {
|
|
62
|
+
encoding: "utf8",
|
|
63
|
+
mode: 384
|
|
64
|
+
});
|
|
65
|
+
await chmod(tmp, 384).catch(() => {
|
|
66
|
+
});
|
|
67
|
+
await rename(tmp, filePath);
|
|
68
|
+
}
|
|
69
|
+
function signTranscript2(ed25519Priv, transcript, crypto = nodeCryptoProvider) {
|
|
70
|
+
return signTranscript(ed25519Priv, transcript, crypto);
|
|
71
|
+
}
|
|
72
|
+
function verifyTranscript2(ed25519Pub, transcript, signature, crypto = nodeCryptoProvider) {
|
|
73
|
+
return verifyTranscript(ed25519Pub, transcript, signature, crypto);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { generateIdentity2 as generateIdentity, identityFingerprint2 as identityFingerprint, loadOrCreateIdentity, signTranscript2 as signTranscript, verifyTranscript2 as verifyTranscript };
|
|
2
77
|
//# sourceMappingURL=index.mjs.map
|
|
3
78
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.mjs"}
|
|
1
|
+
{"version":3,"sources":["../../src/identity/index.ts"],"names":["generateIdentity","identityFingerprint","signTranscript","verifyTranscript"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @agentproto/secrets/identity — the daemon's persistent cryptographic\n * identity for E2E pairing (design: PAIRING / DESIGN §1).\n *\n * A daemon that accepts pairings needs a stable identity a client can pin:\n * - an **X25519** keypair for key agreement (the client seals its hello to\n * this key, and it is one of the two ECDH inputs to the session key), and\n * - an **Ed25519** keypair for authenticity (the daemon signs the handshake\n * transcript so the client — who learned the public halves out-of-band via\n * the offer URL — can prove it is really talking to the daemon it scanned,\n * not an evil rendezvous in the middle).\n *\n * Both keypairs are stored base64-DER (SPKI public / PKCS8 private), the exact\n * shape `@agentproto/secrets/seal` already uses, so the identity file travels\n * as plain JSON and the seal box can consume the X25519 public half verbatim.\n *\n * The crypto (X25519, Ed25519, SHA-256) lives once in ./core.ts against a\n * `CryptoProvider`; this Node entry defaults to `node:crypto` and adds the\n * file-backed store. Everything is async (WebCrypto is) and takes an optional\n * trailing `crypto` to override the provider. The private halves never leave\n * the identity file (mode 0600) and are never logged.\n */\n\nimport { mkdir, readFile, writeFile, chmod, rename } from \"node:fs/promises\"\nimport { dirname, join, basename } from \"node:path\"\nimport { nodeCryptoProvider } from \"../crypto/node.js\"\nimport type { CryptoProvider } from \"../crypto/types.js\"\nimport * as core from \"./core.js\"\nimport { IDENTITY_VERSION, IdentityError, type DaemonIdentity } from \"./core.js\"\n\nexport {\n IDENTITY_VERSION,\n IdentityError,\n type IdentityKeyPair,\n type DaemonIdentity,\n} from \"./core.js\"\nexport type { CryptoProvider } from \"../crypto/types.js\"\n\n/**\n * Mint a fresh daemon identity: one X25519 keypair (encryption) and one\n * Ed25519 keypair (signing). Called lazily on first `pair offer`.\n */\nexport function generateIdentity(crypto: CryptoProvider = nodeCryptoProvider): Promise<DaemonIdentity> {\n return core.generateIdentity(crypto)\n}\n\n/**\n * Stable identifier for a daemon, derived from its X25519 public key: the\n * first 32 hex (128 bits) of `sha256(pub DER)`. It names the daemon's browser\n * origin (`<fingerprint>.agentproto.cloud`), so it is long enough to resist a\n * grind for a colliding key. `sealKeyId` in `@agentproto/secrets/seal` is its\n * 16-hex prefix. Displayed everywhere a human confirms identity (offer QR,\n * `pair accept`, `pair ls`). Not a secret.\n */\nexport function identityFingerprint(x25519Pub: string, crypto: CryptoProvider = nodeCryptoProvider): Promise<string> {\n return core.identityFingerprint(x25519Pub, crypto)\n}\n\n/** True for a filesystem \"no such file\" error, without an unchecked cast. */\nfunction isEnoent(err: unknown): boolean {\n return (\n typeof err === \"object\" &&\n err !== null &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n )\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null\n}\n\nfunction isKeyPair(kp: unknown): boolean {\n return isRecord(kp) && typeof kp[\"pub\"] === \"string\" && typeof kp[\"priv\"] === \"string\"\n}\n\nfunction isDaemonIdentity(value: unknown): value is DaemonIdentity {\n if (!isRecord(value)) return false\n if (value[\"v\"] !== IDENTITY_VERSION) return false\n if (typeof value[\"createdAt\"] !== \"string\") return false\n return isKeyPair(value[\"x25519\"]) && isKeyPair(value[\"ed25519\"])\n}\n\n/**\n * Load the daemon identity from `filePath`, creating it on first use. The\n * caller supplies the path (typically `~/.agentproto/identity.json`) so this\n * module stays free of any home-dir policy.\n *\n * The private halves are secret, so a freshly created file is written 0600 and\n * atomically (temp file in the same directory + `rename`, so a crash mid-write\n * can never leave a half-written identity or a world-readable window). A\n * malformed existing file is a hard error — never silently overwritten, since\n * that would rotate the daemon's identity and orphan every existing pairing.\n */\nexport async function loadOrCreateIdentity(\n filePath: string\n): Promise<DaemonIdentity> {\n try {\n const raw = await readFile(filePath, \"utf8\")\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n throw new IdentityError(\n `identity file ${filePath} is not valid JSON — refusing to overwrite; ` +\n `move it aside to regenerate`\n )\n }\n if (!isDaemonIdentity(parsed)) {\n throw new IdentityError(\n `identity file ${filePath} is malformed or an unsupported version — ` +\n `refusing to overwrite; move it aside to regenerate`\n )\n }\n return parsed\n } catch (err) {\n if (!isEnoent(err)) throw err\n // ENOENT → first run; fall through to lazy creation below.\n }\n\n const identity = await generateIdentity()\n await persistIdentity(filePath, identity)\n return identity\n}\n\n/** Atomic 0600 write: serialize to a sibling temp file, chmod it before it\n * holds any secret bytes, then rename over the target. */\nasync function persistIdentity(\n filePath: string,\n identity: DaemonIdentity\n): Promise<void> {\n const dir = dirname(filePath)\n await mkdir(dir, { recursive: true })\n const tmp = join(dir, `.${basename(filePath)}.tmp-${process.pid}`)\n await writeFile(tmp, JSON.stringify(identity, null, 2) + \"\\n\", {\n encoding: \"utf8\",\n mode: 0o600,\n })\n // Belt-and-suspenders: writeFile's mode is subject to umask on some\n // platforms, so tighten explicitly before the file is visible at its\n // final name. Windows / mounts that ignore chmod fall back to the\n // already-private user profile dir.\n await chmod(tmp, 0o600).catch(() => {})\n await rename(tmp, filePath)\n}\n\n/**\n * Sign a handshake transcript with the daemon's Ed25519 private key. Resolves\n * to a base64 signature. `transcript` is the exact bytes both sides agree on\n * (`sha256(e_pub ‖ ct₀ ‖ d_e_pub)`); signing it — not the raw messages — is\n * what binds the daemon's authenticity to the whole exchange.\n */\nexport function signTranscript(\n ed25519Priv: string,\n transcript: Uint8Array,\n crypto: CryptoProvider = nodeCryptoProvider,\n): Promise<string> {\n return core.signTranscript(ed25519Priv, transcript, crypto)\n}\n\n/**\n * Verify a transcript signature against a daemon's Ed25519 public key. Resolves\n * to a boolean — never rejects on a bad signature (only on a structurally\n * invalid key), so callers branch on the result rather than an exception.\n */\nexport function verifyTranscript(\n ed25519Pub: string,\n transcript: Uint8Array,\n signature: string,\n crypto: CryptoProvider = nodeCryptoProvider,\n): Promise<boolean> {\n return core.verifyTranscript(ed25519Pub, transcript, signature, crypto)\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { C as ClientHandshakeParams, D as DEFAULT_PAIR_PAGE, a as DaemonHandshakeParams, b as DaemonHandshakeResult, H as HOSTED_RENDEZVOUS_URL, L as LEGACY_PAIR_VERSION, O as OFFER_URL_HOST, c as OFFER_URL_SCHEME, d as OFFER_VERSION, P as PAIRING_PROTOCOL_OUTDATED_MESSAGE, e as PAIR_PAGE_FP_PLACEHOLDER, f as PAIR_VERSION, g as PAIR_WEB_URL, h as PAIR_WEB_URL_TEMPLATE_CLOUD, i as PairingError, j as PairingErrorCode, k as PairingHello, l as PairingOffer, m as PairingReply, n as PairingSession, o as ParseOfferOptions, R as RouteAuthTokens, S as StartedClientHandshake, p as StartedTunnelHandshake, T as TUNNEL_E2E_VERSION, q as TunnelAccept, r as TunnelE2ESession, s as TunnelHandshakeError, t as TunnelHandshakeErrorCode, u as TunnelHandshakeResult, v as TunnelOffer, w as currentEpoch, x as decodePairingHello, y as decodePairingReply, z as decodeTunnelAccept, A as decodeTunnelOffer, B as deriveEpochAuthToken, E as deriveEpochRoutingToken, F as deriveEpochTokens, G as deriveOfferTokens, I as derivePairRoot, J as encodeOfferUrl, K as encodeOfferWebUrl, M as encodePairingMessage, N as encodeTunnelMessage, Q as epochRoutingTokens, U as expectedPairHost, V as importPairRootKey, W as parseOfferUrl, X as resolvePairPageUrl, Y as respondToHandshake, Z as respondToLegacyHandshake, _ as respondToTunnelHandshake, $ as startClientHandshake, a0 as startTunnelHandshake, a1 as webCryptoProvider } from '../webcrypto-BU57p0_g.js';
|
|
2
|
+
export { S as SEAL_ALG, a as SEAL_VERSION, b as SealError, c as SealKeyPair, g as generateSealKeyPair, s as seal, d as sealKeyId, e as sealingPublicKey, u as unseal } from '../core-CIn0-z-Y.js';
|
|
3
|
+
export { D as DaemonIdentity, I as IDENTITY_VERSION, a as IdentityError, b as IdentityKeyPair, g as generateIdentity, i as identityFingerprint, s as signTranscript, v as verifyTranscript } from '../core-D8zVNPDb.js';
|
|
4
|
+
export { C as CryptoProvider, K as KeyPairDer } from '../types-B2ZfEhsU.js';
|
|
5
|
+
|
|
6
|
+
/** Standard base64 (padded) — identical to `Buffer#toString("base64")`. */
|
|
7
|
+
declare function base64Encode(bytes: Uint8Array): string;
|
|
8
|
+
/** Lenient base64 decode — identical to `Buffer.from(s, "base64")`. Returns a
|
|
9
|
+
* plain `Uint8Array` view (a `Buffer` under Node). Never throws. */
|
|
10
|
+
declare function base64Decode(s: string): Uint8Array;
|
|
11
|
+
/** base64url without padding. */
|
|
12
|
+
declare function base64UrlEncode(bytes: Uint8Array): string;
|
|
13
|
+
declare function utf8Encode(s: string): Uint8Array;
|
|
14
|
+
/** UTF-8 decode, replacing invalid sequences with U+FFFD (like Buffer). */
|
|
15
|
+
declare function utf8Decode(bytes: Uint8Array): string;
|
|
16
|
+
declare function concatBytes(...parts: Uint8Array[]): Uint8Array;
|
|
17
|
+
|
|
18
|
+
export { base64Decode, base64Encode, base64UrlEncode, concatBytes, utf8Decode, utf8Encode };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { DEFAULT_PAIR_PAGE, HOSTED_RENDEZVOUS_URL, LEGACY_PAIR_VERSION, OFFER_URL_HOST, OFFER_URL_SCHEME, OFFER_VERSION, PAIRING_PROTOCOL_OUTDATED_MESSAGE, PAIR_PAGE_FP_PLACEHOLDER, PAIR_VERSION, PAIR_WEB_URL, PAIR_WEB_URL_TEMPLATE_CLOUD, PairingError, TUNNEL_E2E_VERSION, TunnelHandshakeError, currentEpoch, decodePairingHello, decodePairingReply, decodeTunnelAccept, decodeTunnelOffer, deriveEpochAuthToken, deriveEpochRoutingToken, deriveEpochTokens, deriveOfferTokens, derivePairRoot, encodeOfferUrl, encodeOfferWebUrl, encodePairingMessage, encodeTunnelMessage, epochRoutingTokens, expectedPairHost, importPairRootKey, parseOfferUrl, resolvePairPageUrl, respondToHandshake, respondToLegacyHandshake, respondToTunnelHandshake, startClientHandshake, startTunnelHandshake } from '../chunk-JNTDSOZQ.mjs';
|
|
2
|
+
export { IDENTITY_VERSION, IdentityError, generateIdentity, identityFingerprint, signTranscript, verifyTranscript } from '../chunk-NQX3KBPW.mjs';
|
|
3
|
+
export { SEAL_ALG, SEAL_VERSION, SealError, generateSealKeyPair, seal, sealKeyId, sealingPublicKey, unseal } from '../chunk-432SC3XS.mjs';
|
|
4
|
+
export { base64Decode, base64Encode, base64UrlEncode, concatBytes, utf8Decode, utf8Encode, webCryptoProvider } from '../chunk-3YRYO6LK.mjs';
|
|
5
|
+
//# sourceMappingURL=browser.mjs.map
|
|
6
|
+
//# sourceMappingURL=browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"browser.mjs"}
|