@soropass/core 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -0
- package/dist/{checkAuth-C2AcXqFe.d.cts → checkAuth-B5ObsEsP.d.cts} +11 -7
- package/dist/{checkAuth-C2AcXqFe.d.ts → checkAuth-B5ObsEsP.d.ts} +11 -7
- package/dist/{chunk-AHFGTIBY.js → chunk-2KLSTE4E.js} +16 -4
- package/dist/chunk-2KLSTE4E.js.map +1 -0
- package/dist/{chunk-KDBIRRF7.js → chunk-42ETVY6V.js} +3 -3
- package/dist/{chunk-KDBIRRF7.js.map → chunk-42ETVY6V.js.map} +1 -1
- package/dist/{chunk-ZQRFIL4P.js → chunk-ODXQCLZL.js} +18 -6
- package/dist/chunk-ODXQCLZL.js.map +1 -0
- package/dist/{chunk-MMB4ZIW3.js → chunk-OHKPNVB3.js} +13 -5
- package/dist/chunk-OHKPNVB3.js.map +1 -0
- package/dist/{chunk-BLFCRWCT.js → chunk-QREICNIW.js} +3 -3
- package/dist/{chunk-BLFCRWCT.js.map → chunk-QREICNIW.js.map} +1 -1
- package/dist/{chunk-W75OQKHR.js → chunk-RFMHMWTY.js} +5 -3
- package/dist/chunk-RFMHMWTY.js.map +1 -0
- package/dist/{chunk-FIRTUNWF.js → chunk-XTLWH3VQ.js} +26 -5
- package/dist/chunk-XTLWH3VQ.js.map +1 -0
- package/dist/connect.cjs +14 -2
- package/dist/connect.cjs.map +1 -1
- package/dist/connect.d.cts +11 -1
- package/dist/connect.d.ts +11 -1
- package/dist/connect.js +1 -1
- package/dist/create.cjs +14 -4
- package/dist/create.cjs.map +1 -1
- package/dist/create.d.cts +20 -12
- package/dist/create.d.ts +20 -12
- package/dist/create.js +2 -2
- package/dist/index.cjs +77 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -9
- package/dist/index.d.ts +9 -9
- package/dist/index.js +20 -11
- package/dist/index.js.map +1 -1
- package/dist/{recover-0wbOXDjR.d.cts → recover-BOq0DQaU.d.cts} +1 -1
- package/dist/{recover-COnsxhYk.d.ts → recover-CL_jZ2kN.d.ts} +1 -1
- package/dist/recover.cjs +24 -3
- package/dist/recover.cjs.map +1 -1
- package/dist/recover.d.cts +4 -4
- package/dist/recover.d.ts +4 -4
- package/dist/recover.js +3 -3
- package/dist/{sign-B4JV2Inn.d.ts → sign-O5d7Moma.d.cts} +15 -0
- package/dist/{sign-B4JV2Inn.d.cts → sign-O5d7Moma.d.ts} +15 -0
- package/dist/sign.cjs +39 -6
- package/dist/sign.cjs.map +1 -1
- package/dist/sign.d.cts +27 -14
- package/dist/sign.d.ts +27 -14
- package/dist/sign.js +3 -3
- package/dist/{submit-BsKXOCkL.d.cts → submit-BKogb6Y8.d.cts} +2 -2
- package/dist/{submit-CZt8fNRf.d.ts → submit-CKJp7XgZ.d.ts} +2 -2
- package/dist/testing.cjs +46 -8
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +8 -5
- package/dist/testing.d.ts +8 -5
- package/dist/testing.js +8 -5
- package/dist/testing.js.map +1 -1
- package/dist/{types-C3VIw5Iu.d.ts → types-BJsL-q2B.d.ts} +3 -3
- package/dist/{types-DLcXrud8.d.cts → types-B_pVAg-T.d.cts} +3 -3
- package/dist/{types--WNl-Sda.d.cts → types-CJluKV7s.d.cts} +8 -0
- package/dist/{types--WNl-Sda.d.ts → types-CJluKV7s.d.ts} +8 -0
- package/dist/types.d.cts +4 -4
- package/dist/types.d.ts +4 -4
- package/package.json +23 -2
- package/dist/chunk-AHFGTIBY.js.map +0 -1
- package/dist/chunk-FIRTUNWF.js.map +0 -1
- package/dist/chunk-MMB4ZIW3.js.map +0 -1
- package/dist/chunk-W75OQKHR.js.map +0 -1
- package/dist/chunk-ZQRFIL4P.js.map +0 -1
package/dist/create.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { P as PasskeyCredential } from './types-
|
|
2
|
-
export { d as assertES256, e as assertUserActivation } from './types-
|
|
3
|
-
import { A as AccountDeployer, W as WebAuthnClient, C as CredentialStorage } from './types
|
|
4
|
-
export { g as buildCreateOptions } from './types
|
|
5
|
-
import './checkAuth-
|
|
1
|
+
import { P as PasskeyCredential } from './types-BJsL-q2B.js';
|
|
2
|
+
export { d as assertES256, e as assertUserActivation } from './types-BJsL-q2B.js';
|
|
3
|
+
import { A as AccountDeployer, W as WebAuthnClient, C as CredentialStorage } from './types-CJluKV7s.js';
|
|
4
|
+
export { g as buildCreateOptions } from './types-CJluKV7s.js';
|
|
5
|
+
import './checkAuth-B5ObsEsP.js';
|
|
6
6
|
import '@stellar/stellar-sdk';
|
|
7
|
-
import './sign-
|
|
7
|
+
import './sign-O5d7Moma.js';
|
|
8
8
|
|
|
9
9
|
interface CreatePasskeyOptions {
|
|
10
10
|
rpId: string;
|
|
@@ -66,17 +66,25 @@ declare function extractPublicKeyFromAttestationObject(attestationObject: Uint8A
|
|
|
66
66
|
interface DeriveAccountAddressOptions {
|
|
67
67
|
/** The AccountFactory contract C-address — the deployer. */
|
|
68
68
|
factoryContractId: string;
|
|
69
|
-
/** The credential-id bytes the factory salts
|
|
69
|
+
/** The credential-id bytes the factory salts (utf-8 of the base64url id in our factory). */
|
|
70
70
|
credentialId: Uint8Array;
|
|
71
|
+
/**
|
|
72
|
+
* SEC-1 (65-byte) public key of the founding passkey. The v0.2 factory binds
|
|
73
|
+
* it into the deploy salt (`sha256(credential_id ‖ public_key)`) so a public
|
|
74
|
+
* credential id alone cannot be used to squat a derived address.
|
|
75
|
+
*/
|
|
76
|
+
publicKey: Uint8Array;
|
|
71
77
|
networkPassphrase: string;
|
|
72
78
|
}
|
|
73
79
|
/**
|
|
74
80
|
* Derive the deterministic C-address of the `webauthn-account` our AccountFactory
|
|
75
|
-
* deploys for a passkey — with NO network round-trip. The factory salts by
|
|
76
|
-
* `sha256(credential_id)` and deploys with
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
81
|
+
* deploys for a passkey — with NO network round-trip. The v0.2 factory salts by
|
|
82
|
+
* `sha256(credential_id ‖ public_key)` and deploys with
|
|
83
|
+
* `deployer().with_current_contract(salt)`. Binding the public key is the F1
|
|
84
|
+
* fix: a credential id is public (the factory emits it), so salting by it alone
|
|
85
|
+
* let anyone pre-deploy at a victim's address with their own key. For the
|
|
86
|
+
* passkey-kit v1 smart-wallet, use {@link deriveSmartWalletAddress} instead
|
|
87
|
+
* (different deployer + salt-input scheme).
|
|
80
88
|
*/
|
|
81
89
|
declare function deriveAccountAddress(options: DeriveAccountAddressOptions): string;
|
|
82
90
|
interface DeriveSmartWalletAddressOptions {
|
package/dist/create.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { deriveAccountAddress, deriveSmartWalletAddress } from './chunk-
|
|
2
|
-
export { buildCreateOptions, coseKeyToSec1, createPasskey, extractPublicKeyFromAttestationObject, extractPublicKeyFromAuthData, registerPasskey } from './chunk-
|
|
1
|
+
export { deriveAccountAddress, deriveSmartWalletAddress } from './chunk-OHKPNVB3.js';
|
|
2
|
+
export { buildCreateOptions, coseKeyToSec1, createPasskey, extractPublicKeyFromAttestationObject, extractPublicKeyFromAuthData, registerPasskey } from './chunk-RFMHMWTY.js';
|
|
3
3
|
import './chunk-JNJ2FY45.js';
|
|
4
4
|
export { browserWebAuthnClient, defaultCredentialStorage } from './chunk-LB4HOTLV.js';
|
|
5
5
|
export { assertES256, assertUserActivation } from './chunk-TPBBZNPP.js';
|
package/dist/index.cjs
CHANGED
|
@@ -91,7 +91,9 @@ function buildCreateOptions(input) {
|
|
|
91
91
|
authenticatorSelection: {
|
|
92
92
|
residentKey,
|
|
93
93
|
requireResidentKey: residentKey === "required",
|
|
94
|
-
|
|
94
|
+
// The v0.2 account requires the User-Verified flag at sign time, so
|
|
95
|
+
// register with 'required' to enroll authenticators that can produce it.
|
|
96
|
+
userVerification: input.userVerification ?? "required"
|
|
95
97
|
},
|
|
96
98
|
attestation: "none",
|
|
97
99
|
timeout: input.timeout ?? 6e4
|
|
@@ -534,14 +536,22 @@ function contractIdFromDeployerSalt(deployer, salt, networkPassphrase) {
|
|
|
534
536
|
return stellarSdk.StrKey.encodeContract(stellarSdk.hash(preimage.toXDR()));
|
|
535
537
|
}
|
|
536
538
|
function deriveAccountAddress(options) {
|
|
537
|
-
const { factoryContractId, credentialId, networkPassphrase } = options;
|
|
539
|
+
const { factoryContractId, credentialId, publicKey, networkPassphrase } = options;
|
|
538
540
|
if (credentialId.length === 0) {
|
|
539
541
|
throw new KitError("CONTRACT_AUTH_FAILED", "deriveAccountAddress: empty credential id");
|
|
540
542
|
}
|
|
543
|
+
if (publicKey.length !== 65) {
|
|
544
|
+
throw new KitError(
|
|
545
|
+
"CONTRACT_AUTH_FAILED",
|
|
546
|
+
`deriveAccountAddress: public key must be 65-byte SEC-1 (got ${String(publicKey.length)})`
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
const saltInput = new Uint8Array(credentialId.length + publicKey.length);
|
|
550
|
+
saltInput.set(credentialId, 0);
|
|
551
|
+
saltInput.set(publicKey, credentialId.length);
|
|
541
552
|
return contractIdFromDeployerSalt(
|
|
542
553
|
factoryContractId,
|
|
543
|
-
stellarSdk.hash(Buffer.from(
|
|
544
|
-
// e.crypto().sha256(credential_id)
|
|
554
|
+
stellarSdk.hash(Buffer.from(saltInput)),
|
|
545
555
|
networkPassphrase
|
|
546
556
|
);
|
|
547
557
|
}
|
|
@@ -605,13 +615,16 @@ function browserPasskeySigner(options) {
|
|
|
605
615
|
rpId: options.rpId,
|
|
606
616
|
challenge: base64UrlToBytes(challenge),
|
|
607
617
|
allowCredentials: options.allowCredentials ?? [],
|
|
608
|
-
|
|
618
|
+
// The v0.2 account requires the User-Verified flag, so default to
|
|
619
|
+
// 'required'; a signature without UV fails on-chain.
|
|
620
|
+
userVerification: options.userVerification ?? "required"
|
|
609
621
|
});
|
|
610
622
|
return {
|
|
611
623
|
authenticatorData: assertion.authenticatorData,
|
|
612
624
|
clientDataJSON: assertion.clientDataJSON,
|
|
613
625
|
signature: assertion.signature,
|
|
614
|
-
credentialId: assertion.rawId
|
|
626
|
+
credentialId: assertion.rawId,
|
|
627
|
+
publicKey: options.publicKey
|
|
615
628
|
};
|
|
616
629
|
};
|
|
617
630
|
}
|
|
@@ -634,10 +647,24 @@ function authEntryChallengeBytes(entry, networkPassphrase) {
|
|
|
634
647
|
function authEntryChallenge(entry, networkPassphrase) {
|
|
635
648
|
return bytesToBase64Url(authEntryChallengeBytes(entry, networkPassphrase));
|
|
636
649
|
}
|
|
637
|
-
function applyAssertionToEntry(entry, assertion) {
|
|
638
|
-
entry.credentials().address().signature(
|
|
650
|
+
function applyAssertionToEntry(entry, assertion, publicKey) {
|
|
651
|
+
entry.credentials().address().signature(buildSingleSignerSignatureScVal(assertion, publicKey));
|
|
639
652
|
return entry;
|
|
640
653
|
}
|
|
654
|
+
function buildSingleSignerSignatureScVal(assertion, publicKey) {
|
|
655
|
+
if (publicKey.length !== 65) {
|
|
656
|
+
throw new KitError(
|
|
657
|
+
"CONTRACT_AUTH_FAILED",
|
|
658
|
+
`single-signer signature needs a 65-byte SEC-1 public key (got ${String(publicKey.length)})`
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
return stellarSdk.xdr.ScVal.scvMap([
|
|
662
|
+
bytesField("authenticator_data", assertion.authenticatorData),
|
|
663
|
+
bytesField("client_data_json", assertion.clientDataJSON),
|
|
664
|
+
bytesField("public_key", publicKey),
|
|
665
|
+
bytesField("signature", assertion.signature)
|
|
666
|
+
]);
|
|
667
|
+
}
|
|
641
668
|
function buildSignatureScVal(assertion) {
|
|
642
669
|
return stellarSdk.xdr.ScVal.scvMap([
|
|
643
670
|
bytesField("authenticator_data", assertion.authenticatorData),
|
|
@@ -790,7 +817,14 @@ async function signEntryInPlace(entry, options) {
|
|
|
790
817
|
if (options.target === "smart-wallet") {
|
|
791
818
|
applyAssertionToSmartWalletEntry(entry, normalized);
|
|
792
819
|
} else {
|
|
793
|
-
|
|
820
|
+
const publicKey = options.publicKey ?? assertion.publicKey;
|
|
821
|
+
if (publicKey === void 0) {
|
|
822
|
+
throw new KitError(
|
|
823
|
+
"CONTRACT_AUTH_FAILED",
|
|
824
|
+
"single-signer signing requires the signer public key: set SorobanSignOptions.publicKey or return publicKey from the signer"
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
applyAssertionToEntry(entry, normalized, publicKey);
|
|
794
828
|
}
|
|
795
829
|
}
|
|
796
830
|
async function signAuthEntry(entryXdr, options) {
|
|
@@ -926,17 +960,26 @@ function verifySecp256r1StructMap(structMap, publicKey, signaturePayload) {
|
|
|
926
960
|
}
|
|
927
961
|
const digest = sha256.sha256(concatBytes(authenticatorData, sha256.sha256(clientDataJSON)));
|
|
928
962
|
const signatureValid = nist.p256.verify(signature, digest, publicKey, {
|
|
929
|
-
lowS:
|
|
963
|
+
lowS: true,
|
|
930
964
|
format: "compact"
|
|
931
965
|
});
|
|
932
966
|
return { ok: challengeBound && signatureValid, challengeBound, signatureValid };
|
|
933
967
|
}
|
|
968
|
+
function bytesEqual(a, b) {
|
|
969
|
+
if (a.length !== b.length) return false;
|
|
970
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
971
|
+
return true;
|
|
972
|
+
}
|
|
934
973
|
function referenceCheckAuth(entry, publicKey, networkPassphrase) {
|
|
935
974
|
if (entry.credentials().switch().name !== "sorobanCredentialsAddress") {
|
|
936
975
|
return fail("no address credentials");
|
|
937
976
|
}
|
|
938
977
|
const structMap = entry.credentials().address().signature().map();
|
|
939
978
|
if (!structMap) return fail("signature is not a Secp256r1Signature map");
|
|
979
|
+
const inline = structMap.find((x) => x.key().sym().toString() === "public_key");
|
|
980
|
+
if (inline && !bytesEqual(new Uint8Array(inline.val().bytes()), publicKey)) {
|
|
981
|
+
return fail("unknown signer: inline public_key is not the enrolled key");
|
|
982
|
+
}
|
|
940
983
|
const signaturePayload = authEntryChallengeBytes(entry, networkPassphrase);
|
|
941
984
|
const r = verifySecp256r1StructMap(structMap, publicKey, signaturePayload);
|
|
942
985
|
return { success: r.ok, challengeBound: r.challengeBound, signatureValid: r.signatureValid };
|
|
@@ -1108,8 +1151,20 @@ async function connect(options) {
|
|
|
1108
1151
|
}
|
|
1109
1152
|
}
|
|
1110
1153
|
const accounts = await options.indexer.resolveByCredential(credentialId);
|
|
1111
|
-
const
|
|
1112
|
-
return
|
|
1154
|
+
const selected = selectAccount(accounts, options.publicKey);
|
|
1155
|
+
return selected ? { contractId: selected.contractId, credentialId } : null;
|
|
1156
|
+
}
|
|
1157
|
+
function bytesEqual2(a, b) {
|
|
1158
|
+
if (a.length !== b.length) return false;
|
|
1159
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
1160
|
+
return true;
|
|
1161
|
+
}
|
|
1162
|
+
function selectAccount(accounts, publicKey) {
|
|
1163
|
+
if (publicKey) {
|
|
1164
|
+
const match = accounts.find((a) => a.publicKey && bytesEqual2(a.publicKey, publicKey));
|
|
1165
|
+
return match ? { contractId: match.contractId } : null;
|
|
1166
|
+
}
|
|
1167
|
+
return accounts[0] ?? null;
|
|
1113
1168
|
}
|
|
1114
1169
|
|
|
1115
1170
|
// src/ceremonies/recover.ts
|
|
@@ -1292,7 +1347,10 @@ function defaultMatch(event, credentialId) {
|
|
|
1292
1347
|
const cred = credRaw instanceof Uint8Array ? new TextDecoder().decode(credRaw) : String(credRaw ?? "");
|
|
1293
1348
|
if (tag === "deployed" && cred === credentialId) {
|
|
1294
1349
|
const addr2 = decodeNative(event.value);
|
|
1295
|
-
|
|
1350
|
+
const pkRaw = topics.length >= 3 ? decodeNative(topics[2]) : void 0;
|
|
1351
|
+
const publicKey = pkRaw instanceof Uint8Array ? pkRaw : void 0;
|
|
1352
|
+
if (typeof addr2 === "string" && addr2.startsWith("C"))
|
|
1353
|
+
return { contractId: addr2, publicKey };
|
|
1296
1354
|
}
|
|
1297
1355
|
}
|
|
1298
1356
|
const haystack = [event.value, ...topics].map((v) => v.toXDR("base64")).join("|");
|
|
@@ -1375,6 +1433,12 @@ function factoryDeployer(options) {
|
|
|
1375
1433
|
const source = stellarSdk.Keypair.fromSecret(options.sourceSecret);
|
|
1376
1434
|
return {
|
|
1377
1435
|
async deploy(input) {
|
|
1436
|
+
if (input.publicKey.length !== 65) {
|
|
1437
|
+
throw new KitError(
|
|
1438
|
+
"CONTRACT_AUTH_FAILED",
|
|
1439
|
+
`factory deploy: public key must be 65-byte SEC-1 (got ${String(input.publicKey.length)})`
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1378
1442
|
const pk = stellarSdk.nativeToScVal(Buffer.from(input.publicKey), { type: "bytes" });
|
|
1379
1443
|
const cred = stellarSdk.nativeToScVal(Buffer.from(new TextEncoder().encode(input.credentialId)), {
|
|
1380
1444
|
type: "bytes"
|