@ccmsg/protocol 1.2.0 → 1.3.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/common/auth.ts +20 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ccmsg/protocol",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Wire contract (schema + types + op attribute table) shared by the ccmsg daemon and web UI",
5
5
  "license": "MIT",
6
6
  "author": "kawaz",
@@ -92,6 +92,13 @@ export const RegisterClaims = Type.Object(
92
92
  expires_at: Timestamp,
93
93
  /** Names this registration, so it can be spent once. */
94
94
  jti: Type.String({ minLength: 1 }),
95
+ /** The WebAuthn user handle for this subject: sixteen random bytes the
96
+ * issuing instance settles on once per `sub`. The page creates the
97
+ * credential against it, the record keeps it, and an assertion that names a
98
+ * handle is held to it. It is here rather than left to the page because the
99
+ * authenticator stores it beyond this instance's reach — a second value for
100
+ * one person would be a second account on their device. */
101
+ user_id: Base64Url,
95
102
  /** What the administrator who issued the URL wrote down about who it was
96
103
  * for. Their words, not the holder's — the label the person gives their
97
104
  * own device is `device_label` on the record, and the two are worth telling
@@ -242,7 +249,16 @@ export const AuthRefreshResponse = response("auth_refresh", AuthRefreshResult);
242
249
  * verification, the record lookup — the receiving instance does itself. */
243
250
  export const AuthResolveArgs = Type.Union(
244
251
  [
245
- Type.Object({ kind: Type.Literal("register"), token: Type.String({ minLength: 1 }) }),
252
+ Type.Object({
253
+ kind: Type.Literal("register"),
254
+ token: Type.String({ minLength: 1 }),
255
+ /** The digits the person typed, forwarded unchecked. The issuer holds
256
+ * both the code and the count of attempts against it, so it is the only
257
+ * one that can refuse a wrong one and retire the URL after enough of
258
+ * them; a receiver that judged the code itself would let an attacker
259
+ * spread guesses across instances without any of them counting. */
260
+ code: Type.String({ pattern: "^[0-9]{6}$" }),
261
+ }),
246
262
  Type.Object({ kind: Type.Literal("challenge"), challenge: Base64Url }),
247
263
  ],
248
264
  { $id: "AuthResolveArgs" },
@@ -300,7 +316,9 @@ export const CredentialRecord = Type.Object(
300
316
  credential_id: Base64Url,
301
317
  /** The public key, COSE-encoded. */
302
318
  public_key: Base64Url,
303
- /** The `user.id` this credential was created against. */
319
+ /** The `user_id` of the registration's claims, which is what the credential
320
+ * was created against and what an assertion naming a handle is checked
321
+ * against. */
304
322
  user_handle: Base64Url,
305
323
  /** The relying party this credential was created under, as the claims of
306
324
  * the registration that made it stated. Written by the registration and not