@soropass/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/checkAuth-C2AcXqFe.d.cts +110 -0
  2. package/dist/checkAuth-C2AcXqFe.d.ts +110 -0
  3. package/dist/chunk-AHFGTIBY.js +36 -0
  4. package/dist/chunk-AHFGTIBY.js.map +1 -0
  5. package/dist/chunk-AMYFJQAC.js +29 -0
  6. package/dist/chunk-AMYFJQAC.js.map +1 -0
  7. package/dist/chunk-BIRF5I6I.js +265 -0
  8. package/dist/chunk-BIRF5I6I.js.map +1 -0
  9. package/dist/chunk-JNJ2FY45.js +209 -0
  10. package/dist/chunk-JNJ2FY45.js.map +1 -0
  11. package/dist/chunk-LB4HOTLV.js +135 -0
  12. package/dist/chunk-LB4HOTLV.js.map +1 -0
  13. package/dist/chunk-LM2AZXKZ.js +108 -0
  14. package/dist/chunk-LM2AZXKZ.js.map +1 -0
  15. package/dist/chunk-LUDXP56M.js +3 -0
  16. package/dist/chunk-LUDXP56M.js.map +1 -0
  17. package/dist/chunk-MMB4ZIW3.js +48 -0
  18. package/dist/chunk-MMB4ZIW3.js.map +1 -0
  19. package/dist/chunk-MOLZIRIH.js +22 -0
  20. package/dist/chunk-MOLZIRIH.js.map +1 -0
  21. package/dist/chunk-OGSUGATA.js +3 -0
  22. package/dist/chunk-OGSUGATA.js.map +1 -0
  23. package/dist/chunk-TPBBZNPP.js +30 -0
  24. package/dist/chunk-TPBBZNPP.js.map +1 -0
  25. package/dist/chunk-UQKNPO44.js +32 -0
  26. package/dist/chunk-UQKNPO44.js.map +1 -0
  27. package/dist/chunk-UV5HORMF.js +175 -0
  28. package/dist/chunk-UV5HORMF.js.map +1 -0
  29. package/dist/chunk-W75OQKHR.js +133 -0
  30. package/dist/chunk-W75OQKHR.js.map +1 -0
  31. package/dist/connect.cjs +166 -0
  32. package/dist/connect.cjs.map +1 -0
  33. package/dist/connect.d.cts +24 -0
  34. package/dist/connect.d.ts +24 -0
  35. package/dist/connect.js +6 -0
  36. package/dist/connect.js.map +1 -0
  37. package/dist/create.cjs +483 -0
  38. package/dist/create.cjs.map +1 -0
  39. package/dist/create.d.cts +106 -0
  40. package/dist/create.d.ts +106 -0
  41. package/dist/create.js +8 -0
  42. package/dist/create.js.map +1 -0
  43. package/dist/index.cjs +1542 -0
  44. package/dist/index.cjs.map +1 -0
  45. package/dist/index.d.cts +197 -0
  46. package/dist/index.d.ts +197 -0
  47. package/dist/index.js +354 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/recover-0wbOXDjR.d.cts +23 -0
  50. package/dist/recover-COnsxhYk.d.ts +23 -0
  51. package/dist/recover.cjs +802 -0
  52. package/dist/recover.cjs.map +1 -0
  53. package/dist/recover.d.cts +49 -0
  54. package/dist/recover.d.ts +49 -0
  55. package/dist/recover.js +10 -0
  56. package/dist/recover.js.map +1 -0
  57. package/dist/sign-Cfg0NM0T.d.cts +73 -0
  58. package/dist/sign-Cfg0NM0T.d.ts +73 -0
  59. package/dist/sign.cjs +883 -0
  60. package/dist/sign.cjs.map +1 -0
  61. package/dist/sign.d.cts +143 -0
  62. package/dist/sign.d.ts +143 -0
  63. package/dist/sign.js +8 -0
  64. package/dist/sign.js.map +1 -0
  65. package/dist/submit-BDKADQq0.d.cts +112 -0
  66. package/dist/submit-BO0Nh49I.d.ts +112 -0
  67. package/dist/testing.cjs +955 -0
  68. package/dist/testing.cjs.map +1 -0
  69. package/dist/testing.d.cts +86 -0
  70. package/dist/testing.d.ts +86 -0
  71. package/dist/testing.js +235 -0
  72. package/dist/testing.js.map +1 -0
  73. package/dist/types--WNl-Sda.d.cts +125 -0
  74. package/dist/types--WNl-Sda.d.ts +125 -0
  75. package/dist/types-dMRWEEo0.d.cts +73 -0
  76. package/dist/types-lW2h8Uxn.d.ts +73 -0
  77. package/dist/types.cjs +44 -0
  78. package/dist/types.cjs.map +1 -0
  79. package/dist/types.d.cts +5 -0
  80. package/dist/types.d.ts +5 -0
  81. package/dist/types.js +5 -0
  82. package/dist/types.js.map +1 -0
  83. package/package.json +117 -0
@@ -0,0 +1,235 @@
1
+ import { createPasskey } from './chunk-W75OQKHR.js';
2
+ import { connect } from './chunk-AHFGTIBY.js';
3
+ import { recover } from './chunk-MOLZIRIH.js';
4
+ import { signAuthEntry } from './chunk-BIRF5I6I.js';
5
+ import { sha256, concatBytes } from './chunk-JNJ2FY45.js';
6
+ import { utf8ToBytes, bytesToBase64Url } from './chunk-LB4HOTLV.js';
7
+ import './chunk-TPBBZNPP.js';
8
+ import './chunk-AMYFJQAC.js';
9
+ import { p256 } from '@noble/curves/nist';
10
+ import { StrKey } from '@stellar/stellar-sdk';
11
+
12
+ // src/internal/cborEncode.ts
13
+ function head(major, arg) {
14
+ const m = major << 5;
15
+ if (arg < 24) return [m | arg];
16
+ if (arg < 256) return [m | 24, arg];
17
+ if (arg < 65536) return [m | 25, arg >> 8 & 255, arg & 255];
18
+ return [m | 26, arg >>> 24 & 255, arg >> 16 & 255, arg >> 8 & 255, arg & 255];
19
+ }
20
+ function write(value, out) {
21
+ if (typeof value === "number" && Number.isInteger(value)) {
22
+ if (value >= 0) out.push(...head(0, value));
23
+ else out.push(...head(1, -1 - value));
24
+ } else if (value instanceof Uint8Array) {
25
+ out.push(...head(2, value.length));
26
+ for (const b of value) out.push(b);
27
+ } else if (typeof value === "string") {
28
+ const bytes = utf8ToBytes(value);
29
+ out.push(...head(3, bytes.length));
30
+ for (const b of bytes) out.push(b);
31
+ } else if (Array.isArray(value)) {
32
+ out.push(...head(4, value.length));
33
+ for (const item of value) write(item, out);
34
+ } else if (value instanceof Map) {
35
+ out.push(...head(5, value.size));
36
+ for (const [k, v] of value) {
37
+ write(k, out);
38
+ write(v, out);
39
+ }
40
+ } else {
41
+ throw new Error("CBOR encode: unsupported value");
42
+ }
43
+ }
44
+ function encodeCbor(value) {
45
+ const out = [];
46
+ write(value, out);
47
+ return Uint8Array.from(out);
48
+ }
49
+
50
+ // src/testing/mockAuthenticator.ts
51
+ function deriveScalar(seed) {
52
+ const n = p256.CURVE.n;
53
+ let scalar = BigInt("0x" + bytesToHexLocal(sha256(utf8ToBytes("priv:" + seed)))) % n;
54
+ if (scalar === 0n) scalar = 1n;
55
+ const hex = scalar.toString(16).padStart(64, "0");
56
+ return Uint8Array.from((hex.match(/../g) ?? []).map((h) => parseInt(h, 16)));
57
+ }
58
+ function bytesToHexLocal(bytes) {
59
+ let hex = "";
60
+ for (const b of bytes) hex += b.toString(16).padStart(2, "0");
61
+ return hex;
62
+ }
63
+ function mockAuthenticator(options) {
64
+ const seed = options.seed ?? "mock-authenticator";
65
+ const origin = options.origin ?? `https://${options.rpId}`;
66
+ const privateKey = deriveScalar(seed);
67
+ const publicKey = p256.getPublicKey(privateKey, false);
68
+ const x = publicKey.slice(1, 33);
69
+ const y = publicKey.slice(33, 65);
70
+ const credIdBytes = sha256(utf8ToBytes("cred:" + seed)).slice(0, 16);
71
+ const credentialId = bytesToBase64Url(credIdBytes);
72
+ const rpIdHash = sha256(utf8ToBytes(options.rpId));
73
+ const coseKey = encodeCbor(
74
+ /* @__PURE__ */ new Map([
75
+ [1, 2],
76
+ // kty EC2
77
+ [3, -7],
78
+ // alg ES256
79
+ [-1, 1],
80
+ // crv P-256
81
+ [-2, x],
82
+ [-3, y]
83
+ ])
84
+ );
85
+ const attestedAuthData = concatBytes(
86
+ rpIdHash,
87
+ new Uint8Array([69]),
88
+ // UP | UV | AT
89
+ new Uint8Array([0, 0, 0, 0]),
90
+ // signCount
91
+ new Uint8Array(16),
92
+ // aaguid
93
+ new Uint8Array([0, credIdBytes.length]),
94
+ credIdBytes,
95
+ coseKey
96
+ );
97
+ const attestationObject = encodeCbor(
98
+ /* @__PURE__ */ new Map([
99
+ ["fmt", "none"],
100
+ ["attStmt", /* @__PURE__ */ new Map()],
101
+ ["authData", attestedAuthData]
102
+ ])
103
+ );
104
+ function signAssertion(challengeB64) {
105
+ const authenticatorData = concatBytes(
106
+ rpIdHash,
107
+ new Uint8Array([5]),
108
+ new Uint8Array([0, 0, 0, 1])
109
+ );
110
+ const clientDataJSON = utf8ToBytes(
111
+ JSON.stringify({ type: "webauthn.get", challenge: challengeB64, origin })
112
+ );
113
+ const payload = sha256(concatBytes(authenticatorData, sha256(clientDataJSON)));
114
+ const sig = p256.sign(payload, privateKey);
115
+ const s = options.forceHighS ? p256.CURVE.n - sig.s : sig.s;
116
+ const signatureDer = new p256.Signature(sig.r, s).toDERRawBytes();
117
+ return { authenticatorData, clientDataJSON, signatureDer };
118
+ }
119
+ return {
120
+ publicKey,
121
+ credentialId,
122
+ privateKey,
123
+ create() {
124
+ return Promise.resolve({ id: credentialId, rawId: credIdBytes, attestationObject });
125
+ },
126
+ get(getOptions) {
127
+ const challengeB64 = getOptions.challenge ? bytesToBase64Url(getOptions.challenge) : "mock";
128
+ const a = signAssertion(challengeB64);
129
+ return Promise.resolve({
130
+ id: credentialId,
131
+ rawId: credIdBytes,
132
+ authenticatorData: a.authenticatorData,
133
+ clientDataJSON: a.clientDataJSON,
134
+ signature: a.signatureDer
135
+ });
136
+ },
137
+ sign(challenge) {
138
+ const a = signAssertion(challenge);
139
+ return {
140
+ authenticatorData: a.authenticatorData,
141
+ clientDataJSON: a.clientDataJSON,
142
+ signature: a.signatureDer,
143
+ credentialId: credIdBytes
144
+ };
145
+ }
146
+ };
147
+ }
148
+ function createInMemoryBackend() {
149
+ const registry = /* @__PURE__ */ new Map();
150
+ let nonce = 0;
151
+ return {
152
+ registry,
153
+ deployer: {
154
+ deploy({ publicKey, credentialId }) {
155
+ const contractId = StrKey.encodeContract(
156
+ Buffer.from(sha256(utf8ToBytes("account:" + credentialId)))
157
+ );
158
+ registry.set(credentialId, { contractId, publicKey });
159
+ return Promise.resolve({ contractId, txHash: `mock-deploy-${String(nonce++)}` });
160
+ }
161
+ },
162
+ indexer: {
163
+ resolveByCredential(credentialId) {
164
+ const account = registry.get(credentialId);
165
+ return Promise.resolve(account ? [{ contractId: account.contractId }] : []);
166
+ }
167
+ },
168
+ submission: {
169
+ send: () => Promise.resolve({ status: "SUCCESS", hash: "mock-tx" })
170
+ }
171
+ };
172
+ }
173
+
174
+ // src/testing/kit.ts
175
+ var TESTNET = "Test SDF Network ; September 2015";
176
+ function inMemoryStorage() {
177
+ const map = /* @__PURE__ */ new Map();
178
+ return { get: (rpId) => map.get(rpId) ?? null, set: (rpId, id) => void map.set(rpId, id) };
179
+ }
180
+ function createPasskeyKit(options) {
181
+ const networkPassphrase = options.networkPassphrase ?? TESTNET;
182
+ const rpName = options.rpName ?? options.rpId;
183
+ let webauthn;
184
+ let deployer;
185
+ let indexer;
186
+ let storage;
187
+ let signer;
188
+ if (options.mode === "mock") {
189
+ const auth = mockAuthenticator({
190
+ rpId: options.rpId,
191
+ seed: options.seed,
192
+ forceHighS: options.forceHighS
193
+ });
194
+ const backend = createInMemoryBackend();
195
+ webauthn = auth;
196
+ deployer = backend.deployer;
197
+ indexer = backend.indexer;
198
+ signer = auth.sign;
199
+ storage = inMemoryStorage();
200
+ } else {
201
+ if (!options.webauthn || !options.deployer || !options.indexer || !options.signer) {
202
+ throw new Error("live mode requires webauthn, deployer, indexer and signer");
203
+ }
204
+ webauthn = options.webauthn;
205
+ deployer = options.deployer;
206
+ indexer = options.indexer;
207
+ signer = options.signer;
208
+ storage = options.storage ?? inMemoryStorage();
209
+ }
210
+ return {
211
+ mode: options.mode,
212
+ rpId: options.rpId,
213
+ createPasskey: (input) => createPasskey({
214
+ rpId: options.rpId,
215
+ rpName,
216
+ userName: input?.userName ?? "user",
217
+ deployer,
218
+ webauthn,
219
+ storage
220
+ }),
221
+ connect: () => connect({
222
+ rpId: options.rpId,
223
+ indexer,
224
+ webauthn,
225
+ storage,
226
+ silentMediationSupported: false
227
+ }),
228
+ recover: () => recover({ rpId: options.rpId, indexer, webauthn }),
229
+ signAuthEntry: (entryXdr) => signAuthEntry(entryXdr, { networkPassphrase, sign: signer })
230
+ };
231
+ }
232
+
233
+ export { createInMemoryBackend, createPasskeyKit, mockAuthenticator };
234
+ //# sourceMappingURL=testing.js.map
235
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/cborEncode.ts","../src/testing/mockAuthenticator.ts","../src/testing/inMemory.ts","../src/testing/kit.ts"],"names":[],"mappings":"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","file":"testing.js","sourcesContent":["import type { CborValue } from './cbor';\nimport { utf8ToBytes } from './encoding';\n\n/**\n * Minimal CBOR encoder — the inverse of `cbor.ts`, supporting the same major\n * types (uint, negint, byte string, text string, array, map). Used by the\n * deterministic mock authenticator (S15) to synthesize real attestationObject /\n * COSE-key bytes, so the mock create path goes through the exact same\n * `extractPublicKeyFromAttestationObject` as production. Not canonical-ordered\n * (our decoder is order-agnostic) and intentionally narrow.\n */\nfunction head(major: number, arg: number): number[] {\n const m = major << 5;\n if (arg < 24) return [m | arg];\n if (arg < 0x100) return [m | 24, arg];\n if (arg < 0x10000) return [m | 25, (arg >> 8) & 0xff, arg & 0xff];\n return [m | 26, (arg >>> 24) & 0xff, (arg >> 16) & 0xff, (arg >> 8) & 0xff, arg & 0xff];\n}\n\nfunction write(value: CborValue, out: number[]): void {\n if (typeof value === 'number' && Number.isInteger(value)) {\n if (value >= 0) out.push(...head(0, value));\n else out.push(...head(1, -1 - value));\n } else if (value instanceof Uint8Array) {\n out.push(...head(2, value.length));\n for (const b of value) out.push(b);\n } else if (typeof value === 'string') {\n const bytes = utf8ToBytes(value);\n out.push(...head(3, bytes.length));\n for (const b of bytes) out.push(b);\n } else if (Array.isArray(value)) {\n out.push(...head(4, value.length));\n for (const item of value) write(item, out);\n } else if (value instanceof Map) {\n out.push(...head(5, value.size));\n for (const [k, v] of value) {\n write(k, out);\n write(v, out);\n }\n } else {\n throw new Error('CBOR encode: unsupported value');\n }\n}\n\nexport function encodeCbor(value: CborValue): Uint8Array {\n const out: number[] = [];\n write(value, out);\n return Uint8Array.from(out);\n}\n","import { p256 } from '@noble/curves/nist';\nimport { sha256 } from '../internal/sha256';\nimport { concatBytes } from '../internal/bytes';\nimport { bytesToBase64Url, utf8ToBytes } from '../internal/encoding';\nimport { encodeCbor } from '../internal/cborEncode';\nimport type { CborValue } from '../internal/cbor';\nimport type {\n WebAuthnClient,\n WebAuthnCreateResult,\n WebAuthnGetOptions,\n WebAuthnGetResult,\n} from '../ceremonies/types';\nimport type { AssertionResult } from '../soroban/sign';\n\nexport interface MockAuthenticatorOptions {\n rpId: string;\n origin?: string;\n /** Deterministic seed → keypair + credentialId. */\n seed?: string;\n /** Emit high-S signatures, to exercise the perpetual low-S guard (S04). */\n forceHighS?: boolean;\n}\n\nexport interface MockAuthenticator extends WebAuthnClient {\n readonly publicKey: Uint8Array; // 65-byte SEC-1\n readonly credentialId: string; // base64url\n readonly privateKey: Uint8Array;\n /** WebAuthnSigner for the Soroban sign path (challenge already base64url). */\n sign(challenge: string): AssertionResult;\n}\n\nfunction deriveScalar(seed: string): Uint8Array {\n const n = p256.CURVE.n;\n let scalar = BigInt('0x' + bytesToHexLocal(sha256(utf8ToBytes('priv:' + seed)))) % n;\n if (scalar === 0n) scalar = 1n;\n const hex = scalar.toString(16).padStart(64, '0');\n return Uint8Array.from((hex.match(/../g) ?? []).map((h) => parseInt(h, 16)));\n}\nfunction bytesToHexLocal(bytes: Uint8Array): string {\n let hex = '';\n for (const b of bytes) hex += b.toString(16).padStart(2, '0');\n return hex;\n}\n\n/**\n * A deterministic, in-memory WebAuthn authenticator for the mock kit (S15). It\n * synthesizes a REAL attestationObject / COSE key (so `createPasskey` runs the\n * exact production extraction path) and signs assertions with the same P-256\n * key — optionally as high-S to prove the low-S normalization guard.\n */\nexport function mockAuthenticator(options: MockAuthenticatorOptions): MockAuthenticator {\n const seed = options.seed ?? 'mock-authenticator';\n const origin = options.origin ?? `https://${options.rpId}`;\n const privateKey = deriveScalar(seed);\n const publicKey = p256.getPublicKey(privateKey, false); // 0x04 ‖ X ‖ Y\n const x = publicKey.slice(1, 33);\n const y = publicKey.slice(33, 65);\n const credIdBytes = sha256(utf8ToBytes('cred:' + seed)).slice(0, 16);\n const credentialId = bytesToBase64Url(credIdBytes);\n const rpIdHash = sha256(utf8ToBytes(options.rpId));\n\n const coseKey = encodeCbor(\n new Map<number | string, CborValue>([\n [1, 2], // kty EC2\n [3, -7], // alg ES256\n [-1, 1], // crv P-256\n [-2, x],\n [-3, y],\n ]),\n );\n\n const attestedAuthData = concatBytes(\n rpIdHash,\n new Uint8Array([0x45]), // UP | UV | AT\n new Uint8Array([0, 0, 0, 0]), // signCount\n new Uint8Array(16), // aaguid\n new Uint8Array([0, credIdBytes.length]),\n credIdBytes,\n coseKey,\n );\n const attestationObject = encodeCbor(\n new Map<number | string, CborValue>([\n ['fmt', 'none'],\n ['attStmt', new Map<number | string, CborValue>()],\n ['authData', attestedAuthData],\n ]),\n );\n\n function signAssertion(challengeB64: string): {\n authenticatorData: Uint8Array;\n clientDataJSON: Uint8Array;\n signatureDer: Uint8Array;\n } {\n const authenticatorData = concatBytes(\n rpIdHash,\n new Uint8Array([0x05]),\n new Uint8Array([0, 0, 0, 1]),\n );\n const clientDataJSON = utf8ToBytes(\n JSON.stringify({ type: 'webauthn.get', challenge: challengeB64, origin }),\n );\n const payload = sha256(concatBytes(authenticatorData, sha256(clientDataJSON)));\n const sig = p256.sign(payload, privateKey); // low-S by default\n const s = options.forceHighS ? p256.CURVE.n - sig.s : sig.s;\n const signatureDer = new p256.Signature(sig.r, s).toDERRawBytes();\n return { authenticatorData, clientDataJSON, signatureDer };\n }\n\n return {\n publicKey,\n credentialId,\n privateKey,\n create(): Promise<WebAuthnCreateResult> {\n return Promise.resolve({ id: credentialId, rawId: credIdBytes, attestationObject });\n },\n get(getOptions: WebAuthnGetOptions): Promise<WebAuthnGetResult> {\n const challengeB64 = getOptions.challenge ? bytesToBase64Url(getOptions.challenge) : 'mock';\n const a = signAssertion(challengeB64);\n return Promise.resolve({\n id: credentialId,\n rawId: credIdBytes,\n authenticatorData: a.authenticatorData,\n clientDataJSON: a.clientDataJSON,\n signature: a.signatureDer,\n });\n },\n sign(challenge: string): AssertionResult {\n const a = signAssertion(challenge);\n return {\n authenticatorData: a.authenticatorData,\n clientDataJSON: a.clientDataJSON,\n signature: a.signatureDer,\n credentialId: credIdBytes,\n };\n },\n };\n}\n","import { StrKey } from '@stellar/stellar-sdk';\nimport { sha256 } from '../internal/sha256';\nimport { utf8ToBytes } from '../internal/encoding';\nimport type { AccountDeployer } from '../ceremonies/types';\nimport type { IndexerAdapter, SubmissionAdapter } from '../adapters/types';\n\nexport interface InMemoryBackend {\n deployer: AccountDeployer;\n indexer: IndexerAdapter;\n submission: SubmissionAdapter;\n /** credentialId → { contractId, publicKey } — shared so create/connect/recover agree. */\n registry: Map<string, { contractId: string; publicKey: Uint8Array }>;\n}\n\n/**\n * Deterministic, zero-IO backend for the mock kit: the deployer derives a stable\n * C-address from the credentialId and records it; the indexer resolves from the\n * same registry; submission is a no-op SUCCESS.\n *\n * The address is a real StrKey contract id (checksummed, decodable), so a mock\n * account can be fed straight into `new Address(...)` / auth-entry XDR the same way\n * a deployed one is. It is deterministic but arbitrary: it is not the address the\n * factory would deploy for this credential (that is {@link deriveAccountAddress}).\n */\nexport function createInMemoryBackend(): InMemoryBackend {\n const registry = new Map<string, { contractId: string; publicKey: Uint8Array }>();\n let nonce = 0;\n return {\n registry,\n deployer: {\n deploy({ publicKey, credentialId }) {\n const contractId = StrKey.encodeContract(\n Buffer.from(sha256(utf8ToBytes('account:' + credentialId))),\n );\n registry.set(credentialId, { contractId, publicKey });\n return Promise.resolve({ contractId, txHash: `mock-deploy-${String(nonce++)}` });\n },\n },\n indexer: {\n resolveByCredential(credentialId) {\n const account = registry.get(credentialId);\n return Promise.resolve(account ? [{ contractId: account.contractId }] : []);\n },\n },\n submission: {\n send: () => Promise.resolve({ status: 'SUCCESS', hash: 'mock-tx' }),\n },\n };\n}\n","import { createPasskey as createPasskeyCeremony } from '../ceremonies/create';\nimport { connect as connectCeremony, type ConnectResult } from '../ceremonies/connect';\nimport { recover as recoverCeremony, type RecoverResult } from '../ceremonies/recover';\nimport { signAuthEntry as signAuthEntryFn, type WebAuthnSigner } from '../soroban/sign';\nimport type { AccountDeployer, CredentialStorage, WebAuthnClient } from '../ceremonies/types';\nimport type { IndexerAdapter, SubmissionAdapter } from '../adapters/types';\nimport type { PasskeyCredential } from '../types';\nimport { mockAuthenticator } from './mockAuthenticator';\nimport { createInMemoryBackend } from './inMemory';\n\nconst TESTNET = 'Test SDF Network ; September 2015';\n\nexport interface CreatePasskeyKitOptions {\n mode: 'mock' | 'live';\n rpId: string;\n rpName?: string;\n networkPassphrase?: string;\n // mock-mode knobs\n seed?: string;\n forceHighS?: boolean;\n // live-mode dependencies\n webauthn?: WebAuthnClient;\n deployer?: AccountDeployer;\n indexer?: IndexerAdapter;\n submission?: SubmissionAdapter;\n storage?: CredentialStorage;\n signer?: WebAuthnSigner;\n}\n\nexport interface PasskeyKit {\n readonly mode: 'mock' | 'live';\n readonly rpId: string;\n createPasskey(input?: { userName?: string }): Promise<PasskeyCredential>;\n connect(): Promise<ConnectResult | null>;\n recover(): Promise<RecoverResult[]>;\n signAuthEntry(entryXdr: string): Promise<string>;\n}\n\nfunction inMemoryStorage(): CredentialStorage {\n const map = new Map<string, string>();\n return { get: (rpId) => map.get(rpId) ?? null, set: (rpId, id) => void map.set(rpId, id) };\n}\n\n/**\n * The downstream-adopter kit (S15, Deliverable #6). `mode:'mock'` wires a\n * deterministic in-memory authenticator + backend (zero network IO) so the\n * happy path matches the live path's SHAPE — swap `mock → live` and the demo\n * stays green. `mode:'live'` takes real adapters + a WebAuthn signer.\n */\nexport function createPasskeyKit(options: CreatePasskeyKitOptions): PasskeyKit {\n const networkPassphrase = options.networkPassphrase ?? TESTNET;\n const rpName = options.rpName ?? options.rpId;\n\n let webauthn: WebAuthnClient;\n let deployer: AccountDeployer;\n let indexer: IndexerAdapter;\n let storage: CredentialStorage;\n let signer: WebAuthnSigner;\n\n if (options.mode === 'mock') {\n const auth = mockAuthenticator({\n rpId: options.rpId,\n seed: options.seed,\n forceHighS: options.forceHighS,\n });\n const backend = createInMemoryBackend();\n webauthn = auth;\n deployer = backend.deployer;\n indexer = backend.indexer;\n signer = auth.sign;\n storage = inMemoryStorage();\n } else {\n if (!options.webauthn || !options.deployer || !options.indexer || !options.signer) {\n throw new Error('live mode requires webauthn, deployer, indexer and signer');\n }\n webauthn = options.webauthn;\n deployer = options.deployer;\n indexer = options.indexer;\n signer = options.signer;\n storage = options.storage ?? inMemoryStorage();\n }\n\n return {\n mode: options.mode,\n rpId: options.rpId,\n createPasskey: (input) =>\n createPasskeyCeremony({\n rpId: options.rpId,\n rpName,\n userName: input?.userName ?? 'user',\n deployer,\n webauthn,\n storage,\n }),\n connect: () =>\n connectCeremony({\n rpId: options.rpId,\n indexer,\n webauthn,\n storage,\n silentMediationSupported: false,\n }),\n recover: () => recoverCeremony({ rpId: options.rpId, indexer, webauthn }),\n signAuthEntry: (entryXdr) => signAuthEntryFn(entryXdr, { networkPassphrase, sign: signer }),\n };\n}\n"]}
@@ -0,0 +1,125 @@
1
+ type ResidentKeyRequirement = 'discouraged' | 'preferred' | 'required';
2
+ type UserVerificationRequirement = 'discouraged' | 'preferred' | 'required';
3
+ interface BuildCreateOptionsInput {
4
+ rpId: string;
5
+ rpName: string;
6
+ userName: string;
7
+ /** Stable, opaque user handle. Defaults to UTF-8 bytes of `userName`. */
8
+ userId?: Uint8Array;
9
+ userDisplayName?: string;
10
+ /** Raw challenge bytes (base64url-encoded into the options). */
11
+ challenge: Uint8Array;
12
+ residentKey?: ResidentKeyRequirement;
13
+ userVerification?: UserVerificationRequirement;
14
+ timeout?: number;
15
+ }
16
+ /** ES256-only credential parameter. The `alg: -7` literal is non-negotiable. */
17
+ interface PubKeyCredParam {
18
+ type: 'public-key';
19
+ alg: -7;
20
+ }
21
+ interface PublicKeyCredentialCreationOptionsJSON {
22
+ rp: {
23
+ id: string;
24
+ name: string;
25
+ };
26
+ user: {
27
+ id: string;
28
+ name: string;
29
+ displayName: string;
30
+ };
31
+ challenge: string;
32
+ pubKeyCredParams: PubKeyCredParam[];
33
+ authenticatorSelection: {
34
+ residentKey: ResidentKeyRequirement;
35
+ requireResidentKey: boolean;
36
+ userVerification: UserVerificationRequirement;
37
+ };
38
+ attestation: 'none';
39
+ timeout: number;
40
+ }
41
+ /**
42
+ * Build WebAuthn registration options that offer ES256 *and only* ES256
43
+ * (`pubKeyCredParams: [{ type: 'public-key', alg: -7 }]`) — invariant #1.
44
+ * Soroban verifies only secp256r1, so we never advertise any other algorithm.
45
+ */
46
+ declare function buildCreateOptions(input: BuildCreateOptionsInput): PublicKeyCredentialCreationOptionsJSON;
47
+
48
+ /**
49
+ * S12 (YK-438) — the two adapter interfaces. The ONLY infra coupling points, so
50
+ * the SDK is composable, not monolithic. Ceremonies (S13) depend on these
51
+ * interfaces, never on a concrete backend.
52
+ */
53
+ interface SubmitResult {
54
+ status: 'SUCCESS' | 'PENDING' | 'FAILED';
55
+ /** Transaction hash (hex), when known. */
56
+ hash: string;
57
+ /** Decoded contract return value on success (implementation-defined). */
58
+ returnValue?: unknown;
59
+ /** base64 XDR of the failure result, when failed. */
60
+ errorResultXdr?: string;
61
+ }
62
+ /** How a signed operation reaches the network. */
63
+ interface SubmissionAdapter {
64
+ send(signedTxXdr: string): Promise<SubmitResult>;
65
+ }
66
+ interface ResolvedAccount {
67
+ /** Soroban smart-account C-address. */
68
+ contractId: string;
69
+ }
70
+ /** credentialId → smart-account address lookup. */
71
+ interface IndexerAdapter {
72
+ resolveByCredential(credentialId: string): Promise<ResolvedAccount[]>;
73
+ }
74
+
75
+ /** Normalized WebAuthn results + the pluggable dependencies the ceremonies use. */
76
+ interface WebAuthnCreateResult {
77
+ /** base64url credential id. */
78
+ id: string;
79
+ rawId: Uint8Array;
80
+ attestationObject: Uint8Array;
81
+ }
82
+ interface WebAuthnGetResult {
83
+ id: string;
84
+ rawId: Uint8Array;
85
+ authenticatorData: Uint8Array;
86
+ clientDataJSON: Uint8Array;
87
+ /** DER signature as returned by the authenticator. */
88
+ signature: Uint8Array;
89
+ }
90
+ interface WebAuthnGetOptions {
91
+ rpId: string;
92
+ challenge?: Uint8Array;
93
+ /** base64url credential ids; empty/omitted ⇒ discoverable (recover path). */
94
+ allowCredentials?: string[];
95
+ mediation?: 'silent' | 'optional' | 'conditional' | 'required';
96
+ userVerification?: 'discouraged' | 'preferred' | 'required';
97
+ }
98
+
99
+ /** Abstraction over `navigator.credentials` so ceremonies are testable + isomorphic. */
100
+ interface WebAuthnClient {
101
+ create(options: PublicKeyCredentialCreationOptionsJSON): Promise<WebAuthnCreateResult>;
102
+ get(options: WebAuthnGetOptions): Promise<WebAuthnGetResult>;
103
+ }
104
+ /** Per-rpId credential-id persistence (localStorage by default). */
105
+ interface CredentialStorage {
106
+ get(rpId: string): string | null;
107
+ set(rpId: string, credentialId: string): void;
108
+ }
109
+ /**
110
+ * Deploys a smart account for a freshly-created passkey via the factory (through
111
+ * a SubmissionAdapter) and returns its C-address. Injected because the factory
112
+ * wiring is contract-specific (kalepail webauthn-wallet / OZ) — provided by the
113
+ * kit module (S17) / demo (S21); we don't reinvent the contract layer here.
114
+ */
115
+ interface AccountDeployer {
116
+ deploy(input: {
117
+ publicKey: Uint8Array;
118
+ credentialId: string;
119
+ }): Promise<{
120
+ contractId: string;
121
+ txHash?: string;
122
+ }>;
123
+ }
124
+
125
+ export { type AccountDeployer as A, type BuildCreateOptionsInput as B, type CredentialStorage as C, type IndexerAdapter as I, type PubKeyCredParam as P, type ResidentKeyRequirement as R, type SubmissionAdapter as S, type UserVerificationRequirement as U, type WebAuthnClient as W, type PublicKeyCredentialCreationOptionsJSON as a, type ResolvedAccount as b, type SubmitResult as c, type WebAuthnCreateResult as d, type WebAuthnGetOptions as e, type WebAuthnGetResult as f, buildCreateOptions as g };
@@ -0,0 +1,125 @@
1
+ type ResidentKeyRequirement = 'discouraged' | 'preferred' | 'required';
2
+ type UserVerificationRequirement = 'discouraged' | 'preferred' | 'required';
3
+ interface BuildCreateOptionsInput {
4
+ rpId: string;
5
+ rpName: string;
6
+ userName: string;
7
+ /** Stable, opaque user handle. Defaults to UTF-8 bytes of `userName`. */
8
+ userId?: Uint8Array;
9
+ userDisplayName?: string;
10
+ /** Raw challenge bytes (base64url-encoded into the options). */
11
+ challenge: Uint8Array;
12
+ residentKey?: ResidentKeyRequirement;
13
+ userVerification?: UserVerificationRequirement;
14
+ timeout?: number;
15
+ }
16
+ /** ES256-only credential parameter. The `alg: -7` literal is non-negotiable. */
17
+ interface PubKeyCredParam {
18
+ type: 'public-key';
19
+ alg: -7;
20
+ }
21
+ interface PublicKeyCredentialCreationOptionsJSON {
22
+ rp: {
23
+ id: string;
24
+ name: string;
25
+ };
26
+ user: {
27
+ id: string;
28
+ name: string;
29
+ displayName: string;
30
+ };
31
+ challenge: string;
32
+ pubKeyCredParams: PubKeyCredParam[];
33
+ authenticatorSelection: {
34
+ residentKey: ResidentKeyRequirement;
35
+ requireResidentKey: boolean;
36
+ userVerification: UserVerificationRequirement;
37
+ };
38
+ attestation: 'none';
39
+ timeout: number;
40
+ }
41
+ /**
42
+ * Build WebAuthn registration options that offer ES256 *and only* ES256
43
+ * (`pubKeyCredParams: [{ type: 'public-key', alg: -7 }]`) — invariant #1.
44
+ * Soroban verifies only secp256r1, so we never advertise any other algorithm.
45
+ */
46
+ declare function buildCreateOptions(input: BuildCreateOptionsInput): PublicKeyCredentialCreationOptionsJSON;
47
+
48
+ /**
49
+ * S12 (YK-438) — the two adapter interfaces. The ONLY infra coupling points, so
50
+ * the SDK is composable, not monolithic. Ceremonies (S13) depend on these
51
+ * interfaces, never on a concrete backend.
52
+ */
53
+ interface SubmitResult {
54
+ status: 'SUCCESS' | 'PENDING' | 'FAILED';
55
+ /** Transaction hash (hex), when known. */
56
+ hash: string;
57
+ /** Decoded contract return value on success (implementation-defined). */
58
+ returnValue?: unknown;
59
+ /** base64 XDR of the failure result, when failed. */
60
+ errorResultXdr?: string;
61
+ }
62
+ /** How a signed operation reaches the network. */
63
+ interface SubmissionAdapter {
64
+ send(signedTxXdr: string): Promise<SubmitResult>;
65
+ }
66
+ interface ResolvedAccount {
67
+ /** Soroban smart-account C-address. */
68
+ contractId: string;
69
+ }
70
+ /** credentialId → smart-account address lookup. */
71
+ interface IndexerAdapter {
72
+ resolveByCredential(credentialId: string): Promise<ResolvedAccount[]>;
73
+ }
74
+
75
+ /** Normalized WebAuthn results + the pluggable dependencies the ceremonies use. */
76
+ interface WebAuthnCreateResult {
77
+ /** base64url credential id. */
78
+ id: string;
79
+ rawId: Uint8Array;
80
+ attestationObject: Uint8Array;
81
+ }
82
+ interface WebAuthnGetResult {
83
+ id: string;
84
+ rawId: Uint8Array;
85
+ authenticatorData: Uint8Array;
86
+ clientDataJSON: Uint8Array;
87
+ /** DER signature as returned by the authenticator. */
88
+ signature: Uint8Array;
89
+ }
90
+ interface WebAuthnGetOptions {
91
+ rpId: string;
92
+ challenge?: Uint8Array;
93
+ /** base64url credential ids; empty/omitted ⇒ discoverable (recover path). */
94
+ allowCredentials?: string[];
95
+ mediation?: 'silent' | 'optional' | 'conditional' | 'required';
96
+ userVerification?: 'discouraged' | 'preferred' | 'required';
97
+ }
98
+
99
+ /** Abstraction over `navigator.credentials` so ceremonies are testable + isomorphic. */
100
+ interface WebAuthnClient {
101
+ create(options: PublicKeyCredentialCreationOptionsJSON): Promise<WebAuthnCreateResult>;
102
+ get(options: WebAuthnGetOptions): Promise<WebAuthnGetResult>;
103
+ }
104
+ /** Per-rpId credential-id persistence (localStorage by default). */
105
+ interface CredentialStorage {
106
+ get(rpId: string): string | null;
107
+ set(rpId: string, credentialId: string): void;
108
+ }
109
+ /**
110
+ * Deploys a smart account for a freshly-created passkey via the factory (through
111
+ * a SubmissionAdapter) and returns its C-address. Injected because the factory
112
+ * wiring is contract-specific (kalepail webauthn-wallet / OZ) — provided by the
113
+ * kit module (S17) / demo (S21); we don't reinvent the contract layer here.
114
+ */
115
+ interface AccountDeployer {
116
+ deploy(input: {
117
+ publicKey: Uint8Array;
118
+ credentialId: string;
119
+ }): Promise<{
120
+ contractId: string;
121
+ txHash?: string;
122
+ }>;
123
+ }
124
+
125
+ export { type AccountDeployer as A, type BuildCreateOptionsInput as B, type CredentialStorage as C, type IndexerAdapter as I, type PubKeyCredParam as P, type ResidentKeyRequirement as R, type SubmissionAdapter as S, type UserVerificationRequirement as U, type WebAuthnClient as W, type PublicKeyCredentialCreationOptionsJSON as a, type ResolvedAccount as b, type SubmitResult as c, type WebAuthnCreateResult as d, type WebAuthnGetOptions as e, type WebAuthnGetResult as f, buildCreateOptions as g };
@@ -0,0 +1,73 @@
1
+ import './checkAuth-C2AcXqFe.cjs';
2
+ import './types--WNl-Sda.cjs';
3
+ import './sign-Cfg0NM0T.cjs';
4
+
5
+ /**
6
+ * The frozen taxonomy of error codes the SDK can throw. This union is
7
+ * deliberately closed — every failure path maps to exactly one of these.
8
+ */
9
+ declare const KIT_ERROR_CODES: readonly ["USER_CANCELLED", "ES256_NOT_SUPPORTED", "RP_ID_MISMATCH", "ORIGIN_MISMATCH", "CHALLENGE_MISMATCH", "INVALID_SIGNATURE_DER", "INVALID_PUBLIC_KEY", "CONTRACT_AUTH_FAILED", "NETWORK_ERROR", "UNSUPPORTED_AUTHENTICATOR"];
10
+ type KitErrorCode = (typeof KIT_ERROR_CODES)[number];
11
+ /** Structured error carrying a machine-readable {@link KitErrorCode}. */
12
+ declare class KitError extends Error {
13
+ readonly code: KitErrorCode;
14
+ readonly name = "KitError";
15
+ constructor(code: KitErrorCode, message?: string, options?: {
16
+ cause?: unknown;
17
+ });
18
+ }
19
+ declare function isKitError(value: unknown): value is KitError;
20
+
21
+ /**
22
+ * Stable identifiers for the three battle-tested anchors (S04 / YK-430) — the
23
+ * bugs that silently break ~50% of users. Referenced by stable name from the
24
+ * threat model (S14) and the compatibility matrix (S09) so each mitigation has
25
+ * one canonical id across code and docs.
26
+ */
27
+ declare const BATTLE_TESTED_ANCHORS: Readonly<{
28
+ /** Apple Touch ID/Face ID emit high-S ~50% of the time; we normalize to low-S. */
29
+ readonly LOW_S_NORMALIZATION: "low-s-normalization";
30
+ /** Non-ES256 credentials (e.g. some Windows Hello configs) cannot verify on-chain. */
31
+ readonly RS256_HARD_FAIL: "rs256-hard-fail";
32
+ /** Safari requires create/get inside a user activation or it silently rejects. */
33
+ readonly APPLE_USER_GESTURE: "apple-user-gesture";
34
+ }>;
35
+ type BattleTestedAnchor = (typeof BATTLE_TESTED_ANCHORS)[keyof typeof BATTLE_TESTED_ANCHORS];
36
+ /**
37
+ * Anchor `RS256_HARD_FAIL`. The Soroban webauthn-wallet verifies *only*
38
+ * secp256r1, so a non-ES256 credential would produce an unusable account.
39
+ * Hard-fail rather than continue (invariant #1).
40
+ */
41
+ declare function assertES256(alg: number): void;
42
+ interface UserActivationLike {
43
+ isActive: boolean;
44
+ }
45
+ /**
46
+ * Anchor `APPLE_USER_GESTURE`. `navigator.credentials.create/get` on
47
+ * Safari/WebKit must run inside a transient user activation (a real click/tap)
48
+ * or the promise silently rejects. Call this at the very top of a create/sign
49
+ * handler.
50
+ *
51
+ * UI pattern (for S18): never auto-trigger the ceremony from a mount/effect —
52
+ * always gate it behind an explicit user click, and surface `USER_CANCELLED`
53
+ * in the flow state machine. Lenient when `navigator.userActivation` is
54
+ * unavailable (non-browser / older engines) so the SDK stays isomorphic; pass
55
+ * an explicit `{ isActive }` to force the check.
56
+ */
57
+ declare function assertUserActivation(activation?: UserActivationLike): void;
58
+
59
+ /**
60
+ * `@soropass/core/types` — the shared type surface + error taxonomy.
61
+ */
62
+
63
+ /** A passkey-backed Stellar smart account (populated by the S13 ceremonies). */
64
+ interface PasskeyCredential {
65
+ /** Soroban contract (C…) address of the smart account. */
66
+ contractId: string;
67
+ /** base64url credential id returned by the authenticator. */
68
+ credentialId: string;
69
+ /** SEC-1 uncompressed public key (65 bytes). */
70
+ publicKey: Uint8Array;
71
+ }
72
+
73
+ export { BATTLE_TESTED_ANCHORS as B, KIT_ERROR_CODES as K, type PasskeyCredential as P, type BattleTestedAnchor as a, KitError as b, type KitErrorCode as c, assertES256 as d, assertUserActivation as e, isKitError as i };
@@ -0,0 +1,73 @@
1
+ import './checkAuth-C2AcXqFe.js';
2
+ import './types--WNl-Sda.js';
3
+ import './sign-Cfg0NM0T.js';
4
+
5
+ /**
6
+ * The frozen taxonomy of error codes the SDK can throw. This union is
7
+ * deliberately closed — every failure path maps to exactly one of these.
8
+ */
9
+ declare const KIT_ERROR_CODES: readonly ["USER_CANCELLED", "ES256_NOT_SUPPORTED", "RP_ID_MISMATCH", "ORIGIN_MISMATCH", "CHALLENGE_MISMATCH", "INVALID_SIGNATURE_DER", "INVALID_PUBLIC_KEY", "CONTRACT_AUTH_FAILED", "NETWORK_ERROR", "UNSUPPORTED_AUTHENTICATOR"];
10
+ type KitErrorCode = (typeof KIT_ERROR_CODES)[number];
11
+ /** Structured error carrying a machine-readable {@link KitErrorCode}. */
12
+ declare class KitError extends Error {
13
+ readonly code: KitErrorCode;
14
+ readonly name = "KitError";
15
+ constructor(code: KitErrorCode, message?: string, options?: {
16
+ cause?: unknown;
17
+ });
18
+ }
19
+ declare function isKitError(value: unknown): value is KitError;
20
+
21
+ /**
22
+ * Stable identifiers for the three battle-tested anchors (S04 / YK-430) — the
23
+ * bugs that silently break ~50% of users. Referenced by stable name from the
24
+ * threat model (S14) and the compatibility matrix (S09) so each mitigation has
25
+ * one canonical id across code and docs.
26
+ */
27
+ declare const BATTLE_TESTED_ANCHORS: Readonly<{
28
+ /** Apple Touch ID/Face ID emit high-S ~50% of the time; we normalize to low-S. */
29
+ readonly LOW_S_NORMALIZATION: "low-s-normalization";
30
+ /** Non-ES256 credentials (e.g. some Windows Hello configs) cannot verify on-chain. */
31
+ readonly RS256_HARD_FAIL: "rs256-hard-fail";
32
+ /** Safari requires create/get inside a user activation or it silently rejects. */
33
+ readonly APPLE_USER_GESTURE: "apple-user-gesture";
34
+ }>;
35
+ type BattleTestedAnchor = (typeof BATTLE_TESTED_ANCHORS)[keyof typeof BATTLE_TESTED_ANCHORS];
36
+ /**
37
+ * Anchor `RS256_HARD_FAIL`. The Soroban webauthn-wallet verifies *only*
38
+ * secp256r1, so a non-ES256 credential would produce an unusable account.
39
+ * Hard-fail rather than continue (invariant #1).
40
+ */
41
+ declare function assertES256(alg: number): void;
42
+ interface UserActivationLike {
43
+ isActive: boolean;
44
+ }
45
+ /**
46
+ * Anchor `APPLE_USER_GESTURE`. `navigator.credentials.create/get` on
47
+ * Safari/WebKit must run inside a transient user activation (a real click/tap)
48
+ * or the promise silently rejects. Call this at the very top of a create/sign
49
+ * handler.
50
+ *
51
+ * UI pattern (for S18): never auto-trigger the ceremony from a mount/effect —
52
+ * always gate it behind an explicit user click, and surface `USER_CANCELLED`
53
+ * in the flow state machine. Lenient when `navigator.userActivation` is
54
+ * unavailable (non-browser / older engines) so the SDK stays isomorphic; pass
55
+ * an explicit `{ isActive }` to force the check.
56
+ */
57
+ declare function assertUserActivation(activation?: UserActivationLike): void;
58
+
59
+ /**
60
+ * `@soropass/core/types` — the shared type surface + error taxonomy.
61
+ */
62
+
63
+ /** A passkey-backed Stellar smart account (populated by the S13 ceremonies). */
64
+ interface PasskeyCredential {
65
+ /** Soroban contract (C…) address of the smart account. */
66
+ contractId: string;
67
+ /** base64url credential id returned by the authenticator. */
68
+ credentialId: string;
69
+ /** SEC-1 uncompressed public key (65 bytes). */
70
+ publicKey: Uint8Array;
71
+ }
72
+
73
+ export { BATTLE_TESTED_ANCHORS as B, KIT_ERROR_CODES as K, type PasskeyCredential as P, type BattleTestedAnchor as a, KitError as b, type KitErrorCode as c, assertES256 as d, assertUserActivation as e, isKitError as i };