@soropass/core 0.1.0 → 0.2.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 → 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-UQKNPO44.js → chunk-42ETVY6V.js} +3 -3
- package/dist/{chunk-UQKNPO44.js.map → chunk-42ETVY6V.js.map} +1 -1
- package/dist/{chunk-LM2AZXKZ.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-UV5HORMF.js → chunk-QREICNIW.js} +3 -3
- package/dist/{chunk-UV5HORMF.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-BIRF5I6I.js → chunk-XTLWH3VQ.js} +31 -7
- 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 +81 -14
- 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 +28 -4
- 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-Cfg0NM0T.d.cts → sign-O5d7Moma.d.cts} +23 -0
- package/dist/{sign-Cfg0NM0T.d.ts → sign-O5d7Moma.d.ts} +23 -0
- package/dist/sign.cjs +43 -7
- 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-BDKADQq0.d.cts → submit-BKogb6Y8.d.cts} +2 -2
- package/dist/{submit-BO0Nh49I.d.ts → submit-CKJp7XgZ.d.ts} +2 -2
- package/dist/testing.cjs +68 -9
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +14 -6
- package/dist/testing.d.ts +14 -6
- package/dist/testing.js +30 -7
- package/dist/testing.js.map +1 -1
- package/dist/{types-lW2h8Uxn.d.ts → types-BJsL-q2B.d.ts} +3 -3
- package/dist/{types-dMRWEEo0.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 +1 -1
- package/dist/chunk-AHFGTIBY.js.map +0 -1
- package/dist/chunk-BIRF5I6I.js.map +0 -1
- package/dist/chunk-LM2AZXKZ.js.map +0 -1
- package/dist/chunk-MMB4ZIW3.js.map +0 -1
- package/dist/chunk-W75OQKHR.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),
|
|
@@ -780,7 +807,7 @@ async function signEntryInPlace(entry, options) {
|
|
|
780
807
|
const challenge = authEntryChallenge(entry, options.networkPassphrase);
|
|
781
808
|
const assertion = await options.sign(challenge);
|
|
782
809
|
if (options.verify) preflightAssertion(assertion, challenge, options.verify);
|
|
783
|
-
const signature = assertion.signature.length === 64 ? assertion.signature : derToCompactLowS(assertion.signature);
|
|
810
|
+
const signature = assertion.signature.length === 64 ? normalizeLowS(assertion.signature) : derToCompactLowS(assertion.signature);
|
|
784
811
|
const normalized = {
|
|
785
812
|
credentialId: assertion.credentialId,
|
|
786
813
|
authenticatorData: 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) {
|
|
@@ -823,6 +857,9 @@ async function signTransaction(txXdr, options) {
|
|
|
823
857
|
const entries = op.body().invokeHostFunctionOp().auth();
|
|
824
858
|
for (const entry of entries) {
|
|
825
859
|
if (entry.credentials().switch().name !== "sorobanCredentialsAddress") continue;
|
|
860
|
+
if (options.signerAddress !== void 0 && stellarSdk.Address.fromScAddress(entry.credentials().address().address()).toString() !== options.signerAddress) {
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
826
863
|
await signEntryInPlace(entry, options);
|
|
827
864
|
}
|
|
828
865
|
}
|
|
@@ -923,17 +960,26 @@ function verifySecp256r1StructMap(structMap, publicKey, signaturePayload) {
|
|
|
923
960
|
}
|
|
924
961
|
const digest = sha256.sha256(concatBytes(authenticatorData, sha256.sha256(clientDataJSON)));
|
|
925
962
|
const signatureValid = nist.p256.verify(signature, digest, publicKey, {
|
|
926
|
-
lowS:
|
|
963
|
+
lowS: true,
|
|
927
964
|
format: "compact"
|
|
928
965
|
});
|
|
929
966
|
return { ok: challengeBound && signatureValid, challengeBound, signatureValid };
|
|
930
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
|
+
}
|
|
931
973
|
function referenceCheckAuth(entry, publicKey, networkPassphrase) {
|
|
932
974
|
if (entry.credentials().switch().name !== "sorobanCredentialsAddress") {
|
|
933
975
|
return fail("no address credentials");
|
|
934
976
|
}
|
|
935
977
|
const structMap = entry.credentials().address().signature().map();
|
|
936
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
|
+
}
|
|
937
983
|
const signaturePayload = authEntryChallengeBytes(entry, networkPassphrase);
|
|
938
984
|
const r = verifySecp256r1StructMap(structMap, publicKey, signaturePayload);
|
|
939
985
|
return { success: r.ok, challengeBound: r.challengeBound, signatureValid: r.signatureValid };
|
|
@@ -1105,8 +1151,20 @@ async function connect(options) {
|
|
|
1105
1151
|
}
|
|
1106
1152
|
}
|
|
1107
1153
|
const accounts = await options.indexer.resolveByCredential(credentialId);
|
|
1108
|
-
const
|
|
1109
|
-
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;
|
|
1110
1168
|
}
|
|
1111
1169
|
|
|
1112
1170
|
// src/ceremonies/recover.ts
|
|
@@ -1289,7 +1347,10 @@ function defaultMatch(event, credentialId) {
|
|
|
1289
1347
|
const cred = credRaw instanceof Uint8Array ? new TextDecoder().decode(credRaw) : String(credRaw ?? "");
|
|
1290
1348
|
if (tag === "deployed" && cred === credentialId) {
|
|
1291
1349
|
const addr2 = decodeNative(event.value);
|
|
1292
|
-
|
|
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 };
|
|
1293
1354
|
}
|
|
1294
1355
|
}
|
|
1295
1356
|
const haystack = [event.value, ...topics].map((v) => v.toXDR("base64")).join("|");
|
|
@@ -1372,6 +1433,12 @@ function factoryDeployer(options) {
|
|
|
1372
1433
|
const source = stellarSdk.Keypair.fromSecret(options.sourceSecret);
|
|
1373
1434
|
return {
|
|
1374
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
|
+
}
|
|
1375
1442
|
const pk = stellarSdk.nativeToScVal(Buffer.from(input.publicKey), { type: "bytes" });
|
|
1376
1443
|
const cred = stellarSdk.nativeToScVal(Buffer.from(new TextEncoder().encode(input.credentialId)), {
|
|
1377
1444
|
type: "bytes"
|