livedesk 0.1.458 → 0.1.459

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.
@@ -0,0 +1,503 @@
1
+ import { isIP } from 'node:net';
2
+
3
+ const REQUIRED_PHASES = Object.freeze([
4
+ 'direct',
5
+ 'p2p',
6
+ 'relay',
7
+ 'recover-direct'
8
+ ]);
9
+
10
+ const MAX_PHASE_LATENCY_MS = 15_000;
11
+ const MAX_AGENT_QUEUE_DEPTH = 8;
12
+ const MAX_AGENT_QUEUE_DROPPED_DELTA = 8;
13
+ const MAX_HUB_INGRESS_DROPPED_DELTA = 8;
14
+ const MAX_UDP_INCOMPLETE_DELTA = 2;
15
+ const MAX_HUB_ADDRESS_OBSERVATION_SKEW_MS = 60_000;
16
+
17
+ const SECRET_KEYS = new Set([
18
+ 'authorization',
19
+ 'bearer',
20
+ 'token',
21
+ 'secret',
22
+ 'password',
23
+ 'apikey',
24
+ 'pairtoken'
25
+ ]);
26
+ const SAFE_NETWORK_KEYS = new Set([
27
+ 'clientaddresshash',
28
+ 'hubaddresshash',
29
+ 'clientaddresspublic',
30
+ 'hubaddresspublic',
31
+ 'hubaddressobservedat',
32
+ 'endpointauthenticated',
33
+ 'differentpublicegress',
34
+ 'evidence',
35
+ 'observedat',
36
+ 'udpready'
37
+ ]);
38
+ const IDENTIFIER_KEYS = new Set([
39
+ 'leaseid',
40
+ 'deviceid',
41
+ 'selecteddeviceid',
42
+ 'streamid',
43
+ 'streamcommandid',
44
+ 'commandid',
45
+ 'sessionid',
46
+ 'requestid',
47
+ 'connectionid',
48
+ 'hubconnectionid',
49
+ 'inputeventid',
50
+ 'clientid',
51
+ 'ownerid'
52
+ ]);
53
+ const SECRET_TEXT = /\b(?:authorization|bearer|token|secret|password|api[-_ ]?key|pair[-_ ]?token)(?:\s+|\s*[:=]\s*)\S+/i;
54
+ const IPV4_TEXT = /(^|[^\d])(?:\d{1,3}\.){3}\d{1,3}(?::\d{1,5})?($|[^\d])/;
55
+ const IPV6_CANDIDATE_TEXT = /\[[0-9a-f:.%]+\](?::\d{1,5})?|[0-9a-f:%]*:[0-9a-f:.%:]*/gi;
56
+ const URL_TEXT = /\b[a-z][a-z0-9+.-]*:\/\/[^\s]+/i;
57
+ const HOST_TEXT = /\b(?:localhost|(?:[a-z0-9-]+\.)+[a-z]{2,63})(?::\d{1,5})?\b/i;
58
+ const UUID_TEXT = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i;
59
+
60
+ function normalizedKey(key) {
61
+ return String(key || '').replace(/[-_]/g, '').toLowerCase();
62
+ }
63
+
64
+ function isIdentifierKey(key) {
65
+ return IDENTIFIER_KEYS.has(normalizedKey(key));
66
+ }
67
+
68
+ function isSecretKey(key) {
69
+ const normalized = normalizedKey(key);
70
+ return SECRET_KEYS.has(normalized)
71
+ || normalized.endsWith('token')
72
+ || normalized.endsWith('secret')
73
+ || normalized.endsWith('password')
74
+ || normalized.endsWith('apikey');
75
+ }
76
+
77
+ function isRawNetworkKey(key) {
78
+ const rawKey = String(key || '');
79
+ const normalized = normalizedKey(key);
80
+ if (SAFE_NETWORK_KEYS.has(normalized) || normalized.endsWith('hash')) return false;
81
+ return normalized === 'address'
82
+ || normalized.endsWith('address')
83
+ || normalized === 'endpoint'
84
+ || normalized.endsWith('endpoint')
85
+ || normalized === 'host'
86
+ || normalized.endsWith('host')
87
+ || normalized === 'port'
88
+ || /(?:^|[-_])port$/i.test(rawKey)
89
+ || /[A-Z]Port$/.test(rawKey)
90
+ || normalized === 'url'
91
+ || normalized.endsWith('url')
92
+ || normalized === 'uri'
93
+ || normalized.endsWith('uri')
94
+ || normalized === 'origin'
95
+ || normalized.endsWith('origin');
96
+ }
97
+
98
+ function containsIpv6Text(value) {
99
+ const candidates = String(value || '').match(IPV6_CANDIDATE_TEXT) || [];
100
+ return candidates.some(candidate => {
101
+ const bracketed = candidate.match(/^\[([^\]]+)\](?::\d{1,5})?$/);
102
+ const address = String(bracketed?.[1] || candidate)
103
+ .replace(/%[a-z0-9_.-]+$/i, '')
104
+ .replace(/[.,;]+$/g, '');
105
+ return isIP(address) === 6;
106
+ });
107
+ }
108
+
109
+ function containsRawNetworkText(value) {
110
+ const text = String(value || '');
111
+ return IPV4_TEXT.test(text)
112
+ || containsIpv6Text(text)
113
+ || URL_TEXT.test(text)
114
+ || HOST_TEXT.test(text);
115
+ }
116
+
117
+ function identifierMarker(value) {
118
+ if (value === null || value === undefined || String(value) === '') return '';
119
+ return '[redacted-id]';
120
+ }
121
+
122
+ export function genericTransportPhysicalError(value, fallback = 'transport-diagnostic-error') {
123
+ const text = String(value instanceof Error ? value.message : value || '').trim();
124
+ if (!text
125
+ || containsRawNetworkText(text)
126
+ || SECRET_TEXT.test(text)
127
+ || UUID_TEXT.test(text)) return fallback;
128
+ if (!/^[a-z0-9][a-z0-9 _.,:;()[\]/'"+=-]{0,239}$/i.test(text)) return fallback;
129
+ return text;
130
+ }
131
+
132
+ export function redactTransportPhysicalReport(value, key = '') {
133
+ if (isSecretKey(key)) return '[redacted]';
134
+ if (isIdentifierKey(key)) return identifierMarker(value);
135
+ if (isRawNetworkKey(key)) return '[redacted-network]';
136
+ if (Array.isArray(value)) {
137
+ return value.map(item => redactTransportPhysicalReport(item));
138
+ }
139
+ if (value && typeof value === 'object') {
140
+ return Object.fromEntries(Object.entries(value)
141
+ .filter(([childKey]) => !isSecretKey(childKey))
142
+ .map(([childKey, childValue]) => [
143
+ childKey,
144
+ redactTransportPhysicalReport(childValue, childKey)
145
+ ]));
146
+ }
147
+ if (typeof value === 'string'
148
+ && (containsRawNetworkText(value)
149
+ || SECRET_TEXT.test(value)
150
+ || UUID_TEXT.test(value))) {
151
+ return /error|reason|detail|summary/i.test(key)
152
+ ? '[redacted-sensitive-error]'
153
+ : '[redacted-sensitive]';
154
+ }
155
+ return value;
156
+ }
157
+
158
+ export function findTransportPhysicalReportLeaks(value, path = '$', leaks = []) {
159
+ if (Array.isArray(value)) {
160
+ value.forEach((item, index) => findTransportPhysicalReportLeaks(item, `${path}[${index}]`, leaks));
161
+ return leaks;
162
+ }
163
+ if (value && typeof value === 'object') {
164
+ for (const [key, child] of Object.entries(value)) {
165
+ if (isSecretKey(key)
166
+ || (isRawNetworkKey(key) && child !== '[redacted-network]')) {
167
+ leaks.push(`${path}.${key}`);
168
+ }
169
+ if (isIdentifierKey(key)
170
+ && child !== ''
171
+ && child !== '[redacted-id]') {
172
+ leaks.push(`${path}.${key}`);
173
+ }
174
+ findTransportPhysicalReportLeaks(child, `${path}.${key}`, leaks);
175
+ }
176
+ return leaks;
177
+ }
178
+ if (typeof value === 'string'
179
+ && (containsRawNetworkText(value)
180
+ || SECRET_TEXT.test(value)
181
+ || UUID_TEXT.test(value))) {
182
+ leaks.push(path);
183
+ }
184
+ return leaks;
185
+ }
186
+
187
+ function optionalFinite(value) {
188
+ if (value === null || value === undefined || value === '') return null;
189
+ const parsed = Number(value);
190
+ return Number.isFinite(parsed) ? parsed : null;
191
+ }
192
+
193
+ function phaseFrame(snapshot, phase) {
194
+ return Array.isArray(snapshot?.frames)
195
+ ? snapshot.frames.find(frame => frame?.phase === phase && frame?.accepted === true)
196
+ : null;
197
+ }
198
+
199
+ function expectedPathForPhase(phase) {
200
+ if (phase === 'p2p') return 'p2p';
201
+ if (phase === 'relay') return 'relay';
202
+ return 'direct';
203
+ }
204
+
205
+ export function hubObservedTransport(frame) {
206
+ const transport = String(frame?.transport || '').trim().toLowerCase();
207
+ if (transport === 'udp-p2p') return { path: 'p2p', label: 'udp-p2p' };
208
+ if (transport === 'relay-binary') return { path: 'relay', label: 'relay-binary' };
209
+ if (transport === 'binary' || transport === 'tcp-binary') {
210
+ return { path: 'direct', label: 'direct-tcp' };
211
+ }
212
+ if (transport === 'ws-binary') return { path: 'direct', label: 'direct-ws' };
213
+ return { path: '', label: 'unknown' };
214
+ }
215
+
216
+ export function isTransportPhysicalPhaseEvidence(frame, phase) {
217
+ const expectedPath = expectedPathForPhase(phase);
218
+ const observed = hubObservedTransport(frame);
219
+ const phaseLatencyMs = optionalFinite(frame?.phaseLatencyMs);
220
+ return frame?.accepted === true
221
+ && frame?.phase === phase
222
+ && frame?.actualPath === expectedPath
223
+ && observed.path === expectedPath
224
+ && frame?.isKeyFrame === true
225
+ && frame?.annexB === true
226
+ && frame?.hasIdr === true
227
+ && frame?.hasSps === true
228
+ && frame?.hasPps === true
229
+ && frame?.nalOrderValid === true
230
+ && optionalFinite(frame?.byteLength) > 0
231
+ && phaseLatencyMs !== null
232
+ && phaseLatencyMs >= 0
233
+ && phaseLatencyMs <= MAX_PHASE_LATENCY_MS;
234
+ }
235
+
236
+ function cumulativeDelta(values) {
237
+ if (!Array.isArray(values) || values.length < 2) {
238
+ return { valid: false, delta: null };
239
+ }
240
+ const normalized = values.map(optionalFinite);
241
+ const valid = normalized.every(value => value !== null && value >= 0)
242
+ && normalized.every((value, index) => index === 0 || value >= normalized[index - 1]);
243
+ return {
244
+ valid,
245
+ delta: valid ? normalized.at(-1) - normalized[0] : null
246
+ };
247
+ }
248
+
249
+ function scopedCounterDelta(baselines, samples) {
250
+ const scopes = new Map();
251
+ for (const baseline of baselines || []) {
252
+ const scope = String(baseline?.scope || '');
253
+ const value = optionalFinite(baseline?.value);
254
+ if (!scope || value === null || value < 0 || scopes.has(scope)) {
255
+ return { valid: false, delta: null };
256
+ }
257
+ scopes.set(scope, { initial: value, last: value });
258
+ }
259
+ let total = 0;
260
+ for (const sample of samples || []) {
261
+ const scope = String(sample?.scope || '');
262
+ const value = optionalFinite(sample?.value);
263
+ if (!scope || value === null || value < 0) {
264
+ return { valid: false, delta: null };
265
+ }
266
+ const state = scopes.get(scope) || { initial: 0, last: 0 };
267
+ if (value < state.last) {
268
+ return { valid: false, delta: null };
269
+ }
270
+ state.last = value;
271
+ scopes.set(scope, state);
272
+ }
273
+ for (const state of scopes.values()) {
274
+ total += state.last - state.initial;
275
+ }
276
+ return { valid: true, delta: total };
277
+ }
278
+
279
+ function timestampWithin(value, reference, maximumSkewMs) {
280
+ const observedAt = Date.parse(String(value || ''));
281
+ const referenceAt = Date.parse(String(reference || ''));
282
+ return Number.isFinite(observedAt)
283
+ && Number.isFinite(referenceAt)
284
+ && Math.abs(observedAt - referenceAt) <= maximumSkewMs;
285
+ }
286
+
287
+ export function classifyTransportPhysicalSnapshot(snapshot) {
288
+ const checks = [];
289
+ const add = (id, ok, detail) => checks.push({ id, ok: ok === true, detail });
290
+ const owner = snapshot?.owner || {};
291
+
292
+ add(
293
+ 'same-current-owner',
294
+ !!owner.streamId
295
+ && !!owner.streamCommandId
296
+ && Number(owner.captureGeneration || 0) > 0
297
+ && Number(owner.monitorIndex) >= 0,
298
+ 'One immutable stream, command, generation, and monitor must own the complete run.');
299
+
300
+ const observedFrames = REQUIRED_PHASES.map(phase => phaseFrame(snapshot, phase));
301
+ for (let index = 0; index < REQUIRED_PHASES.length; index += 1) {
302
+ const phase = REQUIRED_PHASES[index];
303
+ const frame = observedFrames[index];
304
+ const expectedPath = expectedPathForPhase(phase);
305
+ const observed = hubObservedTransport(frame);
306
+ add(
307
+ `received-h264-${phase}`,
308
+ !!frame
309
+ && frame.actualPath === expectedPath
310
+ && frame.isKeyFrame === true
311
+ && frame.annexB === true
312
+ && frame.hasIdr === true
313
+ && frame.hasSps === true
314
+ && frame.hasPps === true
315
+ && frame.nalOrderValid === true
316
+ && optionalFinite(frame.byteLength) > 0,
317
+ `A received Annex-B H.264 SPS -> PPS -> IDR access unit must prove ${phase}.`);
318
+ add(
319
+ `hub-observed-transport-${phase}`,
320
+ !!frame && observed.path === expectedPath,
321
+ `Hub ingress must observe ${phase} as ${observed.label}.`);
322
+ const phaseLatencyMs = optionalFinite(frame?.phaseLatencyMs);
323
+ add(
324
+ `phase-latency-${phase}`,
325
+ phaseLatencyMs !== null
326
+ && phaseLatencyMs >= 0
327
+ && phaseLatencyMs <= MAX_PHASE_LATENCY_MS,
328
+ `${phaseLatencyMs === null ? 'unknown' : Math.round(phaseLatencyMs)}ms/15000ms`);
329
+ }
330
+
331
+ const receivedTimes = observedFrames.map(frame => Date.parse(frame?.receivedAt || ''));
332
+ add(
333
+ 'ordered-path-transition',
334
+ observedFrames.every(Boolean)
335
+ && receivedTimes.every(Number.isFinite)
336
+ && receivedTimes.every((time, index) => index === 0 || time > receivedTimes[index - 1]),
337
+ 'Frames must arrive in strict Direct, UDP P2P, encrypted relay, Direct order.');
338
+
339
+ const frameSequences = observedFrames.map(frame => optionalFinite(frame?.frameSeq));
340
+ add(
341
+ 'strict-frame-sequence',
342
+ frameSequences.every(value => Number.isSafeInteger(value) && value > 0)
343
+ && frameSequences.every((value, index) => index === 0 || value > frameSequences[index - 1]),
344
+ frameSequences.map(value => value ?? '?').join(' -> '));
345
+
346
+ const switchCounts = observedFrames.map(frame => optionalFinite(frame?.switchCount));
347
+ add(
348
+ 'transport-switch-count',
349
+ switchCounts.every(value => Number.isSafeInteger(value) && value >= 0)
350
+ && switchCounts.every((value, index) => index === 0 || value > switchCounts[index - 1]),
351
+ switchCounts.map(value => value ?? '?').join(' -> '));
352
+
353
+ const network = snapshot?.network || {};
354
+ add(
355
+ 'distinct-public-ipv4-egress',
356
+ network.evidence === 'authenticated-udp-endpoint-rendezvous-observed'
357
+ && network.endpointAuthenticated === true
358
+ && network.clientAddressPublic === true
359
+ && network.hubAddressPublic === true
360
+ && network.differentPublicEgress === true
361
+ && network.hubEndpointSource === 'trusted-rendezvous-observation',
362
+ 'Authenticated UDP and trusted-rendezvous-observed distinct public IPv4 egress values are required; this does not prove distinct NAT devices.');
363
+ add(
364
+ 'fresh-hub-public-ipv4-observation',
365
+ timestampWithin(
366
+ network.hubAddressObservedAt,
367
+ snapshot?.startedAt,
368
+ MAX_HUB_ADDRESS_OBSERVATION_SKEW_MS),
369
+ 'The Hub public IPv4 value must be freshly observed within 60 seconds of diagnostic start.');
370
+ add(
371
+ 'fresh-client-udp-observation',
372
+ timestampWithin(
373
+ network.observedAt,
374
+ snapshot?.startedAt,
375
+ MAX_HUB_ADDRESS_OBSERVATION_SKEW_MS),
376
+ 'The authenticated Client UDP endpoint must be observed within 60 seconds of diagnostic start.');
377
+
378
+ const cleanup = Array.isArray(snapshot?.cleanup) ? snapshot.cleanup : [];
379
+ add(
380
+ 'lease-cleaned',
381
+ snapshot?.state === 'completed'
382
+ && cleanup.some(entry => entry?.state === 'agent-released'),
383
+ 'The exact-owner diagnostic lease must be released by the Agent.');
384
+
385
+ const baseline = snapshot?.baseline || {};
386
+ const agentTelemetryAvailable = baseline.agentQueueTelemetryAvailable === true
387
+ && optionalFinite(baseline.agentQueueDropped) !== null
388
+ && observedFrames.every(frame =>
389
+ frame?.agentQueueTelemetryAvailable === true
390
+ && optionalFinite(frame.agentQueueDepth) !== null
391
+ && optionalFinite(frame.agentQueueDropped) !== null);
392
+ const hubTelemetryAvailable = baseline.hubIngressTelemetryAvailable === true
393
+ && optionalFinite(baseline.hubIngressDropped) !== null
394
+ && !!baseline.hubIngressCounterEpochHash
395
+ && !!baseline.udpCounterEpochHash
396
+ && observedFrames.every(frame =>
397
+ frame?.hubIngressTelemetryAvailable === true
398
+ && optionalFinite(frame.hubIngressDropped) !== null
399
+ && !!frame.hubIngressCounterEpochHash);
400
+ const p2pFrame = observedFrames[REQUIRED_PHASES.indexOf('p2p')];
401
+ const udpTelemetryAvailable = baseline.udpTelemetryAvailable === true
402
+ && optionalFinite(baseline.udpIncompleteFrames) !== null
403
+ && p2pFrame?.udpTelemetryAvailable === true
404
+ && optionalFinite(p2pFrame?.udpIncompleteFrames) !== null
405
+ && p2pFrame?.hubIngressCounterEpochHash === baseline.udpCounterEpochHash;
406
+ add(
407
+ 'agent-queue-telemetry',
408
+ agentTelemetryAvailable,
409
+ agentTelemetryAvailable ? 'baseline and all four phases' : 'unknown or incomplete');
410
+ add(
411
+ 'hub-ingress-telemetry',
412
+ hubTelemetryAvailable,
413
+ hubTelemetryAvailable ? 'baseline and all four phases' : 'unknown or incomplete');
414
+ add(
415
+ 'udp-reassembly-telemetry',
416
+ udpTelemetryAvailable,
417
+ udpTelemetryAvailable ? 'baseline and P2P phase' : 'unknown or incomplete');
418
+
419
+ const agentDropped = cumulativeDelta([
420
+ baseline.agentQueueDropped,
421
+ ...observedFrames.map(frame => frame?.agentQueueDropped)
422
+ ]);
423
+ const hubDropped = scopedCounterDelta([
424
+ {
425
+ scope: baseline.hubIngressCounterEpochHash,
426
+ value: baseline.hubIngressDropped
427
+ },
428
+ {
429
+ scope: baseline.udpCounterEpochHash,
430
+ value: baseline.udpIncompleteFrames
431
+ }
432
+ ], observedFrames.map(frame => ({
433
+ scope: frame?.hubIngressCounterEpochHash,
434
+ value: frame?.hubIngressDropped
435
+ })));
436
+ const udpIncomplete = cumulativeDelta([
437
+ baseline.udpIncompleteFrames,
438
+ p2pFrame?.udpIncompleteFrames
439
+ ]);
440
+ const maxAgentQueueDepth = agentTelemetryAvailable
441
+ ? Math.max(...observedFrames.map(frame => Number(frame.agentQueueDepth)))
442
+ : null;
443
+ const boundedQueues = agentTelemetryAvailable
444
+ && hubTelemetryAvailable
445
+ && udpTelemetryAvailable
446
+ && agentDropped.valid
447
+ && hubDropped.valid
448
+ && udpIncomplete.valid
449
+ && maxAgentQueueDepth <= MAX_AGENT_QUEUE_DEPTH
450
+ && agentDropped.delta <= MAX_AGENT_QUEUE_DROPPED_DELTA
451
+ && hubDropped.delta <= MAX_HUB_INGRESS_DROPPED_DELTA
452
+ && udpIncomplete.delta <= MAX_UDP_INCOMPLETE_DELTA;
453
+ add(
454
+ 'bounded-frame-queues',
455
+ boundedQueues,
456
+ `queueDepth=${maxAgentQueueDepth ?? 'unknown'}, `
457
+ + `agentDroppedDelta=${agentDropped.delta ?? 'unknown'}, `
458
+ + `hubDroppedDelta=${hubDropped.delta ?? 'unknown'}, `
459
+ + `udpIncompleteDelta=${udpIncomplete.delta ?? 'unknown'}`);
460
+
461
+ const failed = checks.filter(check => !check.ok);
462
+ const phaseLatencies = observedFrames.map(frame => optionalFinite(frame?.phaseLatencyMs));
463
+ return {
464
+ status: failed.length === 0 ? 'passed' : 'blocked',
465
+ summary: failed.length === 0
466
+ ? 'Direct, UDP P2P, encrypted relay, and Direct recovery were proven by independent received H.264 access units.'
467
+ : `Physical transport proof is incomplete (${failed.map(check => check.id).join(', ')}).`,
468
+ checks,
469
+ metrics: {
470
+ maxPhaseLatencyMs: phaseLatencies.every(value => value !== null)
471
+ ? Math.max(...phaseLatencies)
472
+ : null,
473
+ maxAgentQueueDepth,
474
+ agentQueueDroppedDelta: agentDropped.delta,
475
+ hubIngressDroppedDelta: hubDropped.delta,
476
+ udpIncompleteFramesDelta: udpIncomplete.delta,
477
+ observedTransports: observedFrames.map(frame => hubObservedTransport(frame).label)
478
+ }
479
+ };
480
+ }
481
+
482
+ export function buildTransportPhysicalReport(snapshot, context = {}) {
483
+ const classified = classifyTransportPhysicalSnapshot(snapshot);
484
+ const report = redactTransportPhysicalReport({
485
+ schema: 'livedesk.transport-physical.v1',
486
+ generatedAt: new Date().toISOString(),
487
+ hubUrl: context.hubUrl,
488
+ selectedDeviceId: context.deviceId,
489
+ result: classified,
490
+ transport: snapshot
491
+ });
492
+ const leaks = findTransportPhysicalReportLeaks(report);
493
+ if (leaks.length > 0) {
494
+ throw new Error(`transport-physical-report-redaction-failed:${leaks.join(',')}`);
495
+ }
496
+ return report;
497
+ }
498
+
499
+ export {
500
+ MAX_HUB_ADDRESS_OBSERVATION_SKEW_MS,
501
+ MAX_PHASE_LATENCY_MS,
502
+ REQUIRED_PHASES
503
+ };