@ccmsg/protocol 1.6.0 → 1.7.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/package.json +1 -1
- package/src/common/auth.ts +54 -3
package/package.json
CHANGED
package/src/common/auth.ts
CHANGED
|
@@ -212,9 +212,28 @@ export const AuthAssertResponse = response("auth_assert", AuthAssertResult);
|
|
|
212
212
|
|
|
213
213
|
// --- refreshing a token pair ----------------------------------------------
|
|
214
214
|
|
|
215
|
-
/**
|
|
216
|
-
*
|
|
217
|
-
|
|
215
|
+
/** Why a client asked for a fresh pair. Stated by the caller and never checked,
|
|
216
|
+
* so nothing may be decided by it; it is kept only to be recognised later by
|
|
217
|
+
* the person whose sessions they are. */
|
|
218
|
+
export const AuthRefreshReason = Type.Union(
|
|
219
|
+
[Type.Literal("reload"), Type.Literal("expiring"), Type.Literal("reconnect")],
|
|
220
|
+
{ $id: "AuthRefreshReason" },
|
|
221
|
+
);
|
|
222
|
+
export type AuthRefreshReason = Static<typeof AuthRefreshReason>;
|
|
223
|
+
|
|
224
|
+
/** The refresh token is not among the arguments: it is a cookie the carrier
|
|
225
|
+
* already holds, and a caller that could state it is a caller that could read
|
|
226
|
+
* it. What is left is why the caller is asking, which nothing is decided by. */
|
|
227
|
+
export const AuthRefreshTokenArgs = Type.Object({
|
|
228
|
+
/** What prompted this refresh, as the client knows it: the page was loaded
|
|
229
|
+
* again, the access token was about to expire, or a dropped connection is
|
|
230
|
+
* being remade. A hint kept on the family (`last_refresh`) for a person
|
|
231
|
+
* reading their own sessions back — a run of `reconnect` at an hour they were
|
|
232
|
+
* asleep is something to recognise. The value is the caller's word and is
|
|
233
|
+
* never checked, so nothing may turn on it; an unstated reason is as valid a
|
|
234
|
+
* refresh as any. */
|
|
235
|
+
reason: Type.Optional(AuthRefreshReason),
|
|
236
|
+
});
|
|
218
237
|
export type AuthRefreshTokenArgs = Static<typeof AuthRefreshTokenArgs>;
|
|
219
238
|
|
|
220
239
|
export const AuthRefreshTokenResult = AuthSession;
|
|
@@ -345,6 +364,22 @@ export const CredentialRecord = Type.Object(
|
|
|
345
364
|
* zero forever, so only a pair of non-zero readings says anything, and a
|
|
346
365
|
* reading below the last one is a refusal. */
|
|
347
366
|
sign_count: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
367
|
+
/** The BE flag of the authenticator data at registration: whether this
|
|
368
|
+
* credential is one the authenticator may back up, which in practice is
|
|
369
|
+
* what separates a passkey synced across a person's devices from one that
|
|
370
|
+
* lives on the single device it was made on.
|
|
371
|
+
*
|
|
372
|
+
* A hint and nothing else, like the address and the user agent beside it:
|
|
373
|
+
* nothing is admitted or refused by it. It is here so the person reading
|
|
374
|
+
* their own list can tell "this is my iCloud passkey, it is on every device
|
|
375
|
+
* I own" from "this is the key on the stick in my drawer" — which decides
|
|
376
|
+
* what removing the line actually costs them. */
|
|
377
|
+
backup_eligible: Type.Optional(Type.Boolean()),
|
|
378
|
+
/** The BS flag of the same authenticator data: whether the credential was
|
|
379
|
+
* backed up at that moment. Read beside `backup_eligible` — eligible and
|
|
380
|
+
* not yet backed up is an ordinary state on a device that has just made the
|
|
381
|
+
* key, and it too decides nothing. */
|
|
382
|
+
backup_state: Type.Optional(Type.Boolean()),
|
|
348
383
|
/** The label the administrator put on the registration URL, carried over
|
|
349
384
|
* from the claims it was spent against. */
|
|
350
385
|
issued_label: Type.Optional(Type.String({ maxLength: 128 })),
|
|
@@ -385,6 +420,22 @@ export const TokenFamily = Type.Object(
|
|
|
385
420
|
iss: InstanceId,
|
|
386
421
|
access: Type.Object({ value: Base64Url, expires_at: Timestamp }),
|
|
387
422
|
refresh: Type.Object({ value: Base64Url, expires_at: Timestamp }),
|
|
423
|
+
/** When the family was last rotated, and what the client said prompted it.
|
|
424
|
+
*
|
|
425
|
+
* The same kind of thing as a credential's `last_used_*`: a hint for the
|
|
426
|
+
* one person reading their own sessions, never a reason to admit or refuse
|
|
427
|
+
* anything. `reason` in particular is the caller's unchecked word. Only the
|
|
428
|
+
* most recent rotation is kept — a family holds what stands now, and a log
|
|
429
|
+
* of every generation would be a second store hidden inside a record that
|
|
430
|
+
* travels to every instance. */
|
|
431
|
+
last_refresh: Type.Optional(
|
|
432
|
+
Type.Object({
|
|
433
|
+
at: Timestamp,
|
|
434
|
+
reason: Type.Optional(AuthRefreshReason),
|
|
435
|
+
ip: Type.Optional(Type.String({ minLength: 1, maxLength: 45 })),
|
|
436
|
+
user_agent: Type.Optional(Type.String({ maxLength: 512 })),
|
|
437
|
+
}),
|
|
438
|
+
),
|
|
388
439
|
/** The generation before the current one, while the grace for it lasts. */
|
|
389
440
|
previous_refresh: Type.Optional(Type.Object({ value: Base64Url, expires_at: Timestamp })),
|
|
390
441
|
/** What every generation retired before that was, kept only as a digest and
|