@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.
- package/dist/checkAuth-C2AcXqFe.d.cts +110 -0
- package/dist/checkAuth-C2AcXqFe.d.ts +110 -0
- package/dist/chunk-AHFGTIBY.js +36 -0
- package/dist/chunk-AHFGTIBY.js.map +1 -0
- package/dist/chunk-AMYFJQAC.js +29 -0
- package/dist/chunk-AMYFJQAC.js.map +1 -0
- package/dist/chunk-BIRF5I6I.js +265 -0
- package/dist/chunk-BIRF5I6I.js.map +1 -0
- package/dist/chunk-JNJ2FY45.js +209 -0
- package/dist/chunk-JNJ2FY45.js.map +1 -0
- package/dist/chunk-LB4HOTLV.js +135 -0
- package/dist/chunk-LB4HOTLV.js.map +1 -0
- package/dist/chunk-LM2AZXKZ.js +108 -0
- package/dist/chunk-LM2AZXKZ.js.map +1 -0
- package/dist/chunk-LUDXP56M.js +3 -0
- package/dist/chunk-LUDXP56M.js.map +1 -0
- package/dist/chunk-MMB4ZIW3.js +48 -0
- package/dist/chunk-MMB4ZIW3.js.map +1 -0
- package/dist/chunk-MOLZIRIH.js +22 -0
- package/dist/chunk-MOLZIRIH.js.map +1 -0
- package/dist/chunk-OGSUGATA.js +3 -0
- package/dist/chunk-OGSUGATA.js.map +1 -0
- package/dist/chunk-TPBBZNPP.js +30 -0
- package/dist/chunk-TPBBZNPP.js.map +1 -0
- package/dist/chunk-UQKNPO44.js +32 -0
- package/dist/chunk-UQKNPO44.js.map +1 -0
- package/dist/chunk-UV5HORMF.js +175 -0
- package/dist/chunk-UV5HORMF.js.map +1 -0
- package/dist/chunk-W75OQKHR.js +133 -0
- package/dist/chunk-W75OQKHR.js.map +1 -0
- package/dist/connect.cjs +166 -0
- package/dist/connect.cjs.map +1 -0
- package/dist/connect.d.cts +24 -0
- package/dist/connect.d.ts +24 -0
- package/dist/connect.js +6 -0
- package/dist/connect.js.map +1 -0
- package/dist/create.cjs +483 -0
- package/dist/create.cjs.map +1 -0
- package/dist/create.d.cts +106 -0
- package/dist/create.d.ts +106 -0
- package/dist/create.js +8 -0
- package/dist/create.js.map +1 -0
- package/dist/index.cjs +1542 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +197 -0
- package/dist/index.d.ts +197 -0
- package/dist/index.js +354 -0
- package/dist/index.js.map +1 -0
- package/dist/recover-0wbOXDjR.d.cts +23 -0
- package/dist/recover-COnsxhYk.d.ts +23 -0
- package/dist/recover.cjs +802 -0
- package/dist/recover.cjs.map +1 -0
- package/dist/recover.d.cts +49 -0
- package/dist/recover.d.ts +49 -0
- package/dist/recover.js +10 -0
- package/dist/recover.js.map +1 -0
- package/dist/sign-Cfg0NM0T.d.cts +73 -0
- package/dist/sign-Cfg0NM0T.d.ts +73 -0
- package/dist/sign.cjs +883 -0
- package/dist/sign.cjs.map +1 -0
- package/dist/sign.d.cts +143 -0
- package/dist/sign.d.ts +143 -0
- package/dist/sign.js +8 -0
- package/dist/sign.js.map +1 -0
- package/dist/submit-BDKADQq0.d.cts +112 -0
- package/dist/submit-BO0Nh49I.d.ts +112 -0
- package/dist/testing.cjs +955 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +86 -0
- package/dist/testing.d.ts +86 -0
- package/dist/testing.js +235 -0
- package/dist/testing.js.map +1 -0
- package/dist/types--WNl-Sda.d.cts +125 -0
- package/dist/types--WNl-Sda.d.ts +125 -0
- package/dist/types-dMRWEEo0.d.cts +73 -0
- package/dist/types-lW2h8Uxn.d.ts +73 -0
- package/dist/types.cjs +44 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +5 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +117 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/internal/encoding.ts","../src/ceremonies/random.ts","../src/ceremonies/browserClient.ts","../src/ceremonies/connect.ts"],"names":[],"mappings":"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","file":"connect.cjs","sourcesContent":["/**\n * The frozen taxonomy of error codes the SDK can throw. This union is\n * deliberately closed — every failure path maps to exactly one of these.\n */\nexport const KIT_ERROR_CODES = Object.freeze([\n 'USER_CANCELLED',\n 'ES256_NOT_SUPPORTED',\n 'RP_ID_MISMATCH',\n 'ORIGIN_MISMATCH',\n 'CHALLENGE_MISMATCH',\n 'INVALID_SIGNATURE_DER',\n 'INVALID_PUBLIC_KEY',\n 'CONTRACT_AUTH_FAILED',\n 'NETWORK_ERROR',\n 'UNSUPPORTED_AUTHENTICATOR',\n] as const);\n\nexport type KitErrorCode = (typeof KIT_ERROR_CODES)[number];\n\n/** Structured error carrying a machine-readable {@link KitErrorCode}. */\nexport class KitError extends Error {\n readonly code: KitErrorCode;\n override readonly name = 'KitError';\n\n constructor(code: KitErrorCode, message?: string, options?: { cause?: unknown }) {\n super(message ?? code, options);\n this.code = code;\n // Restore the prototype chain so `instanceof KitError` works after\n // down-level transpilation to CJS.\n Object.setPrototypeOf(this, KitError.prototype);\n }\n}\n\nexport function isKitError(value: unknown): value is KitError {\n return value instanceof KitError;\n}\n","/**\n * Isomorphic base64url + UTF-8 codecs. `atob`/`btoa`/`TextEncoder`/`TextDecoder`\n * are globals in modern browsers and Node >= 16, so no platform branch is\n * needed and nothing is bundled.\n */\n\n/** Encode bytes as unpadded base64url. */\nexport function bytesToBase64Url(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/** Decode base64 or base64url (padding optional) to bytes. */\nexport function base64UrlToBytes(input: string): Uint8Array<ArrayBuffer> {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n const binary = atob(padded);\n const out = new Uint8Array(new ArrayBuffer(binary.length));\n for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);\n return out;\n}\n\nexport function utf8ToBytes(text: string): Uint8Array {\n return new TextEncoder().encode(text);\n}\n\nexport function bytesToUtf8(bytes: Uint8Array): string {\n return new TextDecoder().decode(bytes);\n}\n","import { KitError } from '../errors';\n\n/**\n * Cryptographically-random bytes, isomorphic (browser + Node global crypto).\n * Throws instead of silently returning all-zero bytes when no secure RNG is\n * present — an all-zero challenge would be catastrophic, not a soft fallback.\n */\nexport function randomBytes(length: number): Uint8Array<ArrayBuffer> {\n const webcrypto = globalThis.crypto as Crypto | undefined;\n if (typeof webcrypto?.getRandomValues !== 'function') {\n throw new KitError(\n 'UNSUPPORTED_AUTHENTICATOR',\n 'no secure random source (globalThis.crypto.getRandomValues) is available in this environment',\n );\n }\n const out = new Uint8Array(new ArrayBuffer(length));\n webcrypto.getRandomValues(out);\n return out;\n}\n","import { KitError } from '../errors';\nimport { base64UrlToBytes } from '../internal/encoding';\nimport type { PublicKeyCredentialCreationOptionsJSON } from '../webauthn/createOptions';\nimport { randomBytes } from './random';\nimport type {\n CredentialStorage,\n WebAuthnClient,\n WebAuthnCreateResult,\n WebAuthnGetOptions,\n WebAuthnGetResult,\n} from './types';\n\n/**\n * Map a `navigator.credentials` rejection to a `KitError`. Dismissing the OS\n * passkey sheet rejects with a `NotAllowedError` (a DOMException) — surface that\n * as `USER_CANCELLED` so the UI shows the true \"you cancelled\" copy instead of\n * the generic unsupported-authenticator fallback (S20 / S04 polish).\n */\nfunction asKitError(error: unknown): KitError {\n if (error instanceof KitError) return error;\n const name =\n typeof error === 'object' && error !== null && 'name' in error\n ? (error as { name?: unknown }).name\n : undefined;\n if (name === 'NotAllowedError') {\n return new KitError('USER_CANCELLED', 'The passkey prompt was dismissed.', { cause: error });\n }\n const message = error instanceof Error ? error.message : 'WebAuthn request failed';\n // Preserve the original DOMException name (e.g. InvalidStateError / ConstraintError)\n // in the message so diagnostics show the true cause, not just the generic bucket.\n const detail = typeof name === 'string' ? `${name}: ${message}` : message;\n return new KitError('UNSUPPORTED_AUTHENTICATOR', detail, { cause: error });\n}\n\n/** The browser `WebAuthnClient` backed by `navigator.credentials`. */\nexport function browserWebAuthnClient(): WebAuthnClient {\n const credentials = (globalThis as { navigator?: Navigator }).navigator?.credentials;\n if (!credentials) {\n throw new KitError('UNSUPPORTED_AUTHENTICATOR', 'navigator.credentials is unavailable');\n }\n return {\n async create(options: PublicKeyCredentialCreationOptionsJSON): Promise<WebAuthnCreateResult> {\n const publicKey: PublicKeyCredentialCreationOptions = {\n challenge: base64UrlToBytes(options.challenge),\n rp: options.rp,\n user: {\n id: base64UrlToBytes(options.user.id),\n name: options.user.name,\n displayName: options.user.displayName,\n },\n pubKeyCredParams: options.pubKeyCredParams,\n authenticatorSelection: options.authenticatorSelection,\n attestation: options.attestation,\n timeout: options.timeout,\n };\n let credential: PublicKeyCredential | null;\n try {\n credential = (await credentials.create({ publicKey })) as PublicKeyCredential | null;\n } catch (error) {\n throw asKitError(error);\n }\n if (!credential) throw new KitError('USER_CANCELLED', 'credential creation returned null');\n const response = credential.response as AuthenticatorAttestationResponse;\n return {\n id: credential.id,\n rawId: new Uint8Array(credential.rawId),\n attestationObject: new Uint8Array(response.attestationObject),\n };\n },\n async get(options: WebAuthnGetOptions): Promise<WebAuthnGetResult> {\n const publicKey: PublicKeyCredentialRequestOptions = {\n rpId: options.rpId,\n challenge: options.challenge ? new Uint8Array(options.challenge) : randomBytes(32),\n allowCredentials: (options.allowCredentials ?? []).map((id) => ({\n type: 'public-key',\n id: base64UrlToBytes(id),\n })),\n userVerification: options.userVerification,\n };\n const request: CredentialRequestOptions = { publicKey };\n if (options.mediation) request.mediation = options.mediation;\n let credential: PublicKeyCredential | null;\n try {\n credential = (await credentials.get(request)) as PublicKeyCredential | null;\n } catch (error) {\n throw asKitError(error);\n }\n if (!credential) throw new KitError('USER_CANCELLED', 'assertion returned null');\n const response = credential.response as AuthenticatorAssertionResponse;\n return {\n id: credential.id,\n rawId: new Uint8Array(credential.rawId),\n authenticatorData: new Uint8Array(response.authenticatorData),\n clientDataJSON: new Uint8Array(response.clientDataJSON),\n signature: new Uint8Array(response.signature),\n };\n },\n };\n}\n\n/** localStorage-backed credential store, with an in-memory fallback (Node/SSR). */\nexport function defaultCredentialStorage(): CredentialStorage {\n const key = (rpId: string): string => `stellar-passkey:${rpId}`;\n const ls = (globalThis as { localStorage?: Storage }).localStorage;\n if (ls) {\n return {\n get: (rpId) => ls.getItem(key(rpId)),\n set: (rpId, credentialId) => {\n ls.setItem(key(rpId), credentialId);\n },\n };\n }\n const memory = new Map<string, string>();\n return {\n get: (rpId) => memory.get(rpId) ?? null,\n set: (rpId, credentialId) => {\n memory.set(rpId, credentialId);\n },\n };\n}\n","import type { IndexerAdapter } from '../adapters/types';\nimport { browserWebAuthnClient, defaultCredentialStorage } from './browserClient';\nimport type { CredentialStorage, WebAuthnClient } from './types';\n\nexport interface ConnectOptions {\n rpId: string;\n indexer: IndexerAdapter;\n webauthn?: WebAuthnClient;\n storage?: CredentialStorage;\n /** Override silent-mediation detection (default: probe isConditionalMediationAvailable). */\n silentMediationSupported?: boolean;\n}\n\nexport interface ConnectResult {\n contractId: string;\n credentialId: string;\n}\n\nasync function probeConditionalMediation(): Promise<boolean> {\n const pkc = (\n globalThis as {\n PublicKeyCredential?: { isConditionalMediationAvailable?: () => Promise<boolean> };\n }\n ).PublicKeyCredential;\n if (!pkc?.isConditionalMediationAvailable) return false;\n try {\n return await pkc.isConditionalMediationAvailable();\n } catch {\n return false;\n }\n}\n\n/**\n * `connect` — silent reconnect using the stored credential id. Where conditional\n * mediation is available, does a best-effort `mediation:'silent'` liveness check;\n * the C-address is resolved via the IndexerAdapter regardless, so connect\n * degrades gracefully where silent mediation is unsupported. Returns null when\n * there is no stored credential (the caller should `recover`) or no account.\n */\nexport async function connect(options: ConnectOptions): Promise<ConnectResult | null> {\n const storage = options.storage ?? defaultCredentialStorage();\n const credentialId = storage.get(options.rpId);\n if (!credentialId) return null;\n\n const silentSupported = options.silentMediationSupported ?? (await probeConditionalMediation());\n if (silentSupported) {\n const webauthn = options.webauthn ?? browserWebAuthnClient();\n try {\n await webauthn.get({\n rpId: options.rpId,\n allowCredentials: [credentialId],\n mediation: 'silent',\n });\n } catch {\n // A silent get may no-op or reject; resolution is via the indexer.\n }\n }\n\n const accounts = await options.indexer.resolveByCredential(credentialId);\n const contractId = accounts[0]?.contractId;\n return contractId ? { contractId, credentialId } : null;\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { I as IndexerAdapter, W as WebAuthnClient, C as CredentialStorage } from './types--WNl-Sda.cjs';
|
|
2
|
+
|
|
3
|
+
interface ConnectOptions {
|
|
4
|
+
rpId: string;
|
|
5
|
+
indexer: IndexerAdapter;
|
|
6
|
+
webauthn?: WebAuthnClient;
|
|
7
|
+
storage?: CredentialStorage;
|
|
8
|
+
/** Override silent-mediation detection (default: probe isConditionalMediationAvailable). */
|
|
9
|
+
silentMediationSupported?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface ConnectResult {
|
|
12
|
+
contractId: string;
|
|
13
|
+
credentialId: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `connect` — silent reconnect using the stored credential id. Where conditional
|
|
17
|
+
* mediation is available, does a best-effort `mediation:'silent'` liveness check;
|
|
18
|
+
* the C-address is resolved via the IndexerAdapter regardless, so connect
|
|
19
|
+
* degrades gracefully where silent mediation is unsupported. Returns null when
|
|
20
|
+
* there is no stored credential (the caller should `recover`) or no account.
|
|
21
|
+
*/
|
|
22
|
+
declare function connect(options: ConnectOptions): Promise<ConnectResult | null>;
|
|
23
|
+
|
|
24
|
+
export { type ConnectOptions, type ConnectResult, connect };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { I as IndexerAdapter, W as WebAuthnClient, C as CredentialStorage } from './types--WNl-Sda.js';
|
|
2
|
+
|
|
3
|
+
interface ConnectOptions {
|
|
4
|
+
rpId: string;
|
|
5
|
+
indexer: IndexerAdapter;
|
|
6
|
+
webauthn?: WebAuthnClient;
|
|
7
|
+
storage?: CredentialStorage;
|
|
8
|
+
/** Override silent-mediation detection (default: probe isConditionalMediationAvailable). */
|
|
9
|
+
silentMediationSupported?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface ConnectResult {
|
|
12
|
+
contractId: string;
|
|
13
|
+
credentialId: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `connect` — silent reconnect using the stored credential id. Where conditional
|
|
17
|
+
* mediation is available, does a best-effort `mediation:'silent'` liveness check;
|
|
18
|
+
* the C-address is resolved via the IndexerAdapter regardless, so connect
|
|
19
|
+
* degrades gracefully where silent mediation is unsupported. Returns null when
|
|
20
|
+
* there is no stored credential (the caller should `recover`) or no account.
|
|
21
|
+
*/
|
|
22
|
+
declare function connect(options: ConnectOptions): Promise<ConnectResult | null>;
|
|
23
|
+
|
|
24
|
+
export { type ConnectOptions, type ConnectResult, connect };
|
package/dist/connect.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"connect.js"}
|
package/dist/create.cjs
ADDED
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var nist = require('@noble/curves/nist');
|
|
4
|
+
var stellarSdk = require('@stellar/stellar-sdk');
|
|
5
|
+
var sha256 = require('@noble/hashes/sha256');
|
|
6
|
+
|
|
7
|
+
// src/errors.ts
|
|
8
|
+
var KitError = class _KitError extends Error {
|
|
9
|
+
code;
|
|
10
|
+
name = "KitError";
|
|
11
|
+
constructor(code, message, options) {
|
|
12
|
+
super(message ?? code, options);
|
|
13
|
+
this.code = code;
|
|
14
|
+
Object.setPrototypeOf(this, _KitError.prototype);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var ALG_ES256 = -7;
|
|
18
|
+
function assertES256(alg) {
|
|
19
|
+
if (alg !== ALG_ES256) {
|
|
20
|
+
throw new KitError("ES256_NOT_SUPPORTED", `COSE alg ${alg} is not ES256 (-7)`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function assertUserActivation(activation) {
|
|
24
|
+
const ua = activation ?? globalThis.navigator?.userActivation;
|
|
25
|
+
if (ua && !ua.isActive) {
|
|
26
|
+
throw new KitError(
|
|
27
|
+
"USER_CANCELLED",
|
|
28
|
+
"WebAuthn ceremony must be invoked inside a user activation (click/tap)"
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/internal/encoding.ts
|
|
34
|
+
function bytesToBase64Url(bytes) {
|
|
35
|
+
let binary = "";
|
|
36
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
37
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
38
|
+
}
|
|
39
|
+
function base64UrlToBytes(input) {
|
|
40
|
+
const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
41
|
+
const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
|
|
42
|
+
const binary = atob(padded);
|
|
43
|
+
const out = new Uint8Array(new ArrayBuffer(binary.length));
|
|
44
|
+
for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
function utf8ToBytes(text) {
|
|
48
|
+
return new TextEncoder().encode(text);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/webauthn/createOptions.ts
|
|
52
|
+
function buildCreateOptions(input) {
|
|
53
|
+
const residentKey = input.residentKey ?? "required";
|
|
54
|
+
return {
|
|
55
|
+
rp: { id: input.rpId, name: input.rpName },
|
|
56
|
+
user: {
|
|
57
|
+
id: bytesToBase64Url(input.userId ?? utf8ToBytes(input.userName)),
|
|
58
|
+
name: input.userName,
|
|
59
|
+
displayName: input.userDisplayName ?? input.userName
|
|
60
|
+
},
|
|
61
|
+
challenge: bytesToBase64Url(input.challenge),
|
|
62
|
+
pubKeyCredParams: [{ type: "public-key", alg: -7 }],
|
|
63
|
+
authenticatorSelection: {
|
|
64
|
+
residentKey,
|
|
65
|
+
requireResidentKey: residentKey === "required",
|
|
66
|
+
userVerification: input.userVerification ?? "preferred"
|
|
67
|
+
},
|
|
68
|
+
attestation: "none",
|
|
69
|
+
timeout: input.timeout ?? 6e4
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/internal/bytes.ts
|
|
74
|
+
function concatBytes(...arrays) {
|
|
75
|
+
const total = arrays.reduce((n, a) => n + a.length, 0);
|
|
76
|
+
const out = new Uint8Array(total);
|
|
77
|
+
let offset = 0;
|
|
78
|
+
for (const a of arrays) {
|
|
79
|
+
out.set(a, offset);
|
|
80
|
+
offset += a.length;
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/internal/cbor.ts
|
|
86
|
+
function byteAt(bytes, index) {
|
|
87
|
+
const value = bytes[index];
|
|
88
|
+
if (value === void 0) throw new Error(`CBOR: unexpected end of input at byte ${index}`);
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
var MAX_DEPTH = 16;
|
|
92
|
+
function decodeCbor(bytes, offset = 0, depth = 0) {
|
|
93
|
+
if (depth > MAX_DEPTH) throw new Error("CBOR: maximum nesting depth exceeded");
|
|
94
|
+
const first = byteAt(bytes, offset);
|
|
95
|
+
const major = first >> 5;
|
|
96
|
+
const info = first & 31;
|
|
97
|
+
let pos = offset + 1;
|
|
98
|
+
let argument;
|
|
99
|
+
if (info < 24) {
|
|
100
|
+
argument = info;
|
|
101
|
+
} else if (info === 24) {
|
|
102
|
+
argument = byteAt(bytes, pos);
|
|
103
|
+
pos += 1;
|
|
104
|
+
} else if (info === 25) {
|
|
105
|
+
argument = byteAt(bytes, pos) << 8 | byteAt(bytes, pos + 1);
|
|
106
|
+
pos += 2;
|
|
107
|
+
} else if (info === 26) {
|
|
108
|
+
argument = byteAt(bytes, pos) * 16777216 + (byteAt(bytes, pos + 1) << 16) + (byteAt(bytes, pos + 2) << 8) + byteAt(bytes, pos + 3);
|
|
109
|
+
pos += 4;
|
|
110
|
+
} else {
|
|
111
|
+
throw new Error(`CBOR: unsupported length encoding (additional info ${info})`);
|
|
112
|
+
}
|
|
113
|
+
switch (major) {
|
|
114
|
+
case 0:
|
|
115
|
+
return { value: argument, length: pos - offset };
|
|
116
|
+
case 1:
|
|
117
|
+
return { value: -1 - argument, length: pos - offset };
|
|
118
|
+
case 2: {
|
|
119
|
+
const end = pos + argument;
|
|
120
|
+
if (end > bytes.length) throw new Error("CBOR: byte string exceeds input");
|
|
121
|
+
return { value: bytes.slice(pos, end), length: end - offset };
|
|
122
|
+
}
|
|
123
|
+
case 3: {
|
|
124
|
+
const end = pos + argument;
|
|
125
|
+
if (end > bytes.length) throw new Error("CBOR: text string exceeds input");
|
|
126
|
+
return { value: new TextDecoder().decode(bytes.slice(pos, end)), length: end - offset };
|
|
127
|
+
}
|
|
128
|
+
case 4: {
|
|
129
|
+
const items = [];
|
|
130
|
+
let cursor = pos;
|
|
131
|
+
for (let i = 0; i < argument; i += 1) {
|
|
132
|
+
const item = decodeCbor(bytes, cursor, depth + 1);
|
|
133
|
+
items.push(item.value);
|
|
134
|
+
cursor += item.length;
|
|
135
|
+
}
|
|
136
|
+
return { value: items, length: cursor - offset };
|
|
137
|
+
}
|
|
138
|
+
case 5: {
|
|
139
|
+
const map = /* @__PURE__ */ new Map();
|
|
140
|
+
let cursor = pos;
|
|
141
|
+
for (let i = 0; i < argument; i += 1) {
|
|
142
|
+
const key = decodeCbor(bytes, cursor, depth + 1);
|
|
143
|
+
cursor += key.length;
|
|
144
|
+
const val = decodeCbor(bytes, cursor, depth + 1);
|
|
145
|
+
cursor += val.length;
|
|
146
|
+
if (typeof key.value !== "number" && typeof key.value !== "string") {
|
|
147
|
+
throw new Error("CBOR: unsupported map key type");
|
|
148
|
+
}
|
|
149
|
+
if (map.has(key.value)) {
|
|
150
|
+
throw new Error("CBOR: duplicate map key (non-canonical)");
|
|
151
|
+
}
|
|
152
|
+
map.set(key.value, val.value);
|
|
153
|
+
}
|
|
154
|
+
return { value: map, length: cursor - offset };
|
|
155
|
+
}
|
|
156
|
+
default:
|
|
157
|
+
throw new Error(`CBOR: unsupported major type ${major}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function decodeCborFirst(bytes) {
|
|
161
|
+
return decodeCbor(bytes, 0).value;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/webauthn/authData.ts
|
|
165
|
+
var MIN_LENGTH = 37;
|
|
166
|
+
function parseAuthenticatorData(authData) {
|
|
167
|
+
if (authData.length < MIN_LENGTH) {
|
|
168
|
+
throw new KitError(
|
|
169
|
+
"UNSUPPORTED_AUTHENTICATOR",
|
|
170
|
+
`authenticatorData is ${authData.length} bytes, expected at least ${MIN_LENGTH}`
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
const view = new DataView(authData.buffer, authData.byteOffset, authData.byteLength);
|
|
174
|
+
const rpIdHash = authData.slice(0, 32);
|
|
175
|
+
const bits = authData[32] ?? 0;
|
|
176
|
+
const flags = {
|
|
177
|
+
up: (bits & 1) !== 0,
|
|
178
|
+
uv: (bits & 4) !== 0,
|
|
179
|
+
be: (bits & 8) !== 0,
|
|
180
|
+
bs: (bits & 16) !== 0,
|
|
181
|
+
at: (bits & 64) !== 0,
|
|
182
|
+
ed: (bits & 128) !== 0,
|
|
183
|
+
bits
|
|
184
|
+
};
|
|
185
|
+
const signCount = view.getUint32(33, false);
|
|
186
|
+
const result = { rpIdHash, flags, signCount };
|
|
187
|
+
if (flags.at) {
|
|
188
|
+
if (authData.length < 55) {
|
|
189
|
+
throw new KitError(
|
|
190
|
+
"UNSUPPORTED_AUTHENTICATOR",
|
|
191
|
+
"authenticatorData truncated in attested data"
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
result.aaguid = authData.slice(37, 53);
|
|
195
|
+
const credIdLength = view.getUint16(53, false);
|
|
196
|
+
const credIdEnd = 55 + credIdLength;
|
|
197
|
+
if (authData.length < credIdEnd) {
|
|
198
|
+
throw new KitError(
|
|
199
|
+
"UNSUPPORTED_AUTHENTICATOR",
|
|
200
|
+
"authenticatorData truncated in credentialId"
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
result.credentialId = authData.slice(55, credIdEnd);
|
|
204
|
+
const rest = authData.slice(credIdEnd);
|
|
205
|
+
const { length } = decodeCbor(rest, 0);
|
|
206
|
+
result.credentialPublicKey = rest.slice(0, length);
|
|
207
|
+
}
|
|
208
|
+
return result;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/webauthn/publicKey.ts
|
|
212
|
+
var COSE_KTY = 1;
|
|
213
|
+
var COSE_ALG = 3;
|
|
214
|
+
var COSE_CRV = -1;
|
|
215
|
+
var COSE_X = -2;
|
|
216
|
+
var COSE_Y = -3;
|
|
217
|
+
var KTY_EC2 = 2;
|
|
218
|
+
var CRV_P256 = 1;
|
|
219
|
+
function coseKeyToSec1(coseKey) {
|
|
220
|
+
let decoded;
|
|
221
|
+
try {
|
|
222
|
+
decoded = decodeCborFirst(coseKey);
|
|
223
|
+
} catch (cause) {
|
|
224
|
+
throw new KitError("INVALID_PUBLIC_KEY", "failed to CBOR-decode COSE key", { cause });
|
|
225
|
+
}
|
|
226
|
+
if (!(decoded instanceof Map)) {
|
|
227
|
+
throw new KitError("INVALID_PUBLIC_KEY", "COSE key is not a CBOR map");
|
|
228
|
+
}
|
|
229
|
+
const map = decoded;
|
|
230
|
+
const alg = map.get(COSE_ALG);
|
|
231
|
+
if (typeof alg !== "number") {
|
|
232
|
+
throw new KitError("ES256_NOT_SUPPORTED", `COSE alg ${String(alg)} is not ES256 (-7)`);
|
|
233
|
+
}
|
|
234
|
+
assertES256(alg);
|
|
235
|
+
if (map.get(COSE_KTY) !== KTY_EC2) {
|
|
236
|
+
throw new KitError(
|
|
237
|
+
"INVALID_PUBLIC_KEY",
|
|
238
|
+
`COSE kty ${String(map.get(COSE_KTY))} is not EC2 (2)`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
if (map.get(COSE_CRV) !== CRV_P256) {
|
|
242
|
+
throw new KitError(
|
|
243
|
+
"INVALID_PUBLIC_KEY",
|
|
244
|
+
`COSE crv ${String(map.get(COSE_CRV))} is not P-256 (1)`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
const x = map.get(COSE_X);
|
|
248
|
+
const y = map.get(COSE_Y);
|
|
249
|
+
if (!(x instanceof Uint8Array) || x.length !== 32) {
|
|
250
|
+
throw new KitError("INVALID_PUBLIC_KEY", "COSE key X coordinate is not 32 bytes");
|
|
251
|
+
}
|
|
252
|
+
if (!(y instanceof Uint8Array) || y.length !== 32) {
|
|
253
|
+
throw new KitError("INVALID_PUBLIC_KEY", "COSE key Y coordinate is not 32 bytes");
|
|
254
|
+
}
|
|
255
|
+
const sec1 = concatBytes(new Uint8Array([4]), x, y);
|
|
256
|
+
try {
|
|
257
|
+
nist.p256.Point.fromHex(sec1);
|
|
258
|
+
} catch (cause) {
|
|
259
|
+
throw new KitError("INVALID_PUBLIC_KEY", "public key is not a valid P-256 point", { cause });
|
|
260
|
+
}
|
|
261
|
+
return sec1;
|
|
262
|
+
}
|
|
263
|
+
function extractPublicKeyFromAuthData(authData) {
|
|
264
|
+
const parsed = parseAuthenticatorData(authData);
|
|
265
|
+
if (!parsed.credentialPublicKey) {
|
|
266
|
+
throw new KitError(
|
|
267
|
+
"INVALID_PUBLIC_KEY",
|
|
268
|
+
"authenticatorData has no attested credential public key"
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
return coseKeyToSec1(parsed.credentialPublicKey);
|
|
272
|
+
}
|
|
273
|
+
function extractPublicKeyFromAttestationObject(attestationObject) {
|
|
274
|
+
let decoded;
|
|
275
|
+
try {
|
|
276
|
+
decoded = decodeCborFirst(attestationObject);
|
|
277
|
+
} catch (cause) {
|
|
278
|
+
throw new KitError("INVALID_PUBLIC_KEY", "failed to CBOR-decode attestationObject", { cause });
|
|
279
|
+
}
|
|
280
|
+
if (!(decoded instanceof Map)) {
|
|
281
|
+
throw new KitError("INVALID_PUBLIC_KEY", "attestationObject is not a CBOR map");
|
|
282
|
+
}
|
|
283
|
+
const authData = decoded.get("authData");
|
|
284
|
+
if (!(authData instanceof Uint8Array)) {
|
|
285
|
+
throw new KitError("INVALID_PUBLIC_KEY", "attestationObject has no authData byte string");
|
|
286
|
+
}
|
|
287
|
+
return extractPublicKeyFromAuthData(authData);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/ceremonies/random.ts
|
|
291
|
+
function randomBytes(length) {
|
|
292
|
+
const webcrypto = globalThis.crypto;
|
|
293
|
+
if (typeof webcrypto?.getRandomValues !== "function") {
|
|
294
|
+
throw new KitError(
|
|
295
|
+
"UNSUPPORTED_AUTHENTICATOR",
|
|
296
|
+
"no secure random source (globalThis.crypto.getRandomValues) is available in this environment"
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
const out = new Uint8Array(new ArrayBuffer(length));
|
|
300
|
+
webcrypto.getRandomValues(out);
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/ceremonies/browserClient.ts
|
|
305
|
+
function asKitError(error) {
|
|
306
|
+
if (error instanceof KitError) return error;
|
|
307
|
+
const name = typeof error === "object" && error !== null && "name" in error ? error.name : void 0;
|
|
308
|
+
if (name === "NotAllowedError") {
|
|
309
|
+
return new KitError("USER_CANCELLED", "The passkey prompt was dismissed.", { cause: error });
|
|
310
|
+
}
|
|
311
|
+
const message = error instanceof Error ? error.message : "WebAuthn request failed";
|
|
312
|
+
const detail = typeof name === "string" ? `${name}: ${message}` : message;
|
|
313
|
+
return new KitError("UNSUPPORTED_AUTHENTICATOR", detail, { cause: error });
|
|
314
|
+
}
|
|
315
|
+
function browserWebAuthnClient() {
|
|
316
|
+
const credentials = globalThis.navigator?.credentials;
|
|
317
|
+
if (!credentials) {
|
|
318
|
+
throw new KitError("UNSUPPORTED_AUTHENTICATOR", "navigator.credentials is unavailable");
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
async create(options) {
|
|
322
|
+
const publicKey = {
|
|
323
|
+
challenge: base64UrlToBytes(options.challenge),
|
|
324
|
+
rp: options.rp,
|
|
325
|
+
user: {
|
|
326
|
+
id: base64UrlToBytes(options.user.id),
|
|
327
|
+
name: options.user.name,
|
|
328
|
+
displayName: options.user.displayName
|
|
329
|
+
},
|
|
330
|
+
pubKeyCredParams: options.pubKeyCredParams,
|
|
331
|
+
authenticatorSelection: options.authenticatorSelection,
|
|
332
|
+
attestation: options.attestation,
|
|
333
|
+
timeout: options.timeout
|
|
334
|
+
};
|
|
335
|
+
let credential;
|
|
336
|
+
try {
|
|
337
|
+
credential = await credentials.create({ publicKey });
|
|
338
|
+
} catch (error) {
|
|
339
|
+
throw asKitError(error);
|
|
340
|
+
}
|
|
341
|
+
if (!credential) throw new KitError("USER_CANCELLED", "credential creation returned null");
|
|
342
|
+
const response = credential.response;
|
|
343
|
+
return {
|
|
344
|
+
id: credential.id,
|
|
345
|
+
rawId: new Uint8Array(credential.rawId),
|
|
346
|
+
attestationObject: new Uint8Array(response.attestationObject)
|
|
347
|
+
};
|
|
348
|
+
},
|
|
349
|
+
async get(options) {
|
|
350
|
+
const publicKey = {
|
|
351
|
+
rpId: options.rpId,
|
|
352
|
+
challenge: options.challenge ? new Uint8Array(options.challenge) : randomBytes(32),
|
|
353
|
+
allowCredentials: (options.allowCredentials ?? []).map((id) => ({
|
|
354
|
+
type: "public-key",
|
|
355
|
+
id: base64UrlToBytes(id)
|
|
356
|
+
})),
|
|
357
|
+
userVerification: options.userVerification
|
|
358
|
+
};
|
|
359
|
+
const request = { publicKey };
|
|
360
|
+
if (options.mediation) request.mediation = options.mediation;
|
|
361
|
+
let credential;
|
|
362
|
+
try {
|
|
363
|
+
credential = await credentials.get(request);
|
|
364
|
+
} catch (error) {
|
|
365
|
+
throw asKitError(error);
|
|
366
|
+
}
|
|
367
|
+
if (!credential) throw new KitError("USER_CANCELLED", "assertion returned null");
|
|
368
|
+
const response = credential.response;
|
|
369
|
+
return {
|
|
370
|
+
id: credential.id,
|
|
371
|
+
rawId: new Uint8Array(credential.rawId),
|
|
372
|
+
authenticatorData: new Uint8Array(response.authenticatorData),
|
|
373
|
+
clientDataJSON: new Uint8Array(response.clientDataJSON),
|
|
374
|
+
signature: new Uint8Array(response.signature)
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function defaultCredentialStorage() {
|
|
380
|
+
const key = (rpId) => `stellar-passkey:${rpId}`;
|
|
381
|
+
const ls = globalThis.localStorage;
|
|
382
|
+
if (ls) {
|
|
383
|
+
return {
|
|
384
|
+
get: (rpId) => ls.getItem(key(rpId)),
|
|
385
|
+
set: (rpId, credentialId) => {
|
|
386
|
+
ls.setItem(key(rpId), credentialId);
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
const memory = /* @__PURE__ */ new Map();
|
|
391
|
+
return {
|
|
392
|
+
get: (rpId) => memory.get(rpId) ?? null,
|
|
393
|
+
set: (rpId, credentialId) => {
|
|
394
|
+
memory.set(rpId, credentialId);
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/ceremonies/create.ts
|
|
400
|
+
async function registerPasskey(options) {
|
|
401
|
+
assertUserActivation(options.userActivation);
|
|
402
|
+
const webauthn = options.webauthn ?? browserWebAuthnClient();
|
|
403
|
+
const creationOptions = buildCreateOptions({
|
|
404
|
+
rpId: options.rpId,
|
|
405
|
+
rpName: options.rpName,
|
|
406
|
+
userName: options.userName,
|
|
407
|
+
userId: options.userId,
|
|
408
|
+
challenge: options.challenge ?? randomBytes(32),
|
|
409
|
+
residentKey: options.residentKey,
|
|
410
|
+
userVerification: options.userVerification
|
|
411
|
+
});
|
|
412
|
+
const credential = await webauthn.create(creationOptions);
|
|
413
|
+
const publicKey = extractPublicKeyFromAttestationObject(credential.attestationObject);
|
|
414
|
+
return { credentialId: credential.id, publicKey };
|
|
415
|
+
}
|
|
416
|
+
async function createPasskey(options) {
|
|
417
|
+
const storage = options.storage ?? defaultCredentialStorage();
|
|
418
|
+
const { credentialId, publicKey } = await registerPasskey(options);
|
|
419
|
+
const { contractId } = await options.deployer.deploy({ publicKey, credentialId });
|
|
420
|
+
storage.set(options.rpId, credentialId);
|
|
421
|
+
return { contractId, credentialId, publicKey };
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// src/webauthn/clientData.ts
|
|
425
|
+
function decodeChallenge(challenge) {
|
|
426
|
+
return base64UrlToBytes(challenge);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// src/soroban/address.ts
|
|
430
|
+
function contractIdFromDeployerSalt(deployer, salt, networkPassphrase) {
|
|
431
|
+
let address;
|
|
432
|
+
try {
|
|
433
|
+
address = stellarSdk.Address.fromString(deployer).toScAddress();
|
|
434
|
+
} catch (cause) {
|
|
435
|
+
throw new KitError("CONTRACT_AUTH_FAILED", `invalid deployer address "${deployer}"`, { cause });
|
|
436
|
+
}
|
|
437
|
+
const preimage = stellarSdk.xdr.HashIdPreimage.envelopeTypeContractId(
|
|
438
|
+
new stellarSdk.xdr.HashIdPreimageContractId({
|
|
439
|
+
networkId: stellarSdk.hash(Buffer.from(networkPassphrase)),
|
|
440
|
+
contractIdPreimage: stellarSdk.xdr.ContractIdPreimage.contractIdPreimageFromAddress(
|
|
441
|
+
new stellarSdk.xdr.ContractIdPreimageFromAddress({
|
|
442
|
+
address,
|
|
443
|
+
salt: Buffer.from(salt)
|
|
444
|
+
})
|
|
445
|
+
)
|
|
446
|
+
})
|
|
447
|
+
);
|
|
448
|
+
return stellarSdk.StrKey.encodeContract(stellarSdk.hash(preimage.toXDR()));
|
|
449
|
+
}
|
|
450
|
+
function deriveAccountAddress(options) {
|
|
451
|
+
const { factoryContractId, credentialId, networkPassphrase } = options;
|
|
452
|
+
if (credentialId.length === 0) {
|
|
453
|
+
throw new KitError("CONTRACT_AUTH_FAILED", "deriveAccountAddress: empty credential id");
|
|
454
|
+
}
|
|
455
|
+
return contractIdFromDeployerSalt(
|
|
456
|
+
factoryContractId,
|
|
457
|
+
stellarSdk.hash(Buffer.from(credentialId)),
|
|
458
|
+
// e.crypto().sha256(credential_id)
|
|
459
|
+
networkPassphrase
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
function deriveSmartWalletAddress(options) {
|
|
463
|
+
const raw = decodeChallenge(options.credentialId);
|
|
464
|
+
if (raw.length === 0) {
|
|
465
|
+
throw new KitError("CONTRACT_AUTH_FAILED", "deriveSmartWalletAddress: empty credential id");
|
|
466
|
+
}
|
|
467
|
+
return contractIdFromDeployerSalt(options.deployer, sha256.sha256(raw), options.networkPassphrase);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
exports.assertES256 = assertES256;
|
|
471
|
+
exports.assertUserActivation = assertUserActivation;
|
|
472
|
+
exports.browserWebAuthnClient = browserWebAuthnClient;
|
|
473
|
+
exports.buildCreateOptions = buildCreateOptions;
|
|
474
|
+
exports.coseKeyToSec1 = coseKeyToSec1;
|
|
475
|
+
exports.createPasskey = createPasskey;
|
|
476
|
+
exports.defaultCredentialStorage = defaultCredentialStorage;
|
|
477
|
+
exports.deriveAccountAddress = deriveAccountAddress;
|
|
478
|
+
exports.deriveSmartWalletAddress = deriveSmartWalletAddress;
|
|
479
|
+
exports.extractPublicKeyFromAttestationObject = extractPublicKeyFromAttestationObject;
|
|
480
|
+
exports.extractPublicKeyFromAuthData = extractPublicKeyFromAuthData;
|
|
481
|
+
exports.registerPasskey = registerPasskey;
|
|
482
|
+
//# sourceMappingURL=create.cjs.map
|
|
483
|
+
//# sourceMappingURL=create.cjs.map
|