@passlock/client 2.0.6 → 2.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/dist/index.d.ts +101 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +106 -17
- package/dist/index.js.map +1 -1
- package/dist/internal/network.d.ts +14 -1
- package/dist/internal/network.d.ts.map +1 -1
- package/dist/internal/network.js +11 -1
- package/dist/internal/network.js.map +1 -1
- package/dist/internal/promise.d.ts +7 -3
- package/dist/internal/promise.d.ts.map +1 -1
- package/dist/internal/promise.js +9 -5
- package/dist/internal/promise.js.map +1 -1
- package/dist/internal/result.d.ts +33 -0
- package/dist/internal/result.d.ts.map +1 -0
- package/dist/internal/result.js +35 -0
- package/dist/internal/result.js.map +1 -0
- package/dist/options.d.ts +5 -5
- package/dist/options.d.ts.map +1 -1
- package/dist/passkey/authentication/authentication.d.ts +13 -6
- package/dist/passkey/authentication/authentication.d.ts.map +1 -1
- package/dist/passkey/authentication/authentication.js +4 -1
- package/dist/passkey/authentication/authentication.js.map +1 -1
- package/dist/passkey/errors.d.ts +19 -13
- package/dist/passkey/errors.d.ts.map +1 -1
- package/dist/passkey/errors.js +16 -16
- package/dist/passkey/errors.js.map +1 -1
- package/dist/passkey/registration/registration.d.ts +9 -6
- package/dist/passkey/registration/registration.d.ts.map +1 -1
- package/dist/passkey/registration/registration.js +3 -3
- package/dist/passkey/registration/registration.js.map +1 -1
- package/dist/passkey/signals/signals.d.ts +188 -27
- package/dist/passkey/signals/signals.d.ts.map +1 -1
- package/dist/passkey/signals/signals.js +122 -24
- package/dist/passkey/signals/signals.js.map +1 -1
- package/dist/principal.d.ts +1 -1
- package/dist/safe.d.ts +165 -59
- package/dist/safe.d.ts.map +1 -1
- package/dist/safe.js +163 -54
- package/dist/safe.js.map +1 -1
- package/package.json +7 -7
|
@@ -3,42 +3,105 @@ import { Logger } from "../../logger.js";
|
|
|
3
3
|
import type { PasslockOptions } from "../../options.js";
|
|
4
4
|
import { DeleteError, type OrphanedPasskeyError, PruningError, UpdateError } from "../errors.js";
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Detect support for browser-driven local passkey removal via
|
|
7
|
+
* `PublicKeyCredential.signalUnknownCredential`.
|
|
7
8
|
*/
|
|
8
9
|
export declare const isPasskeyDeleteSupport: Micro.Micro<boolean, never, never>;
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
+
* Detect support for browser-driven passkey pruning via
|
|
12
|
+
* `PublicKeyCredential.signalAllAcceptedCredentials`.
|
|
11
13
|
*/
|
|
12
14
|
export declare const isPasskeyPruningSupport: Micro.Micro<boolean, never, never>;
|
|
13
15
|
/**
|
|
14
|
-
*
|
|
16
|
+
* Detect support for browser-driven passkey user-detail updates via
|
|
17
|
+
* `PublicKeyCredential.signalCurrentUserDetails`.
|
|
15
18
|
*/
|
|
16
19
|
export declare const isPasskeyUpdateSupport: Micro.Micro<boolean, never, never>;
|
|
20
|
+
/**
|
|
21
|
+
* Delete a local passkey by Passlock passkey ID.
|
|
22
|
+
*
|
|
23
|
+
* The library uses the tenancy information to look up the credential metadata
|
|
24
|
+
* before signalling the browser.
|
|
25
|
+
*
|
|
26
|
+
* @see {@link deletePasskey}
|
|
27
|
+
* @category Passkeys (core)
|
|
28
|
+
*/
|
|
17
29
|
export interface DeletePasskeyOptions extends PasslockOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Passlock passkey ID (authenticator ID).
|
|
32
|
+
*/
|
|
18
33
|
passkeyId: string;
|
|
19
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Delete a local passkey using credential metadata you already have.
|
|
37
|
+
*
|
|
38
|
+
* This shape is typically produced by `@passlock/server`'s
|
|
39
|
+
* `deleteUserPasskeys` helper, so the browser can be signalled without an
|
|
40
|
+
* extra Passlock lookup.
|
|
41
|
+
*
|
|
42
|
+
* @see {@link deletePasskey}
|
|
43
|
+
* @see {@link deleteUserPasskeys}
|
|
44
|
+
* @category Passkeys (core)
|
|
45
|
+
*/
|
|
20
46
|
export interface DeleteCredentialOptions extends PasslockOptions {
|
|
47
|
+
/**
|
|
48
|
+
* WebAuthn credential ID.
|
|
49
|
+
*/
|
|
21
50
|
credentialId: string;
|
|
51
|
+
/**
|
|
52
|
+
* Credential user ID.
|
|
53
|
+
*/
|
|
22
54
|
userId: string;
|
|
55
|
+
/**
|
|
56
|
+
* Relying party ID.
|
|
57
|
+
*/
|
|
23
58
|
rpId: string;
|
|
24
59
|
}
|
|
25
60
|
/**
|
|
26
|
-
* Instruct the
|
|
27
|
-
*
|
|
61
|
+
* Instruct the browser to remove a local passkey, for example from a password
|
|
62
|
+
* manager.
|
|
63
|
+
*
|
|
64
|
+
* If you pass a Passlock `passkeyId`, the library first fetches the associated
|
|
65
|
+
* credential metadata from Passlock. If you pass a credential payload or
|
|
66
|
+
* {@link OrphanedPasskeyError}, it can signal the browser directly.
|
|
28
67
|
*
|
|
29
68
|
* @param options Passkey identifier/credential details and Passlock tenancy options.
|
|
30
|
-
* @returns A Micro effect that resolves with a {@link DeleteSuccess}
|
|
69
|
+
* @returns A Micro effect that resolves with a {@link DeleteSuccess} once the
|
|
70
|
+
* removal signal has been queued, or fails with {@link DeleteError}.
|
|
31
71
|
*/
|
|
32
72
|
export declare const deletePasskey: (options: DeletePasskeyOptions | DeleteCredentialOptions | OrphanedPasskeyError) => Micro.Micro<DeleteSuccess, DeleteError, Logger>;
|
|
73
|
+
/**
|
|
74
|
+
* Keep only the listed Passlock passkeys for a user on the current device.
|
|
75
|
+
*
|
|
76
|
+
* The library resolves those passkey IDs to the accepted WebAuthn credential
|
|
77
|
+
* list before signalling the browser.
|
|
78
|
+
*
|
|
79
|
+
* @see {@link prunePasskeys}
|
|
80
|
+
* @category Passkeys (core)
|
|
81
|
+
*/
|
|
33
82
|
export interface PrunePasskeyOptions extends PasslockOptions {
|
|
83
|
+
/**
|
|
84
|
+
* Passlock passkey IDs that should remain available on this device.
|
|
85
|
+
*/
|
|
34
86
|
allowablePasskeyIds: Array<string>;
|
|
35
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Indicates the library finished the accepted-credentials signalling flow.
|
|
90
|
+
*
|
|
91
|
+
* @category Passkeys (core)
|
|
92
|
+
*/
|
|
36
93
|
export type PruningSuccess = {
|
|
37
94
|
_tag: "PruningSuccess";
|
|
38
95
|
};
|
|
96
|
+
/**
|
|
97
|
+
* Type guard for {@link PruningSuccess}.
|
|
98
|
+
*
|
|
99
|
+
* @category Passkeys (other)
|
|
100
|
+
*/
|
|
39
101
|
export declare const isPruningSuccess: (payload: unknown) => payload is PruningSuccess;
|
|
40
102
|
/**
|
|
41
|
-
* Given a list of passkey IDs, instruct the device to remove any
|
|
103
|
+
* Given a list of passkey IDs to keep, instruct the device to remove any
|
|
104
|
+
* redundant passkeys for the same account on the same relying party.
|
|
42
105
|
*
|
|
43
106
|
* Note: this will only remove redundant passkeys (based on the userId).
|
|
44
107
|
*
|
|
@@ -53,7 +116,9 @@ export declare const isPruningSuccess: (payload: unknown) => payload is PruningS
|
|
|
53
116
|
* different account, the device will retain it.
|
|
54
117
|
*
|
|
55
118
|
* @param options Passlock tenancy/endpoint options and the passkey IDs to keep.
|
|
56
|
-
* @returns A Micro effect that resolves with a {@link PruningSuccess}
|
|
119
|
+
* @returns A Micro effect that resolves with a {@link PruningSuccess} once the
|
|
120
|
+
* accepted-credentials signal has been sent, or fails with
|
|
121
|
+
* {@link PruningError}.
|
|
57
122
|
*/
|
|
58
123
|
export declare const prunePasskeys: (options: PrunePasskeyOptions) => Micro.Micro<PruningSuccess, PruningError, Logger>;
|
|
59
124
|
/**
|
|
@@ -65,43 +130,99 @@ export declare const prunePasskeys: (options: PrunePasskeyOptions) => Micro.Micr
|
|
|
65
130
|
*/
|
|
66
131
|
export interface UpdatePasskeyOptions extends PasslockOptions {
|
|
67
132
|
/**
|
|
68
|
-
* The Passlock passkey
|
|
133
|
+
* The Passlock passkey ID (authenticator ID).
|
|
69
134
|
*/
|
|
70
135
|
passkeyId: string;
|
|
71
136
|
/**
|
|
72
|
-
* New username
|
|
137
|
+
* New username shown alongside the passkey.
|
|
73
138
|
*/
|
|
74
139
|
username: string;
|
|
75
140
|
/**
|
|
76
|
-
* New display name
|
|
141
|
+
* New display name shown alongside the passkey.
|
|
77
142
|
*/
|
|
78
143
|
displayName?: string | undefined;
|
|
79
144
|
}
|
|
80
145
|
/**
|
|
81
|
-
* Used when you want to update one or more passkeys by the
|
|
82
|
-
* immutable Base64Url
|
|
146
|
+
* Used when you want to update one or more passkeys by the credential user ID,
|
|
147
|
+
* that is the immutable Base64Url-encoded binary ID.
|
|
148
|
+
*
|
|
149
|
+
* This shape is usually returned by `@passlock/server`'s
|
|
150
|
+
* `updatePasskeyUsernames` helper and does not include tenancy or endpoint
|
|
151
|
+
* configuration.
|
|
83
152
|
*
|
|
84
153
|
* @see {@link updatePasskey}
|
|
85
154
|
* @see {@link https://passlock.dev/rest-api/credential/ The Credential property (main docs site)}
|
|
86
155
|
*
|
|
87
156
|
* @category Passkeys (core)
|
|
88
157
|
*/
|
|
89
|
-
export interface UpdateCredentialOptions
|
|
158
|
+
export interface UpdateCredentialOptions {
|
|
159
|
+
/**
|
|
160
|
+
* Credential user ID.
|
|
161
|
+
*/
|
|
90
162
|
userId: string;
|
|
163
|
+
/**
|
|
164
|
+
* Relying party identifier for the passkey.
|
|
165
|
+
*/
|
|
91
166
|
rpId: string;
|
|
92
167
|
/**
|
|
93
|
-
* New username
|
|
168
|
+
* New username shown alongside the passkey.
|
|
94
169
|
*/
|
|
95
170
|
username: string;
|
|
96
171
|
/**
|
|
97
|
-
* New display name
|
|
172
|
+
* New display name shown alongside the passkey.
|
|
98
173
|
*/
|
|
99
174
|
displayName?: string | undefined;
|
|
100
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Indicates the library finished the local passkey update signalling flow.
|
|
178
|
+
*
|
|
179
|
+
* @category Passkeys (core)
|
|
180
|
+
*/
|
|
101
181
|
export type UpdateSuccess = {
|
|
102
182
|
_tag: "UpdateSuccess";
|
|
103
183
|
};
|
|
184
|
+
/**
|
|
185
|
+
* Type guard for {@link UpdateSuccess}.
|
|
186
|
+
*
|
|
187
|
+
* @category Passkeys (other)
|
|
188
|
+
*/
|
|
104
189
|
export declare const isUpdateSuccess: (payload: unknown) => payload is UpdateSuccess;
|
|
190
|
+
/**
|
|
191
|
+
* Update the username and/or display name for multiple local passkeys.
|
|
192
|
+
*
|
|
193
|
+
* Note: this is purely informational. It does not change any passkey
|
|
194
|
+
* identifiers.
|
|
195
|
+
*
|
|
196
|
+
* The typical use case is when a user changes their account email. You would
|
|
197
|
+
* update the username in your backend system, then pass the returned
|
|
198
|
+
* credential list into this function so the same account label is shown in the
|
|
199
|
+
* user's password manager.
|
|
200
|
+
*
|
|
201
|
+
* @param options Credential identifiers plus the updated username/display name,
|
|
202
|
+
* typically taken from `@passlock/server`'s `updatePasskeyUsernames`
|
|
203
|
+
* response.
|
|
204
|
+
* @returns A Micro effect that resolves with a {@link UpdateSuccess} once the
|
|
205
|
+
* browser has been asked to refresh those details, or fails with
|
|
206
|
+
* {@link UpdateError}.
|
|
207
|
+
*/
|
|
208
|
+
export declare const updatePasskeyUsernames: (options: ReadonlyArray<UpdateCredentialOptions>) => Micro.Micro<{
|
|
209
|
+
readonly _tag: "UpdateSuccess";
|
|
210
|
+
}, UpdateError, Logger>;
|
|
211
|
+
/**
|
|
212
|
+
* Delete multiple local passkeys using credentials previously returned from
|
|
213
|
+
* your backend.
|
|
214
|
+
*
|
|
215
|
+
* The typical flow is to delete the server-side passkeys first, then pass the
|
|
216
|
+
* returned `deleted` array into this function so the user’s password manager is
|
|
217
|
+
* updated too.
|
|
218
|
+
*
|
|
219
|
+
* @param options Credentials derived from deleted server-side passkeys.
|
|
220
|
+
* @returns A Micro effect that resolves with a {@link DeleteSuccess} once the
|
|
221
|
+
* removal signals have been queued, or fails with {@link DeleteError}.
|
|
222
|
+
*/
|
|
223
|
+
export declare const deleteUserPasskeys: (options: ReadonlyArray<Credential>) => Micro.Micro<{
|
|
224
|
+
readonly _tag: "DeleteSuccess";
|
|
225
|
+
}, DeleteError, Logger>;
|
|
105
226
|
/**
|
|
106
227
|
* Update a passkey e.g. change the username and/or display name.
|
|
107
228
|
* Note: this is purely informational, it does not change any identifiers.
|
|
@@ -111,17 +232,36 @@ export declare const isUpdateSuccess: (payload: unknown) => payload is UpdateSuc
|
|
|
111
232
|
* account would still show up in their password manager as old-name@gmail.com.
|
|
112
233
|
*
|
|
113
234
|
* @param options Passkey update options.
|
|
114
|
-
* @returns A Micro effect that resolves with a {@link UpdateSuccess}
|
|
235
|
+
* @returns A Micro effect that resolves with a {@link UpdateSuccess} once the
|
|
236
|
+
* browser has been asked to refresh the local details, or fails with
|
|
237
|
+
* {@link UpdateError}.
|
|
115
238
|
*/
|
|
116
239
|
export declare const updatePasskey: (options: UpdatePasskeyOptions | UpdateCredentialOptions) => Micro.Micro<{
|
|
117
240
|
readonly _tag: "UpdateSuccess";
|
|
118
241
|
}, UpdateError, Logger>;
|
|
119
|
-
|
|
242
|
+
/**
|
|
243
|
+
* Credential metadata required to target a local passkey on the device.
|
|
244
|
+
*
|
|
245
|
+
* @category Passkeys (core)
|
|
246
|
+
*/
|
|
247
|
+
export type Credential = {
|
|
248
|
+
/**
|
|
249
|
+
* WebAuthn credential ID.
|
|
250
|
+
*/
|
|
120
251
|
credentialId: string;
|
|
252
|
+
/**
|
|
253
|
+
* Credential user ID.
|
|
254
|
+
*/
|
|
121
255
|
userId: string;
|
|
256
|
+
/**
|
|
257
|
+
* Relying party ID.
|
|
258
|
+
*/
|
|
122
259
|
rpId: string;
|
|
123
260
|
};
|
|
124
|
-
|
|
261
|
+
/**
|
|
262
|
+
* Accepted credential list for a single user on a relying party.
|
|
263
|
+
*/
|
|
264
|
+
export type UserCredentials = {
|
|
125
265
|
rpId: string;
|
|
126
266
|
userId: string;
|
|
127
267
|
allAcceptedCredentialIds: string[];
|
|
@@ -134,25 +274,46 @@ type IPasskeyNotFound = {
|
|
|
134
274
|
export type DeleteSuccess = {
|
|
135
275
|
_tag: "DeleteSuccess";
|
|
136
276
|
};
|
|
277
|
+
/**
|
|
278
|
+
* Type guard for {@link DeleteSuccess}.
|
|
279
|
+
*
|
|
280
|
+
* @category Passkeys (other)
|
|
281
|
+
*/
|
|
137
282
|
export declare const isDeleteSuccess: (payload: unknown) => payload is DeleteSuccess;
|
|
138
283
|
/**
|
|
139
|
-
*
|
|
284
|
+
* Queue a browser removal signal for a credential.
|
|
140
285
|
*
|
|
141
|
-
* @param credential Credential
|
|
142
|
-
* @returns A Micro effect that resolves with a {@link DeleteSuccess}
|
|
286
|
+
* @param credential Credential or missing-passkey payload.
|
|
287
|
+
* @returns A Micro effect that resolves with a {@link DeleteSuccess} once the
|
|
288
|
+
* removal signal has been queued, or fails with {@link DeleteError}.
|
|
143
289
|
*/
|
|
144
|
-
export declare const signalCredentialRemoval: (credential:
|
|
290
|
+
export declare const signalCredentialRemoval: (credential: Credential | IPasskeyNotFound) => Micro.Micro<DeleteSuccess, DeleteError, Logger>;
|
|
145
291
|
/**
|
|
146
|
-
* Tell the
|
|
292
|
+
* Tell the browser which credentials are still accepted for a user.
|
|
147
293
|
*
|
|
148
|
-
* @param credentials Accepted
|
|
149
|
-
* @returns A Micro effect that resolves with a {@link PruningSuccess}
|
|
294
|
+
* @param credentials Accepted credentials for the user.
|
|
295
|
+
* @returns A Micro effect that resolves with a {@link PruningSuccess} once the
|
|
296
|
+
* accepted-credentials signal has been sent, or fails with
|
|
297
|
+
* {@link PruningError}.
|
|
298
|
+
*/
|
|
299
|
+
export declare const signalAcceptedCredentials: (credentials: UserCredentials) => Micro.Micro<PruningSuccess, PruningError, Logger>;
|
|
300
|
+
/**
|
|
301
|
+
* Credential identity needed to update the user-visible details for a local
|
|
302
|
+
* passkey.
|
|
150
303
|
*/
|
|
151
|
-
export declare const signalAcceptedCredentials: (credentials: CredentialMappings) => Micro.Micro<PruningSuccess, PruningError, Logger>;
|
|
152
304
|
export type CredentialUserId = {
|
|
153
305
|
userId: string;
|
|
154
306
|
rpId: string;
|
|
155
307
|
};
|
|
308
|
+
/**
|
|
309
|
+
* Tell the browser to refresh the username and display name shown for a local
|
|
310
|
+
* passkey.
|
|
311
|
+
*
|
|
312
|
+
* @param credential Credential identity used to find the passkey.
|
|
313
|
+
* @param updates Updated username/display-name values.
|
|
314
|
+
* @returns A Micro effect that resolves with an {@link UpdateSuccess} once the
|
|
315
|
+
* signal has been sent, or fails with {@link UpdateError}.
|
|
316
|
+
*/
|
|
156
317
|
export declare const signalCurrentUserDetails: (credential: CredentialUserId, updates: Pick<UpdatePasskeyOptions, "username" | "displayName">) => Micro.Micro<{
|
|
157
318
|
readonly _tag: "UpdateSuccess";
|
|
158
319
|
}, UpdateError, Logger>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../../src/passkey/signals/signals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAQ,MAAM,QAAQ,CAAA;AAGpC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EACL,WAAW,EACX,KAAK,oBAAoB,EACzB,YAAY,EACZ,WAAW,EACZ,MAAM,cAAc,CAAA;AAErB
|
|
1
|
+
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../../src/passkey/signals/signals.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,32 +4,40 @@ import { makeEndpoint } from "../../internal/index.js";
|
|
|
4
4
|
import { Logger } from "../../logger.js";
|
|
5
5
|
import { DeleteError, PruningError, UpdateError, } from "../errors.js";
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Detect support for browser-driven local passkey removal via
|
|
8
|
+
* `PublicKeyCredential.signalUnknownCredential`.
|
|
8
9
|
*/
|
|
9
10
|
export const isPasskeyDeleteSupport = Micro.sync(() => {
|
|
10
11
|
return (PublicKeyCredential?.signalUnknownCredential &&
|
|
11
12
|
typeof PublicKeyCredential.signalUnknownCredential === "function");
|
|
12
13
|
});
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
+
* Detect support for browser-driven passkey pruning via
|
|
16
|
+
* `PublicKeyCredential.signalAllAcceptedCredentials`.
|
|
15
17
|
*/
|
|
16
18
|
export const isPasskeyPruningSupport = Micro.sync(() => {
|
|
17
19
|
return (PublicKeyCredential?.signalAllAcceptedCredentials &&
|
|
18
20
|
typeof PublicKeyCredential.signalAllAcceptedCredentials === "function");
|
|
19
21
|
});
|
|
20
22
|
/**
|
|
21
|
-
*
|
|
23
|
+
* Detect support for browser-driven passkey user-detail updates via
|
|
24
|
+
* `PublicKeyCredential.signalCurrentUserDetails`.
|
|
22
25
|
*/
|
|
23
26
|
export const isPasskeyUpdateSupport = Micro.sync(() => {
|
|
24
27
|
return (PublicKeyCredential?.signalCurrentUserDetails &&
|
|
25
28
|
typeof PublicKeyCredential.signalCurrentUserDetails === "function");
|
|
26
29
|
});
|
|
27
30
|
/**
|
|
28
|
-
* Instruct the
|
|
29
|
-
*
|
|
31
|
+
* Instruct the browser to remove a local passkey, for example from a password
|
|
32
|
+
* manager.
|
|
33
|
+
*
|
|
34
|
+
* If you pass a Passlock `passkeyId`, the library first fetches the associated
|
|
35
|
+
* credential metadata from Passlock. If you pass a credential payload or
|
|
36
|
+
* {@link OrphanedPasskeyError}, it can signal the browser directly.
|
|
30
37
|
*
|
|
31
38
|
* @param options Passkey identifier/credential details and Passlock tenancy options.
|
|
32
|
-
* @returns A Micro effect that resolves with a {@link DeleteSuccess}
|
|
39
|
+
* @returns A Micro effect that resolves with a {@link DeleteSuccess} once the
|
|
40
|
+
* removal signal has been queued, or fails with {@link DeleteError}.
|
|
33
41
|
*/
|
|
34
42
|
export const deletePasskey = (options) => Micro.gen(function* () {
|
|
35
43
|
const logger = yield* Micro.service(Logger);
|
|
@@ -40,10 +48,10 @@ export const deletePasskey = (options) => Micro.gen(function* () {
|
|
|
40
48
|
code: "PASSKEY_DELETION_UNSUPPORTED",
|
|
41
49
|
message: "Passkey deletion not supported on this device",
|
|
42
50
|
}));
|
|
43
|
-
const credential = "rpId" in options ? options : yield*
|
|
51
|
+
const credential = "rpId" in options ? options : yield* getCredential(options);
|
|
44
52
|
return yield* signalCredentialRemoval(credential);
|
|
45
53
|
});
|
|
46
|
-
const
|
|
54
|
+
const getCredential = (options) => Micro.gen(function* () {
|
|
47
55
|
const { tenancyId } = options;
|
|
48
56
|
const logger = yield* Micro.service(Logger);
|
|
49
57
|
const { endpoint } = makeEndpoint(options);
|
|
@@ -56,13 +64,18 @@ const getCredentialMapping = (options) => Micro.gen(function* () {
|
|
|
56
64
|
message: "Unable to find the metadata associated with this passkey",
|
|
57
65
|
}));
|
|
58
66
|
const credential = yield* Micro.promise(() => response.json());
|
|
59
|
-
if (!
|
|
67
|
+
if (!isCredential(credential))
|
|
60
68
|
return yield* Micro.fail(new DeleteError({
|
|
61
69
|
code: "OTHER_ERROR",
|
|
62
70
|
message: "Invalid metadata associated with this passkey",
|
|
63
71
|
}));
|
|
64
72
|
return credential;
|
|
65
73
|
});
|
|
74
|
+
/**
|
|
75
|
+
* Type guard for {@link PruningSuccess}.
|
|
76
|
+
*
|
|
77
|
+
* @category Passkeys (other)
|
|
78
|
+
*/
|
|
66
79
|
export const isPruningSuccess = (payload) => {
|
|
67
80
|
if (typeof payload !== "object")
|
|
68
81
|
return false;
|
|
@@ -75,7 +88,8 @@ export const isPruningSuccess = (payload) => {
|
|
|
75
88
|
return payload._tag === "PruningSuccess";
|
|
76
89
|
};
|
|
77
90
|
/**
|
|
78
|
-
* Given a list of passkey IDs, instruct the device to remove any
|
|
91
|
+
* Given a list of passkey IDs to keep, instruct the device to remove any
|
|
92
|
+
* redundant passkeys for the same account on the same relying party.
|
|
79
93
|
*
|
|
80
94
|
* Note: this will only remove redundant passkeys (based on the userId).
|
|
81
95
|
*
|
|
@@ -90,7 +104,9 @@ export const isPruningSuccess = (payload) => {
|
|
|
90
104
|
* different account, the device will retain it.
|
|
91
105
|
*
|
|
92
106
|
* @param options Passlock tenancy/endpoint options and the passkey IDs to keep.
|
|
93
|
-
* @returns A Micro effect that resolves with a {@link PruningSuccess}
|
|
107
|
+
* @returns A Micro effect that resolves with a {@link PruningSuccess} once the
|
|
108
|
+
* accepted-credentials signal has been sent, or fails with
|
|
109
|
+
* {@link PruningError}.
|
|
94
110
|
*/
|
|
95
111
|
export const prunePasskeys = (options) => Micro.gen(function* () {
|
|
96
112
|
const { tenancyId } = options;
|
|
@@ -113,13 +129,18 @@ export const prunePasskeys = (options) => Micro.gen(function* () {
|
|
|
113
129
|
message: "Unable to find the metadata associated with these passkeys",
|
|
114
130
|
}));
|
|
115
131
|
const credentials = yield* Micro.promise(() => response.json());
|
|
116
|
-
if (!
|
|
132
|
+
if (!isUserCredentials(credentials))
|
|
117
133
|
return yield* Micro.fail(new PruningError({
|
|
118
134
|
code: "OTHER_ERROR",
|
|
119
135
|
message: "Invalid metadata associated with one or more passkeys",
|
|
120
136
|
}));
|
|
121
137
|
return yield* signalAcceptedCredentials(credentials);
|
|
122
138
|
});
|
|
139
|
+
/**
|
|
140
|
+
* Type guard for {@link UpdateSuccess}.
|
|
141
|
+
*
|
|
142
|
+
* @category Passkeys (other)
|
|
143
|
+
*/
|
|
123
144
|
export const isUpdateSuccess = (payload) => {
|
|
124
145
|
if (typeof payload !== "object")
|
|
125
146
|
return false;
|
|
@@ -131,6 +152,64 @@ export const isUpdateSuccess = (payload) => {
|
|
|
131
152
|
return false;
|
|
132
153
|
return payload._tag === "UpdateSuccess";
|
|
133
154
|
};
|
|
155
|
+
/**
|
|
156
|
+
* Update the username and/or display name for multiple local passkeys.
|
|
157
|
+
*
|
|
158
|
+
* Note: this is purely informational. It does not change any passkey
|
|
159
|
+
* identifiers.
|
|
160
|
+
*
|
|
161
|
+
* The typical use case is when a user changes their account email. You would
|
|
162
|
+
* update the username in your backend system, then pass the returned
|
|
163
|
+
* credential list into this function so the same account label is shown in the
|
|
164
|
+
* user's password manager.
|
|
165
|
+
*
|
|
166
|
+
* @param options Credential identifiers plus the updated username/display name,
|
|
167
|
+
* typically taken from `@passlock/server`'s `updatePasskeyUsernames`
|
|
168
|
+
* response.
|
|
169
|
+
* @returns A Micro effect that resolves with a {@link UpdateSuccess} once the
|
|
170
|
+
* browser has been asked to refresh those details, or fails with
|
|
171
|
+
* {@link UpdateError}.
|
|
172
|
+
*/
|
|
173
|
+
export const updatePasskeyUsernames = (options) => Micro.gen(function* () {
|
|
174
|
+
const logger = yield* Micro.service(Logger);
|
|
175
|
+
yield* logger.logInfo("Testing for local passkey update support");
|
|
176
|
+
const canUpdate = yield* isPasskeyUpdateSupport;
|
|
177
|
+
if (!canUpdate)
|
|
178
|
+
return yield* Micro.fail(new UpdateError({
|
|
179
|
+
code: "PASSKEY_UPDATE_UNSUPPORTED",
|
|
180
|
+
message: "Passkey update not supported on this device",
|
|
181
|
+
}));
|
|
182
|
+
yield* Micro.forEach(options, (credential) => signalCurrentUserDetails(credential, credential));
|
|
183
|
+
return {
|
|
184
|
+
_tag: "UpdateSuccess",
|
|
185
|
+
};
|
|
186
|
+
});
|
|
187
|
+
/**
|
|
188
|
+
* Delete multiple local passkeys using credentials previously returned from
|
|
189
|
+
* your backend.
|
|
190
|
+
*
|
|
191
|
+
* The typical flow is to delete the server-side passkeys first, then pass the
|
|
192
|
+
* returned `deleted` array into this function so the user’s password manager is
|
|
193
|
+
* updated too.
|
|
194
|
+
*
|
|
195
|
+
* @param options Credentials derived from deleted server-side passkeys.
|
|
196
|
+
* @returns A Micro effect that resolves with a {@link DeleteSuccess} once the
|
|
197
|
+
* removal signals have been queued, or fails with {@link DeleteError}.
|
|
198
|
+
*/
|
|
199
|
+
export const deleteUserPasskeys = (options) => Micro.gen(function* () {
|
|
200
|
+
const logger = yield* Micro.service(Logger);
|
|
201
|
+
yield* logger.logInfo("Testing for local passkey removal support");
|
|
202
|
+
const canDelete = yield* isPasskeyDeleteSupport;
|
|
203
|
+
if (!canDelete)
|
|
204
|
+
return yield* Micro.fail(new DeleteError({
|
|
205
|
+
code: "PASSKEY_DELETION_UNSUPPORTED",
|
|
206
|
+
message: "Passkey deletion not supported on this device",
|
|
207
|
+
}));
|
|
208
|
+
yield* Micro.forEach(options, signalCredentialRemoval);
|
|
209
|
+
return {
|
|
210
|
+
_tag: "DeleteSuccess",
|
|
211
|
+
};
|
|
212
|
+
});
|
|
134
213
|
/**
|
|
135
214
|
* Update a passkey e.g. change the username and/or display name.
|
|
136
215
|
* Note: this is purely informational, it does not change any identifiers.
|
|
@@ -140,7 +219,9 @@ export const isUpdateSuccess = (payload) => {
|
|
|
140
219
|
* account would still show up in their password manager as old-name@gmail.com.
|
|
141
220
|
*
|
|
142
221
|
* @param options Passkey update options.
|
|
143
|
-
* @returns A Micro effect that resolves with a {@link UpdateSuccess}
|
|
222
|
+
* @returns A Micro effect that resolves with a {@link UpdateSuccess} once the
|
|
223
|
+
* browser has been asked to refresh the local details, or fails with
|
|
224
|
+
* {@link UpdateError}.
|
|
144
225
|
*/
|
|
145
226
|
export const updatePasskey = (options) => Micro.gen(function* () {
|
|
146
227
|
const logger = yield* Micro.service(Logger);
|
|
@@ -151,10 +232,10 @@ export const updatePasskey = (options) => Micro.gen(function* () {
|
|
|
151
232
|
code: "PASSKEY_UPDATE_UNSUPPORTED",
|
|
152
233
|
message: "Passkey update not supported on this device",
|
|
153
234
|
}));
|
|
154
|
-
const credential = "rpId" in options ? options : yield*
|
|
235
|
+
const credential = "rpId" in options ? options : yield* getUserCredential(options);
|
|
155
236
|
return yield* signalCurrentUserDetails(credential, options);
|
|
156
237
|
});
|
|
157
|
-
const
|
|
238
|
+
const getUserCredential = (options) => Micro.gen(function* () {
|
|
158
239
|
const { tenancyId } = options;
|
|
159
240
|
const logger = yield* Micro.service(Logger);
|
|
160
241
|
const { endpoint } = makeEndpoint(options);
|
|
@@ -167,14 +248,14 @@ const getUserCredentialMapping = (options) => Micro.gen(function* () {
|
|
|
167
248
|
message: "Unable to find the metadata associated with this passkey",
|
|
168
249
|
}));
|
|
169
250
|
const credential = yield* Micro.promise(() => response.json());
|
|
170
|
-
if (!
|
|
251
|
+
if (!isCredential(credential))
|
|
171
252
|
return yield* Micro.fail(new UpdateError({
|
|
172
253
|
code: "OTHER_ERROR",
|
|
173
254
|
message: "Invalid metadata associated with this passkey",
|
|
174
255
|
}));
|
|
175
256
|
return credential;
|
|
176
257
|
});
|
|
177
|
-
const
|
|
258
|
+
const isCredential = (payload) => {
|
|
178
259
|
if (typeof payload !== "object")
|
|
179
260
|
return false;
|
|
180
261
|
if (payload === null)
|
|
@@ -193,7 +274,7 @@ const isCredentialMapping = (payload) => {
|
|
|
193
274
|
return false;
|
|
194
275
|
return true;
|
|
195
276
|
};
|
|
196
|
-
const
|
|
277
|
+
const isUserCredentials = (payload) => {
|
|
197
278
|
if (typeof payload !== "object")
|
|
198
279
|
return false;
|
|
199
280
|
if (payload === null)
|
|
@@ -212,6 +293,11 @@ const isCredentialMappings = (payload) => {
|
|
|
212
293
|
return false;
|
|
213
294
|
return true;
|
|
214
295
|
};
|
|
296
|
+
/**
|
|
297
|
+
* Type guard for {@link DeleteSuccess}.
|
|
298
|
+
*
|
|
299
|
+
* @category Passkeys (other)
|
|
300
|
+
*/
|
|
215
301
|
export const isDeleteSuccess = (payload) => {
|
|
216
302
|
if (typeof payload !== "object")
|
|
217
303
|
return false;
|
|
@@ -224,10 +310,11 @@ export const isDeleteSuccess = (payload) => {
|
|
|
224
310
|
return payload._tag === "DeleteSuccess";
|
|
225
311
|
};
|
|
226
312
|
/**
|
|
227
|
-
*
|
|
313
|
+
* Queue a browser removal signal for a credential.
|
|
228
314
|
*
|
|
229
|
-
* @param credential Credential
|
|
230
|
-
* @returns A Micro effect that resolves with a {@link DeleteSuccess}
|
|
315
|
+
* @param credential Credential or missing-passkey payload.
|
|
316
|
+
* @returns A Micro effect that resolves with a {@link DeleteSuccess} once the
|
|
317
|
+
* removal signal has been queued, or fails with {@link DeleteError}.
|
|
231
318
|
*/
|
|
232
319
|
export const signalCredentialRemoval = (credential) => Micro.gen(function* () {
|
|
233
320
|
const logger = yield* Micro.service(Logger);
|
|
@@ -252,10 +339,12 @@ export const signalCredentialRemoval = (credential) => Micro.gen(function* () {
|
|
|
252
339
|
return { _tag: "DeleteSuccess" };
|
|
253
340
|
});
|
|
254
341
|
/**
|
|
255
|
-
* Tell the
|
|
342
|
+
* Tell the browser which credentials are still accepted for a user.
|
|
256
343
|
*
|
|
257
|
-
* @param credentials Accepted
|
|
258
|
-
* @returns A Micro effect that resolves with a {@link PruningSuccess}
|
|
344
|
+
* @param credentials Accepted credentials for the user.
|
|
345
|
+
* @returns A Micro effect that resolves with a {@link PruningSuccess} once the
|
|
346
|
+
* accepted-credentials signal has been sent, or fails with
|
|
347
|
+
* {@link PruningError}.
|
|
259
348
|
*/
|
|
260
349
|
export const signalAcceptedCredentials = (credentials) => Micro.gen(function* () {
|
|
261
350
|
const logger = yield* Micro.service(Logger);
|
|
@@ -278,6 +367,15 @@ export const signalAcceptedCredentials = (credentials) => Micro.gen(function* ()
|
|
|
278
367
|
yield* logger.logInfo("Accepted credentials signalled");
|
|
279
368
|
return { _tag: "PruningSuccess" };
|
|
280
369
|
});
|
|
370
|
+
/**
|
|
371
|
+
* Tell the browser to refresh the username and display name shown for a local
|
|
372
|
+
* passkey.
|
|
373
|
+
*
|
|
374
|
+
* @param credential Credential identity used to find the passkey.
|
|
375
|
+
* @param updates Updated username/display-name values.
|
|
376
|
+
* @returns A Micro effect that resolves with an {@link UpdateSuccess} once the
|
|
377
|
+
* signal has been sent, or fails with {@link UpdateError}.
|
|
378
|
+
*/
|
|
281
379
|
export const signalCurrentUserDetails = (credential, updates) => Micro.gen(function* () {
|
|
282
380
|
const logger = yield* Micro.service(Logger);
|
|
283
381
|
yield* logger.logInfo("Testing for local passkey update support");
|