@zero-server/sdk 0.9.8 → 0.9.10
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/README.md +1 -1
- package/lib/webrtc/signaling.js +61 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
<p align="center">
|
|
14
14
|
<a href="https://github.com/tonywied17/zero-server/actions"><img src="https://img.shields.io/github/actions/workflow/status/tonywied17/zero-server/ci.yml?branch=main&style=flat-square&logo=githubactions&logoColor=white&label=CI" alt="CI"></a>
|
|
15
|
-
<a href="https://github.com/tonywied17/zero-server/actions"><img src="https://img.shields.io/badge/tests-
|
|
15
|
+
<a href="https://github.com/tonywied17/zero-server/actions"><img src="https://img.shields.io/badge/tests-7781%20passing-brightgreen?style=flat-square&logo=vitest&logoColor=white" alt="tests"></a>
|
|
16
16
|
<a href="https://github.com/tonywied17/zero-server"><img src="https://img.shields.io/badge/coverage-95.85%25-brightgreen?style=flat-square&logo=vitest&logoColor=white" alt="coverage"></a>
|
|
17
17
|
<a href="https://z-server.dev"><img src="https://img.shields.io/badge/docs-z--server.dev-00d8e0?style=flat-square&logo=readthedocs&logoColor=white" alt="docs"></a>
|
|
18
18
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-00d8e0?style=flat-square&logo=opensourceinitiative&logoColor=white" alt="MIT"></a>
|
package/lib/webrtc/signaling.js
CHANGED
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
* offer / answer / ICE traffic. Transport-agnostic — bind to `app.ws()`
|
|
6
6
|
* in production, an `EventEmitter` shim in tests.
|
|
7
7
|
*
|
|
8
|
+
* SDP validation is cross-browser by design: session-level
|
|
9
|
+
* `a=fingerprint` / `a=ice-ufrag` / `a=ice-pwd` lines are accepted as a
|
|
10
|
+
* fallback for media sections that omit their own copy (RFC 8839 §5.4,
|
|
11
|
+
* RFC 8122 §5). This is required for Firefox interop — Firefox emits
|
|
12
|
+
* `a=fingerprint` only at session level.
|
|
13
|
+
*
|
|
8
14
|
* @example | Bind a hub to an `app.ws()` route with all production knobs
|
|
9
15
|
* const app = createApp();
|
|
10
16
|
* const hub = new SignalingHub({
|
|
@@ -83,6 +89,16 @@ function _countCandidatesInSdp(sdp)
|
|
|
83
89
|
* Validate that an SDP has the required RFC 8829 attributes on every media
|
|
84
90
|
* section and uses DTLS-SRTP transport. Returns an error code string, or
|
|
85
91
|
* `null` if the SDP is acceptable.
|
|
92
|
+
*
|
|
93
|
+
* Accepts both RTP/SAVPF audio/video sections (RFC 8829) and SCTP data-channel
|
|
94
|
+
* sections (RFC 8841 m=application ... UDP/DTLS/SCTP). When BUNDLE is in use
|
|
95
|
+
* (every browser since ~2018), only the first m-section is required to carry
|
|
96
|
+
* iceUfrag/icePwd; other bundled sections inherit them via a=group:BUNDLE.
|
|
97
|
+
*
|
|
98
|
+
* Session-level `a=fingerprint`, `a=ice-ufrag`, and `a=ice-pwd` lines are
|
|
99
|
+
* honoured: per RFC 8839 §5.4 and RFC 8122 §5 they apply to every media
|
|
100
|
+
* section that omits its own copy. Firefox emits `a=fingerprint` only at
|
|
101
|
+
* session level, so this fallback is required for cross-browser interop.
|
|
86
102
|
*/
|
|
87
103
|
function _validateSdpStructure(sdp)
|
|
88
104
|
{
|
|
@@ -94,12 +110,49 @@ function _validateSdpStructure(sdp)
|
|
|
94
110
|
return 'INVALID_SDP';
|
|
95
111
|
}
|
|
96
112
|
if (!desc.media || desc.media.length === 0) return 'INVALID_SDP';
|
|
113
|
+
|
|
114
|
+
// BUNDLE: collect bundled mids so per-section ice credentials are optional
|
|
115
|
+
// on every section except the first (the BUNDLE owner).
|
|
116
|
+
// Also collect session-level fingerprint / ice-ufrag / ice-pwd, which per
|
|
117
|
+
// RFC 8839 §5.4 and RFC 8122 §5 apply to every media section that omits
|
|
118
|
+
// its own copy (Firefox emits fingerprint only at session level).
|
|
119
|
+
const bundleMids = new Set();
|
|
120
|
+
let sessFingerprint = null, sessIceUfrag = null, sessIcePwd = null;
|
|
121
|
+
for (const a of desc.attributes || [])
|
|
122
|
+
{
|
|
123
|
+
if (a.key === 'group')
|
|
124
|
+
{
|
|
125
|
+
const parts = String(a.value || '').split(/\s+/);
|
|
126
|
+
if (parts[0] === 'BUNDLE')
|
|
127
|
+
for (let i = 1; i < parts.length; i++) bundleMids.add(parts[i]);
|
|
128
|
+
}
|
|
129
|
+
else if (a.key === 'fingerprint' && a.value) sessFingerprint = a.value;
|
|
130
|
+
else if (a.key === 'ice-ufrag' && a.value) sessIceUfrag = a.value;
|
|
131
|
+
else if (a.key === 'ice-pwd' && a.value) sessIcePwd = a.value;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
let firstBundleMid = null;
|
|
97
135
|
for (const m of desc.media)
|
|
98
136
|
{
|
|
99
|
-
if (typeof m.proto !== 'string'
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
137
|
+
if (typeof m.proto !== 'string') return 'INVALID_SDP';
|
|
138
|
+
|
|
139
|
+
// RTP audio/video (RFC 8829) OR SCTP data channels (RFC 8841).
|
|
140
|
+
const isRtp = /^UDP\/TLS\/RTP\/SAVPF?$/i.test(m.proto);
|
|
141
|
+
const isSctp = /^(UDP|TCP)\/DTLS\/SCTP$/i.test(m.proto);
|
|
142
|
+
if (!isRtp && !isSctp) return 'INVALID_SDP';
|
|
143
|
+
|
|
144
|
+
const fp = m.fingerprint || sessFingerprint;
|
|
145
|
+
const ufrag = m.iceUfrag || sessIceUfrag;
|
|
146
|
+
const pwd = m.icePwd || sessIcePwd;
|
|
147
|
+
|
|
148
|
+
if (!fp) return 'INVALID_SDP';
|
|
149
|
+
|
|
150
|
+
// ice-ufrag / ice-pwd: required on the BUNDLE owner; optional on
|
|
151
|
+
// every other bundled section (inherited per RFC 8843 §9.2).
|
|
152
|
+
const bundled = m.mid && bundleMids.has(m.mid);
|
|
153
|
+
if (bundled && firstBundleMid === null) firstBundleMid = m.mid;
|
|
154
|
+
const isBundleOwner = !bundled || m.mid === firstBundleMid;
|
|
155
|
+
if (isBundleOwner && (!ufrag || !pwd)) return 'INVALID_SDP';
|
|
103
156
|
}
|
|
104
157
|
return null;
|
|
105
158
|
}
|
|
@@ -110,6 +163,10 @@ function _validateSdpStructure(sdp)
|
|
|
110
163
|
* Central WebRTC signaling broker. Owns rooms, attaches peers, validates
|
|
111
164
|
* JSEP traffic, and emits `join` / `leave` / `error` lifecycle events.
|
|
112
165
|
*
|
|
166
|
+
* Interop: SDP validation accepts session-level `a=fingerprint`,
|
|
167
|
+
* `a=ice-ufrag`, and `a=ice-pwd` as a fallback when a media section omits
|
|
168
|
+
* them (RFC 8839 §5.4 / RFC 8122 §5). Required for Firefox.
|
|
169
|
+
*
|
|
113
170
|
* @class
|
|
114
171
|
* @section Signaling
|
|
115
172
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zero-server/sdk",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.10",
|
|
4
4
|
"description": "Zero-dependency backend framework for Node.js - routing, ORM, auth, WebSocket, SSE, gRPC, observability, and 20+ middleware. Distributed as a single SDK and as scoped @zero-server/* packages.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|