@ccmsg/protocol 1.0.0 → 1.2.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 +50 -0
- package/src/common/hello.ts +12 -5
package/package.json
CHANGED
package/src/common/auth.ts
CHANGED
|
@@ -92,6 +92,11 @@ 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
|
+
/** What the administrator who issued the URL wrote down about who it was
|
|
96
|
+
* for. Their words, not the holder's — the label the person gives their
|
|
97
|
+
* own device is `device_label` on the record, and the two are worth telling
|
|
98
|
+
* apart when a list is read back later. */
|
|
99
|
+
issued_label: Type.Optional(Type.String({ maxLength: 128 })),
|
|
95
100
|
},
|
|
96
101
|
{ $id: "RegisterClaims" },
|
|
97
102
|
);
|
|
@@ -118,6 +123,24 @@ export const AuthRegisterArgs = Type.Object({
|
|
|
118
123
|
/** The registration URL's token, opaque to the caller and to any instance
|
|
119
124
|
* but its issuer. */
|
|
120
125
|
token: Type.String({ minLength: 1 }),
|
|
126
|
+
/** The six digits the command line showed when the URL was made, typed in by
|
|
127
|
+
* the person registering. It is not in the URL and never travels with it, so
|
|
128
|
+
* a leaked URL is not a registration: the two halves reach the browser by
|
|
129
|
+
* different routes, and only someone who was shown the terminal has both. */
|
|
130
|
+
code: Type.String({ pattern: "^[0-9]{6}$" }),
|
|
131
|
+
/** What the person calls the device they are registering, for their own use
|
|
132
|
+
* when they later read back a list of several. Nothing is decided by it. */
|
|
133
|
+
device_label: Type.Optional(Type.String({ maxLength: 128 })),
|
|
134
|
+
/** The challenge this registration answers, with the instance that can spend
|
|
135
|
+
* it — the same pairing an assertion carries, and for the same reason: the
|
|
136
|
+
* value also sits inside `client_data_json`, but who may consume it does not,
|
|
137
|
+
* and behind a load balancer the instance that issued it, the one that made
|
|
138
|
+
* the registration URL and the one receiving this may all be different.
|
|
139
|
+
*
|
|
140
|
+
* Omitting it leaves the receiver with a value and no issuer, so it can only
|
|
141
|
+
* be honoured where the receiver itself holds the challenge; anywhere else
|
|
142
|
+
* the registration is refused rather than guessed at. */
|
|
143
|
+
challenge: Type.Optional(AuthChallenge),
|
|
121
144
|
credential: RegistrationCredential,
|
|
122
145
|
});
|
|
123
146
|
export type AuthRegisterArgs = Static<typeof AuthRegisterArgs>;
|
|
@@ -279,11 +302,38 @@ export const CredentialRecord = Type.Object(
|
|
|
279
302
|
public_key: Base64Url,
|
|
280
303
|
/** The `user.id` this credential was created against. */
|
|
281
304
|
user_handle: Base64Url,
|
|
305
|
+
/** The relying party this credential was created under, as the claims of
|
|
306
|
+
* the registration that made it stated. Written by the registration and not
|
|
307
|
+
* derived later: a passkey only answers for the domain it was made under,
|
|
308
|
+
* so an assertion's `rpIdHash` is checked against this and not against
|
|
309
|
+
* whatever the endpoint being reached happens to be. Absent only on a
|
|
310
|
+
* record written before the field existed. */
|
|
311
|
+
rp_id: Type.Optional(Type.String({ minLength: 1 })),
|
|
282
312
|
/** The authenticator's counter, when it keeps one. Synced passkeys report
|
|
283
313
|
* zero forever, so only a pair of non-zero readings says anything, and a
|
|
284
314
|
* reading below the last one is a refusal. */
|
|
285
315
|
sign_count: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
316
|
+
/** The label the administrator put on the registration URL, carried over
|
|
317
|
+
* from the claims it was spent against. */
|
|
318
|
+
issued_label: Type.Optional(Type.String({ maxLength: 128 })),
|
|
319
|
+
/** The label the person put on this device as they registered it. */
|
|
320
|
+
device_label: Type.Optional(Type.String({ maxLength: 128 })),
|
|
286
321
|
registered_at: Timestamp,
|
|
322
|
+
/** Where the registration came from and what browser sent it.
|
|
323
|
+
*
|
|
324
|
+
* None of this authenticates anything, and nothing is ever admitted or
|
|
325
|
+
* refused by it — an address is trivially chosen by whoever is making the
|
|
326
|
+
* request. They are here to be recognised by the one person reading their
|
|
327
|
+
* own list: an address that is their home provider's and a browser that is
|
|
328
|
+
* the one they use is how they place a line as theirs, or fail to, which is
|
|
329
|
+
* the whole reason to keep it. The same holds of the pair below. */
|
|
330
|
+
registered_ip: Type.Optional(Type.String({ minLength: 1, maxLength: 45 })),
|
|
331
|
+
registered_user_agent: Type.Optional(Type.String({ maxLength: 512 })),
|
|
332
|
+
/** When this credential last answered a challenge, and from where. A
|
|
333
|
+
* credential the person no longer recognises is one they remove. */
|
|
334
|
+
last_used_at: Type.Optional(Timestamp),
|
|
335
|
+
last_used_ip: Type.Optional(Type.String({ minLength: 1, maxLength: 45 })),
|
|
336
|
+
last_used_user_agent: Type.Optional(Type.String({ maxLength: 512 })),
|
|
287
337
|
},
|
|
288
338
|
{ $id: "CredentialRecord" },
|
|
289
339
|
);
|
package/src/common/hello.ts
CHANGED
|
@@ -86,11 +86,16 @@ export type HelloArgs = Static<typeof HelloArgs>;
|
|
|
86
86
|
/** One instance as seen from the instance answering `hello`. */
|
|
87
87
|
export const InstanceInfo = Type.Object(
|
|
88
88
|
{
|
|
89
|
-
|
|
89
|
+
/** Absent until the handshake with it has settled: an endpoint an operator
|
|
90
|
+
* configured is known before anything answers there, and leaving such a
|
|
91
|
+
* peer out of the list would hide the very entry whose link is down. */
|
|
92
|
+
id: Type.Optional(InstanceId),
|
|
90
93
|
/** Where it is dialed. An attribute of the instance like the host below:
|
|
91
94
|
* it is what a peer connects to and authenticates against, and it may
|
|
92
|
-
* change under a fixed `id` when the instance moves.
|
|
93
|
-
|
|
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),
|
|
94
99
|
/** The host it runs on. An attribute of the instance, not its identity —
|
|
95
100
|
* one host may run several instances. */
|
|
96
101
|
host: Type.String({ minLength: 1 }),
|
|
@@ -107,8 +112,10 @@ export const HelloResult = Type.Object({
|
|
|
107
112
|
instance: InstanceId,
|
|
108
113
|
/** Where the answering instance is dialed. Stated beside the id because the
|
|
109
114
|
* caller reached it by some URL of its own — a proxy's, an alias — and what a
|
|
110
|
-
* peer is to dial is neither that nor derivable from the id.
|
|
111
|
-
|
|
115
|
+
* peer is to dial is neither that nor derivable from the id. Absent on an
|
|
116
|
+
* instance that joins no mesh: it is reached by the people and sessions on
|
|
117
|
+
* its own machine, and it has no URL to give a peer. */
|
|
118
|
+
endpoint: Type.Optional(Endpoint),
|
|
112
119
|
/** The instances this one knows of, itself included. */
|
|
113
120
|
instances: Type.Array(InstanceInfo),
|
|
114
121
|
/** What this instance can do. An op whose `capability` is absent here
|