@ccmsg/protocol 1.4.0 → 1.6.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ccmsg/protocol",
3
- "version": "1.4.0",
3
+ "version": "1.6.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",
@@ -84,7 +84,9 @@ export const RegisterClaims = Type.Object(
84
84
  sub: Subject,
85
85
  /** The instance's name as a person operates it, for display. */
86
86
  unit: Type.String({ minLength: 1 }),
87
- /** The endpoint the credential is being registered for. */
87
+ /** The endpoint the credential is being registered for. The base URL: the
88
+ * registration is posted to `<endpoint>auth/register`, and the cookie set
89
+ * for it hangs under the same prefix. */
88
90
  endpoint: Endpoint,
89
91
  /** The WebAuthn relying party: a domain, not an origin. Either the
90
92
  * endpoint's host or a registrable suffix of it. */
@@ -320,6 +322,18 @@ export const CredentialRecord = Type.Object(
320
322
  * was created against and what an assertion naming a handle is checked
321
323
  * against. */
322
324
  user_handle: Base64Url,
325
+ /** The endpoint this credential was registered for, as the registration's
326
+ * claims stated it.
327
+ *
328
+ * What the credential is good for, and the whole of it: an assertion is
329
+ * accepted only where the origin matches and the request's path falls under
330
+ * this base URL. `https://h.example/` and `https://h.example/personal/` are
331
+ * two endpoints and take two registrations, even on one host and one
332
+ * relying party — the RP ID says which domain an authenticator will answer
333
+ * for, which is a coarser thing than which instance a person has been
334
+ * admitted to. Binding to the base URL rather than the origin is what keeps
335
+ * one instance's credential from being a way into its neighbour. */
336
+ endpoint: Endpoint,
323
337
  /** The relying party this credential was created under, as the claims of
324
338
  * the registration that made it stated. Written by the registration and not
325
339
  * derived later: a passkey only answers for the domain it was made under,
@@ -13,9 +13,10 @@ export const MeshHello = Type.Object(
13
13
  /** Generation of the mesh handshake format, apart from the protocol
14
14
  * generation so the handshake can change without the wire changing. */
15
15
  ver: Type.Integer({ minimum: 1 }),
16
- /** The endpoint URL the connecting instance claims to be reached at. */
16
+ /** The base URL the connecting instance claims to be published at — the
17
+ * endpoint itself, not the `<endpoint>ws` it dialed to get here. */
17
18
  iss: Endpoint,
18
- /** The endpoint URL it believes it is connecting to. Compared whole
19
+ /** The base URL it believes it is connecting to. Compared whole
19
20
  * against the receiver's own URL, which is what stops a signature made for
20
21
  * one instance from being replayed at another on the same host. */
21
22
  aud: Endpoint,
@@ -90,9 +91,11 @@ export const InstanceInfo = Type.Object(
90
91
  * configured is known before anything answers there, and leaving such a
91
92
  * peer out of the list would hide the very entry whose link is down. */
92
93
  id: Type.Optional(InstanceId),
93
- /** Where it is dialed. An attribute of the instance like the host below:
94
- * it is what a peer connects to and authenticates against, and it may
95
- * change under a fixed `id` when the instance moves. Absent for the same
94
+ /** The base URL it is published at, which a peer dials as `<endpoint>ws`,
95
+ * that scheme included the WebSocket upgrades from an HTTP request.
96
+ * An attribute of the instance like the host below: it is what a peer
97
+ * connects to and authenticates against, and it may change under a fixed
98
+ * `id` when the instance moves. Absent for the same
96
99
  * reason it is absent from the reply's own `endpoint`: an instance in no
97
100
  * mesh has no URL to be dialed at, including on its own line. */
98
101
  endpoint: Type.Optional(Endpoint),
@@ -110,7 +113,8 @@ export const HelloResult = Type.Object({
110
113
  protocol_version: Type.Integer({ minimum: 1 }),
111
114
  /** The instance answering. Every other id in the reply is relative to it. */
112
115
  instance: InstanceId,
113
- /** Where the answering instance is dialed. Stated beside the id because the
116
+ /** The base URL the answering instance is published at, under which its own
117
+ * routes (`ws`, `mesh/…`, `auth/…`) sit. Stated beside the id because the
114
118
  * caller reached it by some URL of its own — a proxy's, an alias — and what a
115
119
  * peer is to dial is neither that nor derivable from the id. Absent on an
116
120
  * instance that joins no mesh: it is reached by the people and sessions on
@@ -43,9 +43,22 @@ export const InstanceId = Type.String({
43
43
  });
44
44
  export type InstanceId = Static<typeof InstanceId>;
45
45
 
46
- /** Where an instance is reached: the URL other instances dial, compared as a
47
- * whole string including its path (mesh-peer-auth §4.2 one origin may host
48
- * several instances, so origin-level comparison would confuse them).
46
+ /** Where an instance is published: the base URL everything it serves hangs
47
+ * under, ending in a slash and naming no route of its own.
48
+ *
49
+ * The routes are below it and are not part of it — `<endpoint>ws` for the
50
+ * WebSocket, `<endpoint>mesh/…`, `<endpoint>auth/…`, `<endpoint>webhook/…`. All
51
+ * of them keep the endpoint's own scheme: a WebSocket starts as an HTTP request
52
+ * that upgrades, so there is no second spelling of the URL and nothing to
53
+ * rewrite. Naming the base rather than one of
54
+ * them is what lets a transport be added or replaced without the value that
55
+ * identifies where an instance lives changing with it, and what lets the HTTP
56
+ * routes be spelled without stripping a suffix off first.
57
+ *
58
+ * Compared as a whole string, path included (mesh-peer-auth §4.2 — one origin
59
+ * may host several instances, so an origin-level comparison would confuse
60
+ * them). The trailing slash is required so that comparison is exact: `/ccmsg`
61
+ * and `/ccmsg/` would otherwise be two spellings of one instance.
49
62
  *
50
63
  * Apart from `InstanceId` because the two answer different questions and change
51
64
  * on different occasions. This is what a peer dials, what the TLS certificate
@@ -55,7 +68,7 @@ export type InstanceId = Static<typeof InstanceId>;
55
68
  * not alter. */
56
69
  export const Endpoint = Type.String({
57
70
  $id: "Endpoint",
58
- pattern: "^wss?://[^\\s?#]+$",
71
+ pattern: "^https?://[^/?#\\s]+(/[^?#\\s]*)?/$",
59
72
  });
60
73
  export type Endpoint = Static<typeof Endpoint>;
61
74