@ccmsg/protocol 1.1.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.
- package/package.json +1 -1
- package/src/common/auth.ts +37 -2
- package/src/common/hello.ts +4 -2
package/package.json
CHANGED
package/src/common/auth.ts
CHANGED
|
@@ -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
|
|
@@ -131,6 +138,16 @@ export const AuthRegisterArgs = Type.Object({
|
|
|
131
138
|
/** What the person calls the device they are registering, for their own use
|
|
132
139
|
* when they later read back a list of several. Nothing is decided by it. */
|
|
133
140
|
device_label: Type.Optional(Type.String({ maxLength: 128 })),
|
|
141
|
+
/** The challenge this registration answers, with the instance that can spend
|
|
142
|
+
* it — the same pairing an assertion carries, and for the same reason: the
|
|
143
|
+
* value also sits inside `client_data_json`, but who may consume it does not,
|
|
144
|
+
* and behind a load balancer the instance that issued it, the one that made
|
|
145
|
+
* the registration URL and the one receiving this may all be different.
|
|
146
|
+
*
|
|
147
|
+
* Omitting it leaves the receiver with a value and no issuer, so it can only
|
|
148
|
+
* be honoured where the receiver itself holds the challenge; anywhere else
|
|
149
|
+
* the registration is refused rather than guessed at. */
|
|
150
|
+
challenge: Type.Optional(AuthChallenge),
|
|
134
151
|
credential: RegistrationCredential,
|
|
135
152
|
});
|
|
136
153
|
export type AuthRegisterArgs = Static<typeof AuthRegisterArgs>;
|
|
@@ -232,7 +249,16 @@ export const AuthRefreshResponse = response("auth_refresh", AuthRefreshResult);
|
|
|
232
249
|
* verification, the record lookup — the receiving instance does itself. */
|
|
233
250
|
export const AuthResolveArgs = Type.Union(
|
|
234
251
|
[
|
|
235
|
-
Type.Object({
|
|
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
|
+
}),
|
|
236
262
|
Type.Object({ kind: Type.Literal("challenge"), challenge: Base64Url }),
|
|
237
263
|
],
|
|
238
264
|
{ $id: "AuthResolveArgs" },
|
|
@@ -290,8 +316,17 @@ export const CredentialRecord = Type.Object(
|
|
|
290
316
|
credential_id: Base64Url,
|
|
291
317
|
/** The public key, COSE-encoded. */
|
|
292
318
|
public_key: Base64Url,
|
|
293
|
-
/** The `
|
|
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. */
|
|
294
322
|
user_handle: Base64Url,
|
|
323
|
+
/** The relying party this credential was created under, as the claims of
|
|
324
|
+
* the registration that made it stated. Written by the registration and not
|
|
325
|
+
* derived later: a passkey only answers for the domain it was made under,
|
|
326
|
+
* so an assertion's `rpIdHash` is checked against this and not against
|
|
327
|
+
* whatever the endpoint being reached happens to be. Absent only on a
|
|
328
|
+
* record written before the field existed. */
|
|
329
|
+
rp_id: Type.Optional(Type.String({ minLength: 1 })),
|
|
295
330
|
/** The authenticator's counter, when it keeps one. Synced passkeys report
|
|
296
331
|
* zero forever, so only a pair of non-zero readings says anything, and a
|
|
297
332
|
* reading below the last one is a refusal. */
|
package/src/common/hello.ts
CHANGED
|
@@ -92,8 +92,10 @@ export const InstanceInfo = Type.Object(
|
|
|
92
92
|
id: Type.Optional(InstanceId),
|
|
93
93
|
/** Where it is dialed. An attribute of the instance like the host below:
|
|
94
94
|
* it is what a peer connects to and authenticates against, and it may
|
|
95
|
-
* change under a fixed `id` when the instance moves.
|
|
96
|
-
|
|
95
|
+
* change under a fixed `id` when the instance moves. Absent for the same
|
|
96
|
+
* reason it is absent from the reply's own `endpoint`: an instance in no
|
|
97
|
+
* mesh has no URL to be dialed at, including on its own line. */
|
|
98
|
+
endpoint: Type.Optional(Endpoint),
|
|
97
99
|
/** The host it runs on. An attribute of the instance, not its identity —
|
|
98
100
|
* one host may run several instances. */
|
|
99
101
|
host: Type.String({ minLength: 1 }),
|