wire-mesh-core 1.27.0 → 1.28.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/dist/domain/room.cjs +38 -0
- package/dist/domain/room.d.cts +18 -1
- package/dist/domain/room.d.mts +18 -1
- package/dist/domain/room.mjs +38 -1
- package/package.json +1 -1
package/dist/domain/room.cjs
CHANGED
|
@@ -6,6 +6,19 @@ let cbor2 = require("cbor2");
|
|
|
6
6
|
/**
|
|
7
7
|
* Room-notice verification (spec/room.cddl's own noticeboard extension of core/room). A room-notice is self-certifying the same way a capability-token or revocation-entry already is: a bare cose-sign1 whose payload carries its own signer's key, so a reader verifies posting authority from the entry alone, with no prior contact with the poster and no central gatekeeper. This module is the first TypeScript verifier for it -- no `room.ts` domain module existed anywhere before this, despite the CDDL claim (including `valid-until`) having shipped already.
|
|
8
8
|
*/
|
|
9
|
+
function buf(bytes) {
|
|
10
|
+
return Uint8Array.from(bytes);
|
|
11
|
+
}
|
|
12
|
+
function encodeBuf(value) {
|
|
13
|
+
return buf((0, cbor2.encode)(value, cbor2.cdeEncodeOptions));
|
|
14
|
+
}
|
|
15
|
+
/** The COSE protected header a room-notice signs over: label 1 (alg) and label 4 (kid, the poster's own device-id) -- the identical shape tokens.ts's own protectedHeaderFor uses for capability-token/revocation-entry envelopes, reimplemented here rather than imported since tokens.ts does not export it (matching sig1ToBeSigned's own precedent below). verifyRoomNotice never inspects this header's own decoded content -- it only needs the same bytes fed back into its own signature check -- but a real, kid-bearing header keeps a room-notice's wire shape consistent with every other signed envelope in this spec, rather than the empty header a merely-self-consistent test fixture can get away with. */
|
|
16
|
+
function protectedHeaderFor(identity) {
|
|
17
|
+
return encodeBuf({
|
|
18
|
+
1: identity.identityKey.alg,
|
|
19
|
+
4: identity.deviceId
|
|
20
|
+
});
|
|
21
|
+
}
|
|
9
22
|
/**
|
|
10
23
|
* RFC 9052 §4.4 Sig_structure for a COSE_Sign1 with no external AAD -- identical in shape to tokens.ts's own private helper of the same name, but reimplemented here rather than imported, since tokens.ts does not export it. Worth consolidating into a shared cose.ts once a third caller needs the identical helper, but two independent five-line copies is not yet a real duplication problem on its own.
|
|
11
24
|
*/
|
|
@@ -103,6 +116,31 @@ function compareRoomNotices(a, b) {
|
|
|
103
116
|
if (posterOrder !== 0) return posterOrder;
|
|
104
117
|
return compareBytes(a["notice-id"], b["notice-id"]);
|
|
105
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Mints one self-certifying room-notice as `identity` -- the counterpart to verifyRoomNotice above, producing exactly what it accepts. `posted-at` is always stamped from the injected clock, never caller-supplied, matching obligation 4's own requirement that a poster's own log stay non-decreasing: a caller backdating its own posted-at would be indistinguishable from a clock bug at mint time, so this function simply doesn't expose the field to override.
|
|
121
|
+
*/
|
|
122
|
+
async function createRoomNotice(options) {
|
|
123
|
+
const payload = encodeBuf({
|
|
124
|
+
room: options.room,
|
|
125
|
+
poster: options.identity.deviceId,
|
|
126
|
+
"poster-key": options.identity.identityKey,
|
|
127
|
+
token: options.token,
|
|
128
|
+
"notice-id": options.noticeId,
|
|
129
|
+
"posted-at": options.clock.now(),
|
|
130
|
+
"content-type": options.contentType,
|
|
131
|
+
content: options.content,
|
|
132
|
+
...options.refs !== void 0 ? { refs: [...options.refs] } : {},
|
|
133
|
+
...options.validUntil !== void 0 ? { "valid-until": options.validUntil } : {}
|
|
134
|
+
});
|
|
135
|
+
const protectedHeader = protectedHeaderFor(options.identity);
|
|
136
|
+
return [
|
|
137
|
+
protectedHeader,
|
|
138
|
+
{},
|
|
139
|
+
payload,
|
|
140
|
+
await options.identity.sign(sig1ToBeSigned(protectedHeader, payload))
|
|
141
|
+
];
|
|
142
|
+
}
|
|
106
143
|
//#endregion
|
|
107
144
|
exports.compareRoomNotices = compareRoomNotices;
|
|
145
|
+
exports.createRoomNotice = createRoomNotice;
|
|
108
146
|
exports.verifyRoomNotice = verifyRoomNotice;
|
package/dist/domain/room.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Dt as RoomPath, Et as RoomNoticeClaims, Tt as RoomNotice } from "../protocol-sW8d6Og-.cjs";
|
|
1
|
+
import { Dt as RoomPath, Et as RoomNoticeClaims, Tt as RoomNotice, p as CapabilityToken, q as MessageRef } from "../protocol-sW8d6Og-.cjs";
|
|
2
2
|
import { t as IdentityPort } from "../identity-DJ06jn4k.cjs";
|
|
3
3
|
import { t as Clock } from "../clock-DiSx-WKM.cjs";
|
|
4
4
|
import { a as RevocationCheck } from "../tokens-DfVfE00W.cjs";
|
|
@@ -33,4 +33,21 @@ export declare function verifyRoomNotice(notice: RoomNotice, options: Readonly<V
|
|
|
33
33
|
* Deterministic display ordering for room-notice entries from possibly several different posters (spec/room.cddl obligation 4): sorts by (posted-at, poster, notice-id), the exact tiebreak idiom the CDDL comment specifies -- the same "lowest wins" idea coordinator-frame's own lowest-device-id rule already uses for equal-term claims elsewhere in this spec. Takes already-verified claims (the output of verifyRoomNotice) -- this is purely a merge-order comparator, never a validity check, so it is kept structurally separate from verifyRoomNotice's own pass/fail verdict.
|
|
34
34
|
*/
|
|
35
35
|
export declare function compareRoomNotices(a: Readonly<RoomNoticeClaims>, b: Readonly<RoomNoticeClaims>): number;
|
|
36
|
+
export interface CreateRoomNoticeOptions {
|
|
37
|
+
identity: IdentityPort;
|
|
38
|
+
clock: Clock;
|
|
39
|
+
room: RoomPath;
|
|
40
|
+
/** The poster's own room:member token, embedded in full -- a reader checks token-claims.bearer against this notice's own signed poster field (see verifyRoomNotice's own obligation 2), so there is no live connection for the bearer binding to ride on the way a real room.send has. */
|
|
41
|
+
token: CapabilityToken;
|
|
42
|
+
/** Caller-supplied, matching mintCapabilityToken's own tokenId/mintRevocationEntry's own tokenId convention -- this module has no opinion on how a noticeId is generated (random bytes, a counter, anything else), only that it is unique enough for compareRoomNotices' own cross-author tiebreak to work. */
|
|
43
|
+
noticeId: Uint8Array<ArrayBuffer>;
|
|
44
|
+
contentType: string;
|
|
45
|
+
content: Uint8Array<ArrayBuffer>;
|
|
46
|
+
refs?: readonly MessageRef[];
|
|
47
|
+
validUntil?: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Mints one self-certifying room-notice as `identity` -- the counterpart to verifyRoomNotice above, producing exactly what it accepts. `posted-at` is always stamped from the injected clock, never caller-supplied, matching obligation 4's own requirement that a poster's own log stay non-decreasing: a caller backdating its own posted-at would be indistinguishable from a clock bug at mint time, so this function simply doesn't expose the field to override.
|
|
51
|
+
*/
|
|
52
|
+
export declare function createRoomNotice(options: Readonly<CreateRoomNoticeOptions>): Promise<RoomNotice>;
|
|
36
53
|
//#endregion
|
package/dist/domain/room.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Dt as RoomPath, Et as RoomNoticeClaims, Tt as RoomNotice } from "../protocol-sW8d6Og-.mjs";
|
|
1
|
+
import { Dt as RoomPath, Et as RoomNoticeClaims, Tt as RoomNotice, p as CapabilityToken, q as MessageRef } from "../protocol-sW8d6Og-.mjs";
|
|
2
2
|
import { t as IdentityPort } from "../identity-C5N86BPz.mjs";
|
|
3
3
|
import { t as Clock } from "../clock-DiSx-WKM.mjs";
|
|
4
4
|
import { a as RevocationCheck } from "../tokens-CpLDI5Fo.mjs";
|
|
@@ -33,4 +33,21 @@ export declare function verifyRoomNotice(notice: RoomNotice, options: Readonly<V
|
|
|
33
33
|
* Deterministic display ordering for room-notice entries from possibly several different posters (spec/room.cddl obligation 4): sorts by (posted-at, poster, notice-id), the exact tiebreak idiom the CDDL comment specifies -- the same "lowest wins" idea coordinator-frame's own lowest-device-id rule already uses for equal-term claims elsewhere in this spec. Takes already-verified claims (the output of verifyRoomNotice) -- this is purely a merge-order comparator, never a validity check, so it is kept structurally separate from verifyRoomNotice's own pass/fail verdict.
|
|
34
34
|
*/
|
|
35
35
|
export declare function compareRoomNotices(a: Readonly<RoomNoticeClaims>, b: Readonly<RoomNoticeClaims>): number;
|
|
36
|
+
export interface CreateRoomNoticeOptions {
|
|
37
|
+
identity: IdentityPort;
|
|
38
|
+
clock: Clock;
|
|
39
|
+
room: RoomPath;
|
|
40
|
+
/** The poster's own room:member token, embedded in full -- a reader checks token-claims.bearer against this notice's own signed poster field (see verifyRoomNotice's own obligation 2), so there is no live connection for the bearer binding to ride on the way a real room.send has. */
|
|
41
|
+
token: CapabilityToken;
|
|
42
|
+
/** Caller-supplied, matching mintCapabilityToken's own tokenId/mintRevocationEntry's own tokenId convention -- this module has no opinion on how a noticeId is generated (random bytes, a counter, anything else), only that it is unique enough for compareRoomNotices' own cross-author tiebreak to work. */
|
|
43
|
+
noticeId: Uint8Array<ArrayBuffer>;
|
|
44
|
+
contentType: string;
|
|
45
|
+
content: Uint8Array<ArrayBuffer>;
|
|
46
|
+
refs?: readonly MessageRef[];
|
|
47
|
+
validUntil?: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Mints one self-certifying room-notice as `identity` -- the counterpart to verifyRoomNotice above, producing exactly what it accepts. `posted-at` is always stamped from the injected clock, never caller-supplied, matching obligation 4's own requirement that a poster's own log stay non-decreasing: a caller backdating its own posted-at would be indistinguishable from a clock bug at mint time, so this function simply doesn't expose the field to override.
|
|
51
|
+
*/
|
|
52
|
+
export declare function createRoomNotice(options: Readonly<CreateRoomNoticeOptions>): Promise<RoomNotice>;
|
|
36
53
|
//#endregion
|
package/dist/domain/room.mjs
CHANGED
|
@@ -5,6 +5,19 @@ import { cdeDecodeOptions, cdeEncodeOptions, decode, encode } from "cbor2";
|
|
|
5
5
|
/**
|
|
6
6
|
* Room-notice verification (spec/room.cddl's own noticeboard extension of core/room). A room-notice is self-certifying the same way a capability-token or revocation-entry already is: a bare cose-sign1 whose payload carries its own signer's key, so a reader verifies posting authority from the entry alone, with no prior contact with the poster and no central gatekeeper. This module is the first TypeScript verifier for it -- no `room.ts` domain module existed anywhere before this, despite the CDDL claim (including `valid-until`) having shipped already.
|
|
7
7
|
*/
|
|
8
|
+
function buf(bytes) {
|
|
9
|
+
return Uint8Array.from(bytes);
|
|
10
|
+
}
|
|
11
|
+
function encodeBuf(value) {
|
|
12
|
+
return buf(encode(value, cdeEncodeOptions));
|
|
13
|
+
}
|
|
14
|
+
/** The COSE protected header a room-notice signs over: label 1 (alg) and label 4 (kid, the poster's own device-id) -- the identical shape tokens.ts's own protectedHeaderFor uses for capability-token/revocation-entry envelopes, reimplemented here rather than imported since tokens.ts does not export it (matching sig1ToBeSigned's own precedent below). verifyRoomNotice never inspects this header's own decoded content -- it only needs the same bytes fed back into its own signature check -- but a real, kid-bearing header keeps a room-notice's wire shape consistent with every other signed envelope in this spec, rather than the empty header a merely-self-consistent test fixture can get away with. */
|
|
15
|
+
function protectedHeaderFor(identity) {
|
|
16
|
+
return encodeBuf({
|
|
17
|
+
1: identity.identityKey.alg,
|
|
18
|
+
4: identity.deviceId
|
|
19
|
+
});
|
|
20
|
+
}
|
|
8
21
|
/**
|
|
9
22
|
* RFC 9052 §4.4 Sig_structure for a COSE_Sign1 with no external AAD -- identical in shape to tokens.ts's own private helper of the same name, but reimplemented here rather than imported, since tokens.ts does not export it. Worth consolidating into a shared cose.ts once a third caller needs the identical helper, but two independent five-line copies is not yet a real duplication problem on its own.
|
|
10
23
|
*/
|
|
@@ -102,5 +115,29 @@ function compareRoomNotices(a, b) {
|
|
|
102
115
|
if (posterOrder !== 0) return posterOrder;
|
|
103
116
|
return compareBytes(a["notice-id"], b["notice-id"]);
|
|
104
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Mints one self-certifying room-notice as `identity` -- the counterpart to verifyRoomNotice above, producing exactly what it accepts. `posted-at` is always stamped from the injected clock, never caller-supplied, matching obligation 4's own requirement that a poster's own log stay non-decreasing: a caller backdating its own posted-at would be indistinguishable from a clock bug at mint time, so this function simply doesn't expose the field to override.
|
|
120
|
+
*/
|
|
121
|
+
async function createRoomNotice(options) {
|
|
122
|
+
const payload = encodeBuf({
|
|
123
|
+
room: options.room,
|
|
124
|
+
poster: options.identity.deviceId,
|
|
125
|
+
"poster-key": options.identity.identityKey,
|
|
126
|
+
token: options.token,
|
|
127
|
+
"notice-id": options.noticeId,
|
|
128
|
+
"posted-at": options.clock.now(),
|
|
129
|
+
"content-type": options.contentType,
|
|
130
|
+
content: options.content,
|
|
131
|
+
...options.refs !== void 0 ? { refs: [...options.refs] } : {},
|
|
132
|
+
...options.validUntil !== void 0 ? { "valid-until": options.validUntil } : {}
|
|
133
|
+
});
|
|
134
|
+
const protectedHeader = protectedHeaderFor(options.identity);
|
|
135
|
+
return [
|
|
136
|
+
protectedHeader,
|
|
137
|
+
{},
|
|
138
|
+
payload,
|
|
139
|
+
await options.identity.sign(sig1ToBeSigned(protectedHeader, payload))
|
|
140
|
+
];
|
|
141
|
+
}
|
|
105
142
|
//#endregion
|
|
106
|
-
export { compareRoomNotices, verifyRoomNotice };
|
|
143
|
+
export { compareRoomNotices, createRoomNotice, verifyRoomNotice };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wire-mesh-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c",
|
|
6
6
|
"repository": {
|