wire-mesh-core 1.33.0 → 1.35.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/group-key.cjs +18 -0
- package/dist/domain/group-key.d.cts +8 -0
- package/dist/domain/group-key.d.mts +8 -0
- package/dist/domain/group-key.mjs +15 -1
- package/dist/domain/room.cjs +8 -1
- package/dist/domain/room.d.cts +3 -1
- package/dist/domain/room.d.mts +3 -1
- package/dist/domain/room.mjs +8 -1
- package/package.json +1 -1
|
@@ -84,10 +84,28 @@ async function encryptNoticeContent(contentKey, plaintext) {
|
|
|
84
84
|
async function decryptNoticeContent(contentKey, ciphertext) {
|
|
85
85
|
return aesGcmDecrypt(await importContentKey(contentKey), ciphertext);
|
|
86
86
|
}
|
|
87
|
+
/** The literal content-type suffix marking a room-notice's content as AES-256-GCM-encrypted under a room.rekey epoch's content key (room.cddl's own key-epoch obligation comment) -- the same suffix convention MIME structured syntaxes like `application/jose+json` already use, so a reader without the key still learns the notice's true underlying kind. */
|
|
88
|
+
const ENCRYPTED_CONTENT_TYPE_SUFFIX = "+aes256gcm";
|
|
89
|
+
/** The notice's own TRUE content-type, with the encryption suffix appended -- never a separate generic sentinel, so the true type stays visible without decrypting anything. Idempotent: an already-suffixed type is returned unchanged. */
|
|
90
|
+
function encryptedContentType(plaintextContentType_) {
|
|
91
|
+
return isEncryptedContentType(plaintextContentType_) ? plaintextContentType_ : `${plaintextContentType_}${ENCRYPTED_CONTENT_TYPE_SUFFIX}`;
|
|
92
|
+
}
|
|
93
|
+
/** Strips the encryption suffix back off, recovering the plaintext content-type the sender originally had. A content-type carrying no suffix is returned unchanged. */
|
|
94
|
+
function plaintextContentType(encryptedContentType_) {
|
|
95
|
+
return isEncryptedContentType(encryptedContentType_) ? encryptedContentType_.slice(0, encryptedContentType_.length - 10) : encryptedContentType_;
|
|
96
|
+
}
|
|
97
|
+
/** Whether a content-type names encrypted content (and therefore that the notice carrying it MUST also name its key-epoch -- room.cddl obligation 7). */
|
|
98
|
+
function isEncryptedContentType(contentType) {
|
|
99
|
+
return contentType.endsWith(ENCRYPTED_CONTENT_TYPE_SUFFIX);
|
|
100
|
+
}
|
|
87
101
|
//#endregion
|
|
102
|
+
exports.ENCRYPTED_CONTENT_TYPE_SUFFIX = ENCRYPTED_CONTENT_TYPE_SUFFIX;
|
|
88
103
|
exports.decryptNoticeContent = decryptNoticeContent;
|
|
89
104
|
exports.deriveWrappingKey = deriveWrappingKey;
|
|
90
105
|
exports.encryptNoticeContent = encryptNoticeContent;
|
|
106
|
+
exports.encryptedContentType = encryptedContentType;
|
|
91
107
|
exports.generateContentKey = generateContentKey;
|
|
108
|
+
exports.isEncryptedContentType = isEncryptedContentType;
|
|
109
|
+
exports.plaintextContentType = plaintextContentType;
|
|
92
110
|
exports.unwrapContentKey = unwrapContentKey;
|
|
93
111
|
exports.wrapContentKey = wrapContentKey;
|
|
@@ -21,4 +21,12 @@ export declare function unwrapContentKey(wrappingKey: CryptoKey, wrapped: Uint8A
|
|
|
21
21
|
export declare function encryptNoticeContent(contentKey: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
|
|
22
22
|
/** Decrypts a room-notice's own `content`, given the content-encryption key for the epoch its key-epoch field names. Rejects on a wrong key or tampered ciphertext, same as unwrapContentKey. */
|
|
23
23
|
export declare function decryptNoticeContent(contentKey: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
|
|
24
|
+
/** The literal content-type suffix marking a room-notice's content as AES-256-GCM-encrypted under a room.rekey epoch's content key (room.cddl's own key-epoch obligation comment) -- the same suffix convention MIME structured syntaxes like `application/jose+json` already use, so a reader without the key still learns the notice's true underlying kind. */
|
|
25
|
+
export declare const ENCRYPTED_CONTENT_TYPE_SUFFIX = "+aes256gcm";
|
|
26
|
+
/** The notice's own TRUE content-type, with the encryption suffix appended -- never a separate generic sentinel, so the true type stays visible without decrypting anything. Idempotent: an already-suffixed type is returned unchanged. */
|
|
27
|
+
export declare function encryptedContentType(plaintextContentType_: string): string;
|
|
28
|
+
/** Strips the encryption suffix back off, recovering the plaintext content-type the sender originally had. A content-type carrying no suffix is returned unchanged. */
|
|
29
|
+
export declare function plaintextContentType(encryptedContentType_: string): string;
|
|
30
|
+
/** Whether a content-type names encrypted content (and therefore that the notice carrying it MUST also name its key-epoch -- room.cddl obligation 7). */
|
|
31
|
+
export declare function isEncryptedContentType(contentType: string): boolean;
|
|
24
32
|
//#endregion
|
|
@@ -21,4 +21,12 @@ export declare function unwrapContentKey(wrappingKey: CryptoKey, wrapped: Uint8A
|
|
|
21
21
|
export declare function encryptNoticeContent(contentKey: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
|
|
22
22
|
/** Decrypts a room-notice's own `content`, given the content-encryption key for the epoch its key-epoch field names. Rejects on a wrong key or tampered ciphertext, same as unwrapContentKey. */
|
|
23
23
|
export declare function decryptNoticeContent(contentKey: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
|
|
24
|
+
/** The literal content-type suffix marking a room-notice's content as AES-256-GCM-encrypted under a room.rekey epoch's content key (room.cddl's own key-epoch obligation comment) -- the same suffix convention MIME structured syntaxes like `application/jose+json` already use, so a reader without the key still learns the notice's true underlying kind. */
|
|
25
|
+
export declare const ENCRYPTED_CONTENT_TYPE_SUFFIX = "+aes256gcm";
|
|
26
|
+
/** The notice's own TRUE content-type, with the encryption suffix appended -- never a separate generic sentinel, so the true type stays visible without decrypting anything. Idempotent: an already-suffixed type is returned unchanged. */
|
|
27
|
+
export declare function encryptedContentType(plaintextContentType_: string): string;
|
|
28
|
+
/** Strips the encryption suffix back off, recovering the plaintext content-type the sender originally had. A content-type carrying no suffix is returned unchanged. */
|
|
29
|
+
export declare function plaintextContentType(encryptedContentType_: string): string;
|
|
30
|
+
/** Whether a content-type names encrypted content (and therefore that the notice carrying it MUST also name its key-epoch -- room.cddl obligation 7). */
|
|
31
|
+
export declare function isEncryptedContentType(contentType: string): boolean;
|
|
24
32
|
//#endregion
|
|
@@ -83,5 +83,19 @@ async function encryptNoticeContent(contentKey, plaintext) {
|
|
|
83
83
|
async function decryptNoticeContent(contentKey, ciphertext) {
|
|
84
84
|
return aesGcmDecrypt(await importContentKey(contentKey), ciphertext);
|
|
85
85
|
}
|
|
86
|
+
/** The literal content-type suffix marking a room-notice's content as AES-256-GCM-encrypted under a room.rekey epoch's content key (room.cddl's own key-epoch obligation comment) -- the same suffix convention MIME structured syntaxes like `application/jose+json` already use, so a reader without the key still learns the notice's true underlying kind. */
|
|
87
|
+
const ENCRYPTED_CONTENT_TYPE_SUFFIX = "+aes256gcm";
|
|
88
|
+
/** The notice's own TRUE content-type, with the encryption suffix appended -- never a separate generic sentinel, so the true type stays visible without decrypting anything. Idempotent: an already-suffixed type is returned unchanged. */
|
|
89
|
+
function encryptedContentType(plaintextContentType_) {
|
|
90
|
+
return isEncryptedContentType(plaintextContentType_) ? plaintextContentType_ : `${plaintextContentType_}${ENCRYPTED_CONTENT_TYPE_SUFFIX}`;
|
|
91
|
+
}
|
|
92
|
+
/** Strips the encryption suffix back off, recovering the plaintext content-type the sender originally had. A content-type carrying no suffix is returned unchanged. */
|
|
93
|
+
function plaintextContentType(encryptedContentType_) {
|
|
94
|
+
return isEncryptedContentType(encryptedContentType_) ? encryptedContentType_.slice(0, encryptedContentType_.length - 10) : encryptedContentType_;
|
|
95
|
+
}
|
|
96
|
+
/** Whether a content-type names encrypted content (and therefore that the notice carrying it MUST also name its key-epoch -- room.cddl obligation 7). */
|
|
97
|
+
function isEncryptedContentType(contentType) {
|
|
98
|
+
return contentType.endsWith(ENCRYPTED_CONTENT_TYPE_SUFFIX);
|
|
99
|
+
}
|
|
86
100
|
//#endregion
|
|
87
|
-
export { decryptNoticeContent, deriveWrappingKey, encryptNoticeContent, generateContentKey, unwrapContentKey, wrapContentKey };
|
|
101
|
+
export { ENCRYPTED_CONTENT_TYPE_SUFFIX, decryptNoticeContent, deriveWrappingKey, encryptNoticeContent, encryptedContentType, generateContentKey, isEncryptedContentType, plaintextContentType, unwrapContentKey, wrapContentKey };
|
package/dist/domain/room.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_generated_protocol = require("../generated/protocol.cjs");
|
|
3
|
+
const require_domain_group_key = require("./group-key.cjs");
|
|
3
4
|
const require_domain_room_token_verification = require("./room-token-verification.cjs");
|
|
4
5
|
let cbor2 = require("cbor2");
|
|
5
6
|
//#region src/domain/room.ts
|
|
@@ -91,6 +92,11 @@ async function verifyRoomNotice(notice, options) {
|
|
|
91
92
|
ok: false,
|
|
92
93
|
reason: "content_expired"
|
|
93
94
|
};
|
|
95
|
+
const keyEpoch = claims["key-epoch"];
|
|
96
|
+
if (require_domain_group_key.isEncryptedContentType(claims["content-type"]) !== (keyEpoch !== void 0)) return {
|
|
97
|
+
ok: false,
|
|
98
|
+
reason: "key_epoch_mismatch"
|
|
99
|
+
};
|
|
94
100
|
const tokenVerdict = await require_domain_room_token_verification.verifyRoomToken(claims.token, {
|
|
95
101
|
identity: options.identity,
|
|
96
102
|
clock: options.clock,
|
|
@@ -130,7 +136,8 @@ async function createRoomNotice(options) {
|
|
|
130
136
|
"content-type": options.contentType,
|
|
131
137
|
content: options.content,
|
|
132
138
|
...options.refs !== void 0 ? { refs: [...options.refs] } : {},
|
|
133
|
-
...options.validUntil !== void 0 ? { "valid-until": options.validUntil } : {}
|
|
139
|
+
...options.validUntil !== void 0 ? { "valid-until": options.validUntil } : {},
|
|
140
|
+
...options.keyEpoch !== void 0 ? { "key-epoch": options.keyEpoch } : {}
|
|
134
141
|
});
|
|
135
142
|
const protectedHeader = protectedHeaderFor(options.identity);
|
|
136
143
|
return [
|
package/dist/domain/room.d.cts
CHANGED
|
@@ -4,7 +4,7 @@ import { t as Clock } from "../clock-DiSx-WKM.cjs";
|
|
|
4
4
|
import { a as RevocationCheck } from "../tokens-C9Kwy0Gk.cjs";
|
|
5
5
|
import { RoomTokenVerdictReason } from "./room-token-verification.cjs";
|
|
6
6
|
//#region src/domain/room.d.ts
|
|
7
|
-
export type RoomNoticeVerdictReason = "malformed" | "wrong_room" | "bad_signature" | "wrong_poster" | "content_expired" | RoomTokenVerdictReason;
|
|
7
|
+
export type RoomNoticeVerdictReason = "malformed" | "wrong_room" | "bad_signature" | "wrong_poster" | "content_expired" | "key_epoch_mismatch" | RoomTokenVerdictReason;
|
|
8
8
|
export type RoomNoticeVerdict = {
|
|
9
9
|
ok: true;
|
|
10
10
|
claims: RoomNoticeClaims;
|
|
@@ -45,6 +45,8 @@ export interface CreateRoomNoticeOptions {
|
|
|
45
45
|
content: Uint8Array<ArrayBuffer>;
|
|
46
46
|
refs?: readonly MessageRef[];
|
|
47
47
|
validUntil?: number;
|
|
48
|
+
/** Which room.rekey epoch content is encrypted under (wire-mesh#141), present iff content-type names an encrypted content-type -- see room-notice-claims' own obligation 7 comment in room.cddl. This function does not itself encrypt content: the caller encrypts via group-key.ts's encryptNoticeContent beforehand and passes the resulting ciphertext as content, exactly as it would pass any other opaque bytes. */
|
|
49
|
+
keyEpoch?: number;
|
|
48
50
|
}
|
|
49
51
|
/**
|
|
50
52
|
* 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.
|
package/dist/domain/room.d.mts
CHANGED
|
@@ -4,7 +4,7 @@ import { t as Clock } from "../clock-DiSx-WKM.mjs";
|
|
|
4
4
|
import { a as RevocationCheck } from "../tokens-k172l0Iy.mjs";
|
|
5
5
|
import { RoomTokenVerdictReason } from "./room-token-verification.mjs";
|
|
6
6
|
//#region src/domain/room.d.ts
|
|
7
|
-
export type RoomNoticeVerdictReason = "malformed" | "wrong_room" | "bad_signature" | "wrong_poster" | "content_expired" | RoomTokenVerdictReason;
|
|
7
|
+
export type RoomNoticeVerdictReason = "malformed" | "wrong_room" | "bad_signature" | "wrong_poster" | "content_expired" | "key_epoch_mismatch" | RoomTokenVerdictReason;
|
|
8
8
|
export type RoomNoticeVerdict = {
|
|
9
9
|
ok: true;
|
|
10
10
|
claims: RoomNoticeClaims;
|
|
@@ -45,6 +45,8 @@ export interface CreateRoomNoticeOptions {
|
|
|
45
45
|
content: Uint8Array<ArrayBuffer>;
|
|
46
46
|
refs?: readonly MessageRef[];
|
|
47
47
|
validUntil?: number;
|
|
48
|
+
/** Which room.rekey epoch content is encrypted under (wire-mesh#141), present iff content-type names an encrypted content-type -- see room-notice-claims' own obligation 7 comment in room.cddl. This function does not itself encrypt content: the caller encrypts via group-key.ts's encryptNoticeContent beforehand and passes the resulting ciphertext as content, exactly as it would pass any other opaque bytes. */
|
|
49
|
+
keyEpoch?: number;
|
|
48
50
|
}
|
|
49
51
|
/**
|
|
50
52
|
* 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.
|
package/dist/domain/room.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { roomNoticeClaimsSchema } from "../generated/protocol.mjs";
|
|
2
|
+
import { isEncryptedContentType } from "./group-key.mjs";
|
|
2
3
|
import { verifyRoomToken } from "./room-token-verification.mjs";
|
|
3
4
|
import { cdeDecodeOptions, cdeEncodeOptions, decode, encode } from "cbor2";
|
|
4
5
|
//#region src/domain/room.ts
|
|
@@ -90,6 +91,11 @@ async function verifyRoomNotice(notice, options) {
|
|
|
90
91
|
ok: false,
|
|
91
92
|
reason: "content_expired"
|
|
92
93
|
};
|
|
94
|
+
const keyEpoch = claims["key-epoch"];
|
|
95
|
+
if (isEncryptedContentType(claims["content-type"]) !== (keyEpoch !== void 0)) return {
|
|
96
|
+
ok: false,
|
|
97
|
+
reason: "key_epoch_mismatch"
|
|
98
|
+
};
|
|
93
99
|
const tokenVerdict = await verifyRoomToken(claims.token, {
|
|
94
100
|
identity: options.identity,
|
|
95
101
|
clock: options.clock,
|
|
@@ -129,7 +135,8 @@ async function createRoomNotice(options) {
|
|
|
129
135
|
"content-type": options.contentType,
|
|
130
136
|
content: options.content,
|
|
131
137
|
...options.refs !== void 0 ? { refs: [...options.refs] } : {},
|
|
132
|
-
...options.validUntil !== void 0 ? { "valid-until": options.validUntil } : {}
|
|
138
|
+
...options.validUntil !== void 0 ? { "valid-until": options.validUntil } : {},
|
|
139
|
+
...options.keyEpoch !== void 0 ? { "key-epoch": options.keyEpoch } : {}
|
|
133
140
|
});
|
|
134
141
|
const protectedHeader = protectedHeaderFor(options.identity);
|
|
135
142
|
return [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wire-mesh-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.35.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c",
|
|
6
6
|
"repository": {
|