@calimero-network/mero-js 29.7.6 → 29.7.7
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/cloud-v2/client.d.ts +20 -1
- package/dist/cloud-v2/client.js +32 -11
- package/dist/cloud-v2/index.d.ts +1 -1
- package/dist/cloud-v2/passkey.d.ts +18 -2
- package/dist/cloud-v2/passkey.js +16 -5
- package/dist/index.browser.mjs +3 -3
- package/dist/index.browser.mjs.map +3 -3
- package/dist/index.cjs +43 -17
- package/dist/index.cjs.map +2 -2
- package/dist/index.mjs +43 -17
- package/dist/index.mjs.map +2 -2
- package/package.json +1 -1
|
@@ -408,6 +408,13 @@ export interface ServedOrigins {
|
|
|
408
408
|
*/
|
|
409
409
|
export interface SignInOptions {
|
|
410
410
|
origin?: string | null;
|
|
411
|
+
/**
|
|
412
|
+
* Closes an open passkey prompt when it aborts (a Cancel button): the
|
|
413
|
+
* ceremony then rejects as a dismissed prompt does (`NotAllowedError`; in a
|
|
414
|
+
* sign-up's confirmation, {@link ConfirmCancelled}). Given to the
|
|
415
|
+
* {@link PasskeyProvider} as `signal`.
|
|
416
|
+
*/
|
|
417
|
+
signal?: AbortSignal;
|
|
411
418
|
}
|
|
412
419
|
/**
|
|
413
420
|
* {@link SignInOptions} for a sign-up, and the invite it is made with: an
|
|
@@ -648,9 +655,21 @@ export declare class CalimeroClient {
|
|
|
648
655
|
*/
|
|
649
656
|
refresh(): Promise<CalimeroSession>;
|
|
650
657
|
private exchangeRefresh;
|
|
658
|
+
/**
|
|
659
|
+
* End this session. The client is signed out whether or not the node
|
|
660
|
+
* answers: the revoke (`POST /auth/logout`) is attempted, and its failure
|
|
661
|
+
* (the node unreachable, say) is thrown after the session is dropped, so a
|
|
662
|
+
* caller can say the server may still hold it, but no request after this
|
|
663
|
+
* one carries its token.
|
|
664
|
+
*/
|
|
651
665
|
signOut(): Promise<void>;
|
|
652
|
-
/**
|
|
666
|
+
/**
|
|
667
|
+
* End every session of the signed-in account, on every device, this one
|
|
668
|
+
* too. Like {@link signOut}, this client is signed out even when the
|
|
669
|
+
* request fails, and the failure is thrown.
|
|
670
|
+
*/
|
|
653
671
|
signOutEverywhere(): Promise<void>;
|
|
672
|
+
private signingOut;
|
|
654
673
|
/** Who the credential is: the account, how it signed in, and the package (`app`) and `origin` a session is bound to. */
|
|
655
674
|
me(): Promise<MeInfo>;
|
|
656
675
|
/**
|
package/dist/cloud-v2/client.js
CHANGED
|
@@ -511,13 +511,14 @@ export class CalimeroClient {
|
|
|
511
511
|
const origin = this.pageOrigin(options);
|
|
512
512
|
const invite = options.invite ? { invite: options.invite } : {};
|
|
513
513
|
const begin = await this.begin('auth/passkey/register/begin', origin === undefined ? { name, ...invite } : { name, origin, ...invite }, origin);
|
|
514
|
-
const
|
|
514
|
+
const signal = options.signal;
|
|
515
|
+
const registration = await (signal ? passkey.create(begin.options, { signal }) : passkey.create(begin.options));
|
|
515
516
|
// The node checks the sign-up's confirmation with the user present, not
|
|
516
517
|
// verified (core `api.rs`: `rp(node)`, `require_uv: false`), as it made
|
|
517
518
|
// the passkey with `preferred`: asking `required` here would refuse a
|
|
518
519
|
// security key without a PIN after it has made the passkey, leaving a
|
|
519
520
|
// passkey with no account.
|
|
520
|
-
const session = await this.confirmed('POST', 'auth/passkey/register/finish', { challengeId: begin.challengeId, registration, ...invite }, passkey, undefined, 'preferred');
|
|
521
|
+
const session = await this.confirmed('POST', 'auth/passkey/register/finish', { challengeId: begin.challengeId, registration, ...invite }, passkey, undefined, 'preferred', signal);
|
|
521
522
|
this.useSession(session);
|
|
522
523
|
return session;
|
|
523
524
|
}
|
|
@@ -537,7 +538,10 @@ export class CalimeroClient {
|
|
|
537
538
|
const origin = this.pageOrigin(options);
|
|
538
539
|
const begin = await this.begin('auth/passkey/login/begin', origin === undefined ? undefined : { origin }, origin);
|
|
539
540
|
const rpId = begin.options.rpId ?? begin.options.rp?.id ?? '';
|
|
540
|
-
const
|
|
541
|
+
const challenge = fromB64url(begin.options.challenge);
|
|
542
|
+
const assertion = await (options.signal
|
|
543
|
+
? passkey.get(challenge, rpId, undefined, { signal: options.signal })
|
|
544
|
+
: passkey.get(challenge, rpId));
|
|
541
545
|
const session = await this.post('auth/passkey/login/finish', {
|
|
542
546
|
challengeId: begin.challengeId,
|
|
543
547
|
assertion,
|
|
@@ -617,16 +621,32 @@ export class CalimeroClient {
|
|
|
617
621
|
this.useSession(session);
|
|
618
622
|
return session;
|
|
619
623
|
}
|
|
624
|
+
/**
|
|
625
|
+
* End this session. The client is signed out whether or not the node
|
|
626
|
+
* answers: the revoke (`POST /auth/logout`) is attempted, and its failure
|
|
627
|
+
* (the node unreachable, say) is thrown after the session is dropped, so a
|
|
628
|
+
* caller can say the server may still hold it, but no request after this
|
|
629
|
+
* one carries its token.
|
|
630
|
+
*/
|
|
620
631
|
async signOut() {
|
|
621
|
-
await this.
|
|
622
|
-
this.auth = undefined;
|
|
623
|
-
this.current = undefined;
|
|
632
|
+
await this.signingOut('auth/logout');
|
|
624
633
|
}
|
|
625
|
-
/**
|
|
634
|
+
/**
|
|
635
|
+
* End every session of the signed-in account, on every device, this one
|
|
636
|
+
* too. Like {@link signOut}, this client is signed out even when the
|
|
637
|
+
* request fails, and the failure is thrown.
|
|
638
|
+
*/
|
|
626
639
|
async signOutEverywhere() {
|
|
627
|
-
await this.
|
|
628
|
-
|
|
629
|
-
|
|
640
|
+
await this.signingOut('auth/logout-all');
|
|
641
|
+
}
|
|
642
|
+
async signingOut(path) {
|
|
643
|
+
try {
|
|
644
|
+
await this.post(path);
|
|
645
|
+
}
|
|
646
|
+
finally {
|
|
647
|
+
this.auth = undefined;
|
|
648
|
+
this.current = undefined;
|
|
649
|
+
}
|
|
630
650
|
}
|
|
631
651
|
/** Who the credential is: the account, how it signed in, and the package (`app`) and `origin` a session is bound to. */
|
|
632
652
|
me() {
|
|
@@ -915,7 +935,7 @@ export class CalimeroClient {
|
|
|
915
935
|
deleteConfirmed(path, passkey, body = {}) {
|
|
916
936
|
return this.confirmed('DELETE', path, body, passkey);
|
|
917
937
|
}
|
|
918
|
-
async confirmed(method, path, body, passkey, send = (b) => this.json(method, path, b), userVerification = 'required') {
|
|
938
|
+
async confirmed(method, path, body, passkey, send = (b) => this.json(method, path, b), userVerification = 'required', signal) {
|
|
919
939
|
try {
|
|
920
940
|
return await send(body);
|
|
921
941
|
}
|
|
@@ -931,6 +951,7 @@ export class CalimeroClient {
|
|
|
931
951
|
// requirement the node names itself wins.
|
|
932
952
|
assertion = await passkey.get(fromB64url(d.challenge), d.rpId, d.allowCredentials, {
|
|
933
953
|
userVerification: userVerificationOf(d.userVerification, userVerification),
|
|
954
|
+
...(signal ? { signal } : {}),
|
|
934
955
|
});
|
|
935
956
|
}
|
|
936
957
|
catch (declined) {
|
package/dist/cloud-v2/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { claimedRelease, fetchAttestedKey, freshCollateral, MOCK_QUOTE_HEADER }
|
|
|
8
8
|
export type { AttestationDoc, CloudPolicy, CloudReleasePolicy } from './attestation.js';
|
|
9
9
|
export { browserPasskey, b64url, fromB64url } from './passkey.js';
|
|
10
10
|
export { MAX_RECOVERY_NONCE_BYTES, RECOVERY_DOMAIN, newRecoverySeed, parseRecoverySeed, recoveryMessage, recoveryPublicKey, recoverySeedText, signRecovery, } from './recovery.js';
|
|
11
|
-
export type { AssertionJSON, PasskeyGetOptions, PasskeyProvider, PasskeyUserVerification, RegistrationJSON, } from './passkey.js';
|
|
11
|
+
export type { AssertionJSON, PasskeyCreateOptions, PasskeyGetOptions, PasskeyProvider, PasskeyUserVerification, RegistrationJSON, } from './passkey.js';
|
|
12
12
|
export { MAX_REPORT_PAGE, RELEASE_VERIFIER, compareVersions, confirmationCode, consentReturn, pageQuery, pendingApprovalsFrom, publisherBindingBytes, publisherBindingMessage, releaseConsent, releaseNotesUrl, stalledBy, upgradeConsent, verifyReleaseUrl, withdrawConsent, } from './approvals.js';
|
|
13
13
|
export type { ActorKind, AppsReport, Authority, ClusterRelease, ConsentReleaseModel, ConsentRequest, ConsentResult, ConsentScope, ConsentStarted, ConsentStatus, OpenConsentOptions, Governance, LastUpgrade, OpsAppsReport, OpsOrgsReport, PageOptions, PendingApprovals, PendingRelease, PendingUpgrade, PublisherBindingInfo, PublisherProof, ReleaseDeadline, ReleaseRules, ReportScope, ReportedApp, ReportedBundle, ReportedRelease, ReportedReplica, UpgradeAuthority, } from './approvals.js';
|
|
14
14
|
export { DEFAULT_ORG_CAPABILITIES, ORG_CAPABILITIES, orgCapabilities } from './capabilities.js';
|
|
@@ -26,16 +26,32 @@ export interface PasskeyGetOptions {
|
|
|
26
26
|
* `"preferred"` is enough.
|
|
27
27
|
*/
|
|
28
28
|
userVerification?: PasskeyUserVerification;
|
|
29
|
+
/**
|
|
30
|
+
* Closes the open prompt when it aborts (a Cancel button, a page leaving).
|
|
31
|
+
* The browser provider then rejects as a dismissed prompt does
|
|
32
|
+
* (`NotAllowedError`), so the caller treats it as a cancel.
|
|
33
|
+
*/
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
}
|
|
36
|
+
/** What a passkey creation takes beyond the node's options. */
|
|
37
|
+
export interface PasskeyCreateOptions {
|
|
38
|
+
/** As {@link PasskeyGetOptions.signal}: aborting closes the prompt, rejecting as a cancel (`NotAllowedError`). */
|
|
39
|
+
signal?: AbortSignal;
|
|
29
40
|
}
|
|
30
41
|
/** Something that holds a passkey. */
|
|
31
42
|
export interface PasskeyProvider {
|
|
32
|
-
/**
|
|
33
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Answer `navigator.credentials.create` for the node's options.
|
|
45
|
+
* `createOptions.signal` closes the prompt when it aborts; a provider with
|
|
46
|
+
* no prompt to close may ignore it.
|
|
47
|
+
*/
|
|
48
|
+
create(options: Record<string, unknown>, createOptions?: PasskeyCreateOptions): Promise<RegistrationJSON>;
|
|
34
49
|
/**
|
|
35
50
|
* Sign `challenge` (an assertion), optionally limited to
|
|
36
51
|
* `allowCredentials`. `options.userVerification` is `"required"` when the
|
|
37
52
|
* client answers a step-up confirmation (`"preferred"` for the sign-up's);
|
|
38
53
|
* a provider that always verifies the user may ignore it.
|
|
54
|
+
* `options.signal` closes the prompt when it aborts.
|
|
39
55
|
*/
|
|
40
56
|
get(challenge: Uint8Array, rpId: string, allowCredentials?: string[], options?: PasskeyGetOptions): Promise<AssertionJSON>;
|
|
41
57
|
}
|
package/dist/cloud-v2/passkey.js
CHANGED
|
@@ -25,11 +25,22 @@ function cancelled(message) {
|
|
|
25
25
|
error.name = "NotAllowedError";
|
|
26
26
|
return error;
|
|
27
27
|
}
|
|
28
|
-
async function ask(method, options) {
|
|
28
|
+
async function ask(method, options, signal, what) {
|
|
29
29
|
const container = navigator.credentials;
|
|
30
30
|
const own = globalThis.CredentialsContainer?.prototype?.[method];
|
|
31
31
|
const call = own ?? container[method];
|
|
32
|
-
|
|
32
|
+
try {
|
|
33
|
+
return await call.call(container, signal ? { ...options, signal } : options);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
// An aborted `signal` rejects with its reason (an `AbortError` unless the
|
|
37
|
+
// caller gave another): the prompt was closed on purpose, so it reads as
|
|
38
|
+
// a dismissed one.
|
|
39
|
+
if (signal?.aborted || error?.name === "AbortError") {
|
|
40
|
+
throw Object.assign(cancelled(`${what} was cancelled`), { cause: error });
|
|
41
|
+
}
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
33
44
|
}
|
|
34
45
|
/**
|
|
35
46
|
* The node's algorithms with ES256 alone when it is among them. Some password
|
|
@@ -48,7 +59,7 @@ export function es256First(params) {
|
|
|
48
59
|
/** The platform authenticator (Touch ID, Face ID, Windows Hello, a security key, a synced passkey). */
|
|
49
60
|
export function browserPasskey() {
|
|
50
61
|
return {
|
|
51
|
-
async create(options) {
|
|
62
|
+
async create(options, createOptions) {
|
|
52
63
|
const o = options;
|
|
53
64
|
const cred = (await ask("create", {
|
|
54
65
|
publicKey: {
|
|
@@ -64,7 +75,7 @@ export function browserPasskey() {
|
|
|
64
75
|
attestation: "none",
|
|
65
76
|
timeout: o.timeout,
|
|
66
77
|
},
|
|
67
|
-
}));
|
|
78
|
+
}, createOptions?.signal, "passkey creation"));
|
|
68
79
|
if (!cred)
|
|
69
80
|
throw cancelled("passkey creation was cancelled");
|
|
70
81
|
const r = cred.response;
|
|
@@ -84,7 +95,7 @@ export function browserPasskey() {
|
|
|
84
95
|
id: buf(fromB64url(id)),
|
|
85
96
|
})),
|
|
86
97
|
},
|
|
87
|
-
}));
|
|
98
|
+
}, options?.signal, "passkey sign-in"));
|
|
88
99
|
if (!cred)
|
|
89
100
|
throw cancelled("passkey sign-in was cancelled");
|
|
90
101
|
const r = cred.response;
|