node-rtc-connection 2.0.4 → 2.0.6
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/index.cjs +1 -0
- package/index.mjs +1 -0
- package/package.json +10 -47
- package/{dist/types → types}/stun/stun-client.d.ts +2 -0
- package/dist/index.cjs +0 -32
- package/dist/index.mjs +0 -43
- package/src/crypto/der.ts +0 -205
- package/src/crypto/x509.ts +0 -146
- package/src/datachannel/RTCDataChannel.ts +0 -388
- package/src/dtls/RTCCertificate.ts +0 -396
- package/src/dtls/cipher.ts +0 -198
- package/src/dtls/connection.ts +0 -974
- package/src/dtls/prf.ts +0 -62
- package/src/dtls/protocol.ts +0 -204
- package/src/foundation/ByteBufferQueue.ts +0 -237
- package/src/foundation/RTCError.ts +0 -276
- package/src/ice/RTCIceCandidate.ts +0 -349
- package/src/ice/ice-agent.ts +0 -609
- package/src/ice/stun-message.ts +0 -260
- package/src/index.ts +0 -72
- package/src/peerconnection/RTCPeerConnection.ts +0 -430
- package/src/sctp/association.ts +0 -523
- package/src/sctp/chunks.ts +0 -350
- package/src/sctp/crc32c.ts +0 -57
- package/src/sctp/datachannel-manager.ts +0 -187
- package/src/sctp/dcep.ts +0 -94
- package/src/sdp/RTCSessionDescription.ts +0 -115
- package/src/sdp/sdp-utils.ts +0 -229
- package/src/stun/stun-client.ts +0 -936
- package/src/transport-stack.ts +0 -165
- /package/{dist/types → types}/crypto/der.d.ts +0 -0
- /package/{dist/types → types}/crypto/x509.d.ts +0 -0
- /package/{dist/types → types}/datachannel/RTCDataChannel.d.ts +0 -0
- /package/{dist/types → types}/dtls/RTCCertificate.d.ts +0 -0
- /package/{dist/types → types}/dtls/cipher.d.ts +0 -0
- /package/{dist/types → types}/dtls/connection.d.ts +0 -0
- /package/{dist/types → types}/dtls/prf.d.ts +0 -0
- /package/{dist/types → types}/dtls/protocol.d.ts +0 -0
- /package/{dist/types → types}/foundation/ByteBufferQueue.d.ts +0 -0
- /package/{dist/types → types}/foundation/RTCError.d.ts +0 -0
- /package/{dist/types → types}/ice/RTCIceCandidate.d.ts +0 -0
- /package/{dist/types → types}/ice/ice-agent.d.ts +0 -0
- /package/{dist/types → types}/ice/stun-message.d.ts +0 -0
- /package/{dist/types → types}/index.d.ts +0 -0
- /package/{dist/types → types}/peerconnection/RTCPeerConnection.d.ts +0 -0
- /package/{dist/types → types}/sctp/association.d.ts +0 -0
- /package/{dist/types → types}/sctp/chunks.d.ts +0 -0
- /package/{dist/types → types}/sctp/crc32c.d.ts +0 -0
- /package/{dist/types → types}/sctp/datachannel-manager.d.ts +0 -0
- /package/{dist/types → types}/sctp/dcep.d.ts +0 -0
- /package/{dist/types → types}/sdp/RTCSessionDescription.d.ts +0 -0
- /package/{dist/types → types}/sdp/sdp-utils.d.ts +0 -0
- /package/{dist/types → types}/transport-stack.d.ts +0 -0
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file RTCSessionDescription.ts
|
|
3
|
-
* @description Session Description Protocol (SDP) representation
|
|
4
|
-
* @module sdp/RTCSessionDescription
|
|
5
|
-
*
|
|
6
|
-
* Implements the W3C RTCSessionDescription interface
|
|
7
|
-
* (https://www.w3.org/TR/webrtc/#rtcsessiondescription-class).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
'use strict';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* RTCSdpType - Types of session descriptions
|
|
14
|
-
* @readonly
|
|
15
|
-
* @enum {string}
|
|
16
|
-
*/
|
|
17
|
-
export const RTCSdpType: Readonly<Record<string, string>> = Object.freeze({
|
|
18
|
-
OFFER: 'offer',
|
|
19
|
-
PRANSWER: 'pranswer',
|
|
20
|
-
ANSWER: 'answer',
|
|
21
|
-
ROLLBACK: 'rollback'
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Session description init object.
|
|
26
|
-
*/
|
|
27
|
-
export interface RTCSessionDescriptionInit {
|
|
28
|
-
type?: string;
|
|
29
|
-
sdp?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* JSON representation of an RTCSessionDescription.
|
|
34
|
-
*/
|
|
35
|
-
export interface RTCSessionDescriptionJSON {
|
|
36
|
-
type: string | null;
|
|
37
|
-
sdp: string | null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @class RTCSessionDescription
|
|
42
|
-
* @description Represents a WebRTC session description (offer/answer)
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* const desc = new RTCSessionDescription({
|
|
46
|
-
* type: 'offer',
|
|
47
|
-
* sdp: 'v=0\r\no=- 123456 2 IN IP4 127.0.0.1\r\n...'
|
|
48
|
-
* });
|
|
49
|
-
*/
|
|
50
|
-
export class RTCSessionDescription {
|
|
51
|
-
#type: string | null;
|
|
52
|
-
#sdp: string | null;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Create an RTCSessionDescription instance.
|
|
56
|
-
* @param {Object} [init] - Session description init
|
|
57
|
-
* @param {string} [init.type] - SDP type (offer/answer/pranswer/rollback)
|
|
58
|
-
* @param {string} [init.sdp] - SDP string
|
|
59
|
-
*/
|
|
60
|
-
constructor(init: RTCSessionDescriptionInit = {}) {
|
|
61
|
-
this.#type = init.type || null;
|
|
62
|
-
this.#sdp = init.sdp || null;
|
|
63
|
-
|
|
64
|
-
// Validate type if provided
|
|
65
|
-
if (this.#type && !Object.values(RTCSdpType).includes(this.#type)) {
|
|
66
|
-
throw new TypeError(`Invalid SDP type: ${this.#type}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Get the SDP type.
|
|
72
|
-
* @returns {string|null} SDP type
|
|
73
|
-
*/
|
|
74
|
-
get type(): string | null {
|
|
75
|
-
return this.#type;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Set the SDP type.
|
|
80
|
-
* @param {string} value - SDP type
|
|
81
|
-
*/
|
|
82
|
-
set type(value: string | null) {
|
|
83
|
-
if (value && !Object.values(RTCSdpType).includes(value)) {
|
|
84
|
-
throw new TypeError(`Invalid SDP type: ${value}`);
|
|
85
|
-
}
|
|
86
|
-
this.#type = value;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Get the SDP string.
|
|
91
|
-
* @returns {string|null} SDP string
|
|
92
|
-
*/
|
|
93
|
-
get sdp(): string | null {
|
|
94
|
-
return this.#sdp;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Set the SDP string.
|
|
99
|
-
* @param {string} value - SDP string
|
|
100
|
-
*/
|
|
101
|
-
set sdp(value: string | null) {
|
|
102
|
-
this.#sdp = value;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Convert to JSON representation.
|
|
107
|
-
* @returns {Object} JSON representation
|
|
108
|
-
*/
|
|
109
|
-
toJSON(): RTCSessionDescriptionJSON {
|
|
110
|
-
return {
|
|
111
|
-
type: this.#type,
|
|
112
|
-
sdp: this.#sdp
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
}
|
package/src/sdp/sdp-utils.ts
DELETED
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file sdp-utils.ts
|
|
3
|
-
* @description SDP generation/parsing for a WebRTC data-channel m-section.
|
|
4
|
-
* @module sdp/sdp-utils
|
|
5
|
-
*
|
|
6
|
-
* Emits the standard application m-line with the SCTP-over-DTLS profile and
|
|
7
|
-
* conveys transport addresses through ICE candidates (not the c=/m= lines, per
|
|
8
|
-
* the WebRTC JSEP/SDP rules). This is what browsers expect.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
'use strict';
|
|
12
|
-
|
|
13
|
-
import * as crypto from 'crypto';
|
|
14
|
-
|
|
15
|
-
/** ICE credentials. */
|
|
16
|
-
export interface IceCredentials {
|
|
17
|
-
usernameFragment: string;
|
|
18
|
-
password: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** DTLS certificate fingerprint. */
|
|
22
|
-
export interface Fingerprint {
|
|
23
|
-
algorithm: string;
|
|
24
|
-
value: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** A candidate descriptor as accepted by {@link buildSdp}. */
|
|
28
|
-
export interface CandidateInput {
|
|
29
|
-
sdp?: string;
|
|
30
|
-
candidate?: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Options accepted by {@link buildSdp}. */
|
|
34
|
-
export interface BuildSdpOptions {
|
|
35
|
-
kind?: 'offer' | 'answer';
|
|
36
|
-
iceUfrag: string;
|
|
37
|
-
icePwd: string;
|
|
38
|
-
fingerprint?: Fingerprint;
|
|
39
|
-
setup?: string;
|
|
40
|
-
candidates?: CandidateInput[];
|
|
41
|
-
sctpPort?: number;
|
|
42
|
-
maxMessageSize?: number;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Options accepted by {@link generateOffer} / {@link generateAnswer}. */
|
|
46
|
-
export interface GenerateOptions extends BuildSdpOptions {}
|
|
47
|
-
|
|
48
|
-
/** Parsed ICE parameters. */
|
|
49
|
-
export interface IceParameters {
|
|
50
|
-
usernameFragment: string | null;
|
|
51
|
-
password: string | null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** Parsed DTLS parameters. */
|
|
55
|
-
export interface DtlsParameters {
|
|
56
|
-
role: string;
|
|
57
|
-
fingerprints: Fingerprint[];
|
|
58
|
-
setup?: string;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Parsed SCTP parameters. */
|
|
62
|
-
export interface SctpParameters {
|
|
63
|
-
port: number;
|
|
64
|
-
maxMessageSize: number;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** A parsed ICE candidate. */
|
|
68
|
-
export interface ParsedCandidate {
|
|
69
|
-
candidate: string;
|
|
70
|
-
foundation: string;
|
|
71
|
-
component: number;
|
|
72
|
-
protocol: string;
|
|
73
|
-
priority: number;
|
|
74
|
-
address: string;
|
|
75
|
-
port: number;
|
|
76
|
-
type: string;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Generate ICE credentials (ufrag >= 4 chars, pwd >= 22 chars per RFC 8445).
|
|
81
|
-
* @returns {{usernameFragment:string, password:string}}
|
|
82
|
-
*/
|
|
83
|
-
export function generateIceCredentials(): IceCredentials {
|
|
84
|
-
return {
|
|
85
|
-
usernameFragment: crypto.randomBytes(3).toString('base64').replace(/[^a-zA-Z0-9]/g, '').slice(0, 4).padEnd(4, 'x'),
|
|
86
|
-
password: crypto.randomBytes(18).toString('base64').replace(/[^a-zA-Z0-9]/g, '').slice(0, 24).padEnd(24, 'x'),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Build the SDP for a data-channel-only session.
|
|
92
|
-
* @param {Object} o
|
|
93
|
-
* @param {'offer'|'answer'} o.kind
|
|
94
|
-
* @param {string} o.iceUfrag
|
|
95
|
-
* @param {string} o.icePwd
|
|
96
|
-
* @param {{algorithm:string,value:string}} o.fingerprint - DTLS cert fingerprint
|
|
97
|
-
* @param {string} o.setup - 'actpass' | 'active' | 'passive'
|
|
98
|
-
* @param {Array<{sdp?:string,candidate?:string}>} [o.candidates]
|
|
99
|
-
* @param {number} [o.sctpPort=5000]
|
|
100
|
-
* @param {number} [o.maxMessageSize=262144]
|
|
101
|
-
* @returns {string}
|
|
102
|
-
*/
|
|
103
|
-
export function buildSdp(o: BuildSdpOptions): string {
|
|
104
|
-
const {
|
|
105
|
-
iceUfrag,
|
|
106
|
-
icePwd,
|
|
107
|
-
fingerprint,
|
|
108
|
-
setup = 'actpass',
|
|
109
|
-
candidates = [],
|
|
110
|
-
sctpPort = 5000,
|
|
111
|
-
maxMessageSize = 262144,
|
|
112
|
-
} = o;
|
|
113
|
-
|
|
114
|
-
const lines: string[] = [];
|
|
115
|
-
lines.push('v=0');
|
|
116
|
-
// Session id is arbitrary; use random to avoid Date.now noise.
|
|
117
|
-
const sessId = crypto.randomBytes(4).readUInt32BE(0);
|
|
118
|
-
lines.push(`o=- ${sessId} 2 IN IP4 127.0.0.1`);
|
|
119
|
-
lines.push('s=-');
|
|
120
|
-
lines.push('t=0 0');
|
|
121
|
-
lines.push('a=group:BUNDLE 0');
|
|
122
|
-
lines.push('a=msid-semantic: WMS');
|
|
123
|
-
|
|
124
|
-
// The port in the m-line is the standard placeholder 9; addresses come from
|
|
125
|
-
// ICE candidates. Proto reflects the real transport: DTLS/SCTP.
|
|
126
|
-
lines.push('m=application 9 UDP/DTLS/SCTP webrtc-datachannel');
|
|
127
|
-
lines.push('c=IN IP4 0.0.0.0');
|
|
128
|
-
lines.push('a=ice-ufrag:' + iceUfrag);
|
|
129
|
-
lines.push('a=ice-pwd:' + icePwd);
|
|
130
|
-
lines.push('a=ice-options:trickle');
|
|
131
|
-
if (fingerprint) {
|
|
132
|
-
lines.push(`a=fingerprint:${fingerprint.algorithm} ${fingerprint.value}`);
|
|
133
|
-
}
|
|
134
|
-
lines.push(`a=setup:${setup}`);
|
|
135
|
-
lines.push('a=mid:0');
|
|
136
|
-
lines.push('a=sctp-port:' + sctpPort);
|
|
137
|
-
lines.push('a=max-message-size:' + maxMessageSize);
|
|
138
|
-
|
|
139
|
-
for (const c of candidates) {
|
|
140
|
-
const cstr = c.sdp || c.candidate;
|
|
141
|
-
if (cstr) lines.push('a=' + (cstr.startsWith('candidate:') ? cstr : 'candidate:' + cstr));
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return lines.join('\r\n') + '\r\n';
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function generateOffer(opts: GenerateOptions): string {
|
|
148
|
-
return buildSdp({ ...opts, kind: 'offer', setup: opts.setup || 'actpass' });
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export function generateAnswer(opts: GenerateOptions): string {
|
|
152
|
-
return buildSdp({ ...opts, kind: 'answer', setup: opts.setup || 'active' });
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/** Parse ICE ufrag/pwd. */
|
|
156
|
-
export function parseIceParameters(sdp: string): IceParameters {
|
|
157
|
-
const params: IceParameters = { usernameFragment: null, password: null };
|
|
158
|
-
for (const line of sdp.split(/\r?\n/)) {
|
|
159
|
-
if (line.startsWith('a=ice-ufrag:')) params.usernameFragment = line.slice(12).trim();
|
|
160
|
-
else if (line.startsWith('a=ice-pwd:')) params.password = line.slice(10).trim();
|
|
161
|
-
}
|
|
162
|
-
return params;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/** Parse DTLS setup role + fingerprints. */
|
|
166
|
-
export function parseDtlsParameters(sdp: string): DtlsParameters {
|
|
167
|
-
const params: DtlsParameters = { role: 'auto', fingerprints: [] };
|
|
168
|
-
for (const line of sdp.split(/\r?\n/)) {
|
|
169
|
-
if (line.startsWith('a=setup:')) {
|
|
170
|
-
const setup = line.slice(8).trim();
|
|
171
|
-
if (setup === 'active') params.role = 'client';
|
|
172
|
-
else if (setup === 'passive') params.role = 'server';
|
|
173
|
-
else params.role = 'actpass';
|
|
174
|
-
params.setup = setup;
|
|
175
|
-
} else if (line.startsWith('a=fingerprint:')) {
|
|
176
|
-
const parts = line.slice(14).trim().split(/\s+/);
|
|
177
|
-
if (parts.length === 2) {
|
|
178
|
-
params.fingerprints.push({ algorithm: parts[0]!.toLowerCase(), value: parts[1]!.toUpperCase() });
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return params;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/** Parse SCTP port / max message size. */
|
|
186
|
-
export function parseSctpParameters(sdp: string): SctpParameters {
|
|
187
|
-
const params: SctpParameters = { port: 5000, maxMessageSize: 262144 };
|
|
188
|
-
for (const line of sdp.split(/\r?\n/)) {
|
|
189
|
-
if (line.startsWith('a=sctp-port:')) params.port = parseInt(line.slice(12), 10);
|
|
190
|
-
else if (line.startsWith('a=max-message-size:')) params.maxMessageSize = parseInt(line.slice(19), 10);
|
|
191
|
-
}
|
|
192
|
-
return params;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Parse ICE candidate lines into structured objects.
|
|
197
|
-
* @param {string} sdp
|
|
198
|
-
* @returns {Array<{candidate:string,foundation:string,component:number,protocol:string,priority:number,address:string,port:number,type:string}>}
|
|
199
|
-
*/
|
|
200
|
-
export function parseCandidates(sdp: string): ParsedCandidate[] {
|
|
201
|
-
const out: ParsedCandidate[] = [];
|
|
202
|
-
for (const line of sdp.split(/\r?\n/)) {
|
|
203
|
-
if (!line.startsWith('a=candidate:')) continue;
|
|
204
|
-
const c = parseCandidateLine(line.slice(2));
|
|
205
|
-
if (c) out.push(c);
|
|
206
|
-
}
|
|
207
|
-
return out;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Parse a single "candidate:..." string.
|
|
212
|
-
* @param {string} str
|
|
213
|
-
*/
|
|
214
|
-
export function parseCandidateLine(str: string): ParsedCandidate | null {
|
|
215
|
-
// candidate:<foundation> <component> <protocol> <priority> <address> <port> typ <type> ...
|
|
216
|
-
const s = str.startsWith('candidate:') ? str.slice('candidate:'.length) : str;
|
|
217
|
-
const t = s.split(/\s+/);
|
|
218
|
-
if (t.length < 8) return null;
|
|
219
|
-
return {
|
|
220
|
-
candidate: str.startsWith('candidate:') ? str : 'candidate:' + str,
|
|
221
|
-
foundation: t[0]!,
|
|
222
|
-
component: parseInt(t[1]!, 10),
|
|
223
|
-
protocol: t[2]!.toLowerCase(),
|
|
224
|
-
priority: parseInt(t[3]!, 10) >>> 0,
|
|
225
|
-
address: t[4]!,
|
|
226
|
-
port: parseInt(t[5]!, 10),
|
|
227
|
-
type: t[7]!,
|
|
228
|
-
};
|
|
229
|
-
}
|