@camstack/server 1.2.582 → 1.2.584

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.
@@ -5373,6 +5373,13 @@ function createCapRouter_localNetwork(getProvider, createRemoteProxy) {
5373
5373
  const p = resolveProvider('local-network', input?.nodeId, () => getProvider(ctx), createRemoteProxy);
5374
5374
  return p.downloadCa();
5375
5375
  }),
5376
+ useStoredUploadedCertificate: trpc_middleware_js_1.adminProcedure
5377
+ .input(zod_1.z.object({ nodeId: zod_1.z.string().optional() }).optional())
5378
+ .output(types_70.localNetworkCapability.methods.useStoredUploadedCertificate.output)
5379
+ .mutation(async ({ input, ctx }) => {
5380
+ const p = resolveProvider('local-network', input?.nodeId, () => getProvider(ctx), createRemoteProxy);
5381
+ return p.useStoredUploadedCertificate();
5382
+ }),
5376
5383
  revertToGeneratedCertificate: trpc_middleware_js_1.adminProcedure
5377
5384
  .input(zod_1.z.object({ nodeId: zod_1.z.string().optional() }).optional())
5378
5385
  .output(types_70.localNetworkCapability.methods.revertToGeneratedCertificate.output)
@@ -245,6 +245,9 @@ async function setupInfra(_configPath, bootstrapConfig) {
245
245
  if (boot.uploadedMissing) {
246
246
  console.warn(`[Phase2c] WARN the uploaded TLS certificate is missing from ${path.join(dataPath, 'tls')} — serving the generated one. Upload it again in Network → Local access.`);
247
247
  }
248
+ if (boot.dormantCaReplaced) {
249
+ console.warn(`[Phase2c] WARN the local CA kept beside the uploaded certificate had no name constraints and was replaced by a constrained one (D873). The previous CA stays on disk until the listener is up. Clients that trusted it must download and trust the new CA again.`);
250
+ }
248
251
  if (boot.ensured !== undefined) {
249
252
  tlsCert = boot.ensured;
250
253
  logTlsCert(boot.ensured);
@@ -277,6 +280,12 @@ function logTlsCert(result) {
277
280
  console.log(`[Phase2c] TLS CERTIFICATE REISSUED — reason=${result.reason}, caRotated=${result.caRotated}`);
278
281
  console.log(`[Phase2c] leaf ${result.previousFingerprintSha256 ?? '(none)'} → ${result.fingerprintSha256}`);
279
282
  console.log(`[Phase2c] valid to ${result.validTo}, names: ${result.sans.join(', ')}`);
283
+ if (result.reason === 'ca-unconstrained') {
284
+ console.log(`[Phase2c] The previous local CA had no name constraints (D873); it is kept on disk until the listener serves the new leaf, then removed.`);
285
+ }
286
+ if (result.droppedNames.length > 0) {
287
+ console.log(`[Phase2c] WARN not certified (outside the local CA's name constraints): ${result.droppedNames.join(', ')}`);
288
+ }
280
289
  console.log(result.caRotated
281
290
  ? `[Phase2c] ACTION REQUIRED: the local CA changed. Install ${result.caCertPath} (SHA-256 ${result.caFingerprintSha256}) on every device that trusted the previous certificate.`
282
291
  : `[Phase2c] Local CA unchanged (${result.caFingerprintSha256}) — devices that trust ${result.caCertPath} keep working.`);
@@ -59,6 +59,11 @@ class PostBootService {
59
59
  // A certificate that changed underneath the operator is an alert, not
60
60
  // a boot line they will never scroll back to (D227).
61
61
  this.emitTlsCertChangedIfReissued(tlsCert);
62
+ // The listener is up on the replacement CA's leaf: the retired unconstrained CA (and
63
+ // its key) kept on disk for the replacement window can go (D873).
64
+ if ((0, system_1.retirePreviousLocalCa)(dataPath)) {
65
+ this.logger.warn('Retired the previous local CA that had no name constraints (D873)');
66
+ }
62
67
  // Re-drive every non-terminal lifecycle job (addon task phases) from its
63
68
  // on-disk checkpoint. Framework tasks are no longer applied by the engine
64
69
  // (single-copy collapse — framework updates ship via applyServerUpdate);
@@ -54,8 +54,15 @@
54
54
  "reach": "closure-postinstall",
55
55
  "markers": {
56
56
  "lib/ice/src/ice.js": ["camstack: relay-only SDP under forceTurn"],
57
- "lib/index.mjs": ["camstack: relay-only SDP under forceTurn", "RTP_HISTORY_SIZE = 4096"],
58
- "lib/webrtc/src/media/rtpSender.js": ["RTP_HISTORY_SIZE = 4096"]
57
+ "lib/index.mjs": [
58
+ "camstack: relay-only SDP under forceTurn",
59
+ "RTP_HISTORY_SIZE = 4096",
60
+ "camstack: D868 — SRTP output arena"
61
+ ],
62
+ "lib/webrtc/src/media/rtpSender.js": ["RTP_HISTORY_SIZE = 4096"],
63
+ "lib/rtp/src/rtp/rtp.js": ["camstack: D868 — SRTP output arena"],
64
+ "lib/rtp/src/srtp/cipher/ctr.js": ["camstack: D868 — header, ciphertext and tag in ONE arena slice"],
65
+ "lib/rtp/src/srtp/cipher/gcm.js": ["camstack: D868 — header, ciphertext and tag in ONE arena slice"]
59
66
  },
60
67
  "declaredBy": [
61
68
  "packages/addon-pipeline",
@@ -25,10 +25,87 @@ index 74cf126..0c5cedf 100644
25
25
  }
26
26
  clearTimeout(timer);
27
27
  diff --git a/node_modules/werift/lib/index.mjs b/node_modules/werift/lib/index.mjs
28
- index 3e8b013..48823e7 100644
28
+ index 3e8b013..f481aa5 100644
29
29
  --- a/node_modules/werift/lib/index.mjs
30
30
  +++ b/node_modules/werift/lib/index.mjs
31
- @@ -7940,7 +7940,10 @@ var Connection = class {
31
+ @@ -4358,6 +4358,21 @@ var timestampOffset = 4;
32
+ var ssrcOffset = 8;
33
+ var csrcOffset = 12;
34
+ var csrcSize = 4;
35
+ +
36
+ +// camstack: D868 — SRTP output arena (see lib/rtp/src/rtp/rtp.js).
37
+ +var CAMSTACK_SRTP_ARENA_BYTES = 262144;
38
+ +var camstackSrtpArena = Buffer.allocUnsafeSlow(0);
39
+ +var camstackSrtpArenaOffset = 0;
40
+ +function camstackSrtpOut(size) {
41
+ + if (size > CAMSTACK_SRTP_ARENA_BYTES >> 2) return Buffer.allocUnsafeSlow(size);
42
+ + if (camstackSrtpArenaOffset + size > camstackSrtpArena.length) {
43
+ + camstackSrtpArena = Buffer.allocUnsafeSlow(CAMSTACK_SRTP_ARENA_BYTES);
44
+ + camstackSrtpArenaOffset = 0;
45
+ + }
46
+ + const out = camstackSrtpArena.subarray(camstackSrtpArenaOffset, camstackSrtpArenaOffset + size);
47
+ + camstackSrtpArenaOffset += size;
48
+ + return out;
49
+ +}
50
+ var RtpHeader = class _RtpHeader {
51
+ version = 2;
52
+ padding = false;
53
+ @@ -4501,8 +4516,8 @@ var RtpHeader = class _RtpHeader {
54
+ }
55
+ return size;
56
+ }
57
+ - serialize(size) {
58
+ - const buf = Buffer.alloc(size);
59
+ + serialize(size, into) {
60
+ + const buf = into ? into.fill(0, 0, size) : Buffer.alloc(size);
61
+ let offset = 0;
62
+ const v_p_x_cc = new BitWriter(8);
63
+ v_p_x_cc.set(2, 0, this.version);
64
+ @@ -4679,7 +4694,9 @@ var CipherAesCtr = class extends CipherAesBase {
65
+ }
66
+ authTagLength = 10;
67
+ encryptRtp(header, payload, rolloverCounter) {
68
+ - const headerBuffer = header.serialize(header.serializeSize);
69
+ + const hdrSize = header.serializeSize;
70
+ + const out = camstackSrtpOut(hdrSize + payload.length + this.authTagLength);
71
+ + const headerBuffer = header.serialize(hdrSize, out.subarray(0, hdrSize));
72
+ const counter = this.generateCounter(
73
+ header.sequenceNumber,
74
+ rolloverCounter,
75
+ @@ -4693,7 +4710,9 @@ var CipherAesCtr = class extends CipherAesBase {
76
+ headerBuffer,
77
+ enc
78
+ );
79
+ - return Buffer.concat([headerBuffer, enc, authTag]);
80
+ + enc.copy(out, hdrSize);
81
+ + authTag.copy(out, hdrSize + enc.length);
82
+ + return out.subarray(0, hdrSize + enc.length + authTag.length);
83
+ }
84
+ decryptRtp(cipherText, rolloverCounter) {
85
+ const header = RtpHeader.deSerialize(cipherText);
86
+ @@ -4800,15 +4819,18 @@ var CipherAesGcm = class extends CipherAesBase {
87
+ super(srtpSessionKey, srtpSessionSalt, srtcpSessionKey, srtcpSessionSalt);
88
+ }
89
+ encryptRtp(header, payload, rolloverCounter) {
90
+ - const hdr = header.serialize(header.serializeSize);
91
+ + const hdrSize = header.serializeSize;
92
+ + const out = camstackSrtpOut(hdrSize + payload.length + this.aeadAuthTagLen);
93
+ + const hdr = header.serialize(hdrSize, out.subarray(0, hdrSize));
94
+ const iv = this.rtpInitializationVector(header, rolloverCounter);
95
+ const cipher = createCipheriv3("aes-128-gcm", this.srtpSessionKey, iv);
96
+ cipher.setAAD(hdr);
97
+ const enc = cipher.update(payload);
98
+ cipher.final();
99
+ const authTag = cipher.getAuthTag();
100
+ - const dst = Buffer.concat([hdr, enc, authTag]);
101
+ - return dst;
102
+ + enc.copy(out, hdrSize);
103
+ + authTag.copy(out, hdrSize + enc.length);
104
+ + return out.subarray(0, hdrSize + enc.length + authTag.length);
105
+ }
106
+ decryptRtp(cipherText, rolloverCounter) {
107
+ const header = RtpHeader.deSerialize(cipherText);
108
+ @@ -7940,7 +7962,10 @@ var Connection = class {
32
109
  this.localUsername
33
110
  );
34
111
  this.pairLocalProtocol(protocol);
@@ -40,7 +117,7 @@ index 3e8b013..48823e7 100644
40
117
  return protocol;
41
118
  } catch (error) {
42
119
  log22("error protocol STUN", error);
43
- @@ -7967,7 +7970,8 @@ var Connection = class {
120
+ @@ -7967,7 +7992,8 @@ var Connection = class {
44
121
  ).catch((error) => {
45
122
  log22("error", error);
46
123
  });
@@ -50,7 +127,7 @@ index 3e8b013..48823e7 100644
50
127
  this.appendLocalCandidate(candidate);
51
128
  }
52
129
  clearTimeout(timer2);
53
- @@ -13565,7 +13569,7 @@ var SenderBandwidthEstimator = class {
130
+ @@ -13565,7 +13591,7 @@ var SenderBandwidthEstimator = class {
54
131
 
55
132
  // src/media/rtpSender.ts
56
133
  var log33 = debug("werift:packages/webrtc/src/media/rtpSender.ts");
@@ -59,6 +136,100 @@ index 3e8b013..48823e7 100644
59
136
  var RTT_ALPHA = 0.85;
60
137
  var RTCRtpSender = class {
61
138
  constructor(trackOrKind) {
139
+ diff --git a/node_modules/werift/lib/rtp/src/rtp/rtp.js b/node_modules/werift/lib/rtp/src/rtp/rtp.js
140
+ index 97b2767..b8ee886 100644
141
+ --- a/node_modules/werift/lib/rtp/src/rtp/rtp.js
142
+ +++ b/node_modules/werift/lib/rtp/src/rtp/rtp.js
143
+ @@ -11,6 +11,26 @@ const timestampOffset = 4;
144
+ const ssrcOffset = 8;
145
+ const csrcOffset = 12;
146
+ const csrcSize = 4;
147
+ +
148
+ +// camstack: D868 — SRTP output arena. Every outgoing RTP packet used to cost a
149
+ +// Buffer.alloc for the header and a Buffer.concat for header + ciphertext + tag.
150
+ +// The packet now lands in a dense slice of a 256 KiB arena that is never reused
151
+ +// (a full arena is left to the GC and lives as long as the datagram in flight).
152
+ +const CAMSTACK_SRTP_ARENA_BYTES = 262144;
153
+ +let camstackSrtpArena = Buffer.allocUnsafeSlow(0);
154
+ +let camstackSrtpArenaOffset = 0;
155
+ +function camstackSrtpOut(size) {
156
+ + if (size > CAMSTACK_SRTP_ARENA_BYTES >> 2)
157
+ + return Buffer.allocUnsafeSlow(size);
158
+ + if (camstackSrtpArenaOffset + size > camstackSrtpArena.length) {
159
+ + camstackSrtpArena = Buffer.allocUnsafeSlow(CAMSTACK_SRTP_ARENA_BYTES);
160
+ + camstackSrtpArenaOffset = 0;
161
+ + }
162
+ + const out = camstackSrtpArena.subarray(camstackSrtpArenaOffset, camstackSrtpArenaOffset + size);
163
+ + camstackSrtpArenaOffset += size;
164
+ + return out;
165
+ +}
166
+ +exports.camstackSrtpOut = camstackSrtpOut;
167
+ /*
168
+ * 0 1 2 3
169
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
170
+ @@ -242,8 +262,9 @@ class RtpHeader {
171
+ }
172
+ return size;
173
+ }
174
+ - serialize(size) {
175
+ - const buf = Buffer.alloc(size);
176
+ + serialize(size, into) {
177
+ + // camstack: D868 — SRTP writes the header straight into its output buffer.
178
+ + const buf = into ? into.fill(0, 0, size) : Buffer.alloc(size);
179
+ let offset = 0;
180
+ const v_p_x_cc = new src_1.BitWriter(8);
181
+ v_p_x_cc.set(2, 0, this.version);
182
+ diff --git a/node_modules/werift/lib/rtp/src/srtp/cipher/ctr.js b/node_modules/werift/lib/rtp/src/srtp/cipher/ctr.js
183
+ index e0c1380..13aa5aa 100644
184
+ --- a/node_modules/werift/lib/rtp/src/srtp/cipher/ctr.js
185
+ +++ b/node_modules/werift/lib/rtp/src/srtp/cipher/ctr.js
186
+ @@ -28,12 +28,17 @@ class CipherAesCtr extends _1.CipherAesBase {
187
+ });
188
+ }
189
+ encryptRtp(header, payload, rolloverCounter) {
190
+ - const headerBuffer = header.serialize(header.serializeSize);
191
+ + // camstack: D868 — header, ciphertext and tag in ONE arena slice (no serialize alloc, no concat).
192
+ + const hdrSize = header.serializeSize;
193
+ + const out = rtp_1.camstackSrtpOut(hdrSize + payload.length + this.authTagLength);
194
+ + const headerBuffer = header.serialize(hdrSize, out.subarray(0, hdrSize));
195
+ const counter = this.generateCounter(header.sequenceNumber, rolloverCounter, header.ssrc, this.srtpSessionSalt);
196
+ const cipher = (0, crypto_1.createCipheriv)("aes-128-ctr", this.srtpSessionKey, counter);
197
+ const enc = cipher.update(payload);
198
+ const authTag = this.generateSrtpAuthTag(rolloverCounter, headerBuffer, enc);
199
+ - return Buffer.concat([headerBuffer, enc, authTag]);
200
+ + enc.copy(out, hdrSize);
201
+ + authTag.copy(out, hdrSize + enc.length);
202
+ + return out.subarray(0, hdrSize + enc.length + authTag.length);
203
+ }
204
+ decryptRtp(cipherText, rolloverCounter) {
205
+ const header = rtp_1.RtpHeader.deSerialize(cipherText);
206
+ diff --git a/node_modules/werift/lib/rtp/src/srtp/cipher/gcm.js b/node_modules/werift/lib/rtp/src/srtp/cipher/gcm.js
207
+ index 8d9d498..4cdd15b 100644
208
+ --- a/node_modules/werift/lib/rtp/src/srtp/cipher/gcm.js
209
+ +++ b/node_modules/werift/lib/rtp/src/srtp/cipher/gcm.js
210
+ @@ -36,15 +36,19 @@ class CipherAesGcm extends _1.CipherAesBase {
211
+ });
212
+ }
213
+ encryptRtp(header, payload, rolloverCounter) {
214
+ - const hdr = header.serialize(header.serializeSize);
215
+ + // camstack: D868 — header, ciphertext and tag in ONE arena slice (no serialize alloc, no concat).
216
+ + const hdrSize = header.serializeSize;
217
+ + const out = rtp_1.camstackSrtpOut(hdrSize + payload.length + this.aeadAuthTagLen);
218
+ + const hdr = header.serialize(hdrSize, out.subarray(0, hdrSize));
219
+ const iv = this.rtpInitializationVector(header, rolloverCounter);
220
+ const cipher = (0, crypto_1.createCipheriv)("aes-128-gcm", this.srtpSessionKey, iv);
221
+ cipher.setAAD(hdr);
222
+ const enc = cipher.update(payload);
223
+ cipher.final();
224
+ const authTag = cipher.getAuthTag();
225
+ - const dst = Buffer.concat([hdr, enc, authTag]);
226
+ - return dst;
227
+ + enc.copy(out, hdrSize);
228
+ + authTag.copy(out, hdrSize + enc.length);
229
+ + return out.subarray(0, hdrSize + enc.length + authTag.length);
230
+ }
231
+ decryptRtp(cipherText, rolloverCounter) {
232
+ const header = rtp_1.RtpHeader.deSerialize(cipherText);
62
233
  diff --git a/node_modules/werift/lib/webrtc/src/media/rtpSender.js b/node_modules/werift/lib/webrtc/src/media/rtpSender.js
63
234
  index bc85968..64a5304 100644
64
235
  --- a/node_modules/werift/lib/webrtc/src/media/rtpSender.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.582",
3
+ "version": "1.2.584",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "files": [
@@ -38,19 +38,19 @@
38
38
  ]
39
39
  },
40
40
  "dependencies": {
41
- "@camstack/addon-admin-ui": "1.2.429",
42
- "@camstack/addon-agent-ui": "1.2.236",
41
+ "@camstack/addon-admin-ui": "1.2.430",
42
+ "@camstack/addon-agent-ui": "1.2.237",
43
43
  "@camstack/addon-auth": "1.2.148",
44
44
  "@camstack/addon-decoder-nodeav": "1.2.123",
45
45
  "@camstack/addon-notifiers": "1.2.135",
46
- "@camstack/addon-pipeline": "1.2.371",
47
- "@camstack/addon-pipeline-orchestrator": "1.2.325",
48
- "@camstack/addon-post-analysis": "1.2.370",
46
+ "@camstack/addon-pipeline": "1.2.373",
47
+ "@camstack/addon-pipeline-orchestrator": "1.2.326",
48
+ "@camstack/addon-post-analysis": "1.2.371",
49
49
  "@camstack/develop": "0.1.11",
50
50
  "@camstack/sdk": "1.2.132",
51
- "@camstack/system": "1.2.438",
52
- "@camstack/types": "1.2.374",
53
- "@camstack/ui-library": "1.2.292",
51
+ "@camstack/system": "1.2.439",
52
+ "@camstack/types": "1.2.375",
53
+ "@camstack/ui-library": "1.2.293",
54
54
  "@fastify/compress": "^9.0.0",
55
55
  "@fastify/cookie": "^11.0.2",
56
56
  "@fastify/cors": "^11.2.0",