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.
Files changed (53) hide show
  1. package/index.cjs +1 -0
  2. package/index.mjs +1 -0
  3. package/package.json +10 -47
  4. package/{dist/types → types}/stun/stun-client.d.ts +2 -0
  5. package/dist/index.cjs +0 -32
  6. package/dist/index.mjs +0 -43
  7. package/src/crypto/der.ts +0 -205
  8. package/src/crypto/x509.ts +0 -146
  9. package/src/datachannel/RTCDataChannel.ts +0 -388
  10. package/src/dtls/RTCCertificate.ts +0 -396
  11. package/src/dtls/cipher.ts +0 -198
  12. package/src/dtls/connection.ts +0 -974
  13. package/src/dtls/prf.ts +0 -62
  14. package/src/dtls/protocol.ts +0 -204
  15. package/src/foundation/ByteBufferQueue.ts +0 -237
  16. package/src/foundation/RTCError.ts +0 -276
  17. package/src/ice/RTCIceCandidate.ts +0 -349
  18. package/src/ice/ice-agent.ts +0 -609
  19. package/src/ice/stun-message.ts +0 -260
  20. package/src/index.ts +0 -72
  21. package/src/peerconnection/RTCPeerConnection.ts +0 -430
  22. package/src/sctp/association.ts +0 -523
  23. package/src/sctp/chunks.ts +0 -350
  24. package/src/sctp/crc32c.ts +0 -57
  25. package/src/sctp/datachannel-manager.ts +0 -187
  26. package/src/sctp/dcep.ts +0 -94
  27. package/src/sdp/RTCSessionDescription.ts +0 -115
  28. package/src/sdp/sdp-utils.ts +0 -229
  29. package/src/stun/stun-client.ts +0 -936
  30. package/src/transport-stack.ts +0 -165
  31. /package/{dist/types → types}/crypto/der.d.ts +0 -0
  32. /package/{dist/types → types}/crypto/x509.d.ts +0 -0
  33. /package/{dist/types → types}/datachannel/RTCDataChannel.d.ts +0 -0
  34. /package/{dist/types → types}/dtls/RTCCertificate.d.ts +0 -0
  35. /package/{dist/types → types}/dtls/cipher.d.ts +0 -0
  36. /package/{dist/types → types}/dtls/connection.d.ts +0 -0
  37. /package/{dist/types → types}/dtls/prf.d.ts +0 -0
  38. /package/{dist/types → types}/dtls/protocol.d.ts +0 -0
  39. /package/{dist/types → types}/foundation/ByteBufferQueue.d.ts +0 -0
  40. /package/{dist/types → types}/foundation/RTCError.d.ts +0 -0
  41. /package/{dist/types → types}/ice/RTCIceCandidate.d.ts +0 -0
  42. /package/{dist/types → types}/ice/ice-agent.d.ts +0 -0
  43. /package/{dist/types → types}/ice/stun-message.d.ts +0 -0
  44. /package/{dist/types → types}/index.d.ts +0 -0
  45. /package/{dist/types → types}/peerconnection/RTCPeerConnection.d.ts +0 -0
  46. /package/{dist/types → types}/sctp/association.d.ts +0 -0
  47. /package/{dist/types → types}/sctp/chunks.d.ts +0 -0
  48. /package/{dist/types → types}/sctp/crc32c.d.ts +0 -0
  49. /package/{dist/types → types}/sctp/datachannel-manager.d.ts +0 -0
  50. /package/{dist/types → types}/sctp/dcep.d.ts +0 -0
  51. /package/{dist/types → types}/sdp/RTCSessionDescription.d.ts +0 -0
  52. /package/{dist/types → types}/sdp/sdp-utils.d.ts +0 -0
  53. /package/{dist/types → types}/transport-stack.d.ts +0 -0
@@ -1,260 +0,0 @@
1
- /**
2
- * @file stun-message.ts
3
- * @description STUN message codec for ICE connectivity checks (RFC 5389 / 8445).
4
- * @module ice/stun-message
5
- *
6
- * Unlike the server-oriented stun-client.js (binding/allocate), this builds and
7
- * validates the connectivity-check messages browsers require: USERNAME,
8
- * MESSAGE-INTEGRITY (HMAC-SHA1 keyed by the peer's ice-pwd), FINGERPRINT
9
- * (CRC-32 of the message Xored with 0x5354554e), PRIORITY, ICE-CONTROLLING/
10
- * ICE-CONTROLLED, and USE-CANDIDATE.
11
- */
12
-
13
- 'use strict';
14
-
15
- import * as crypto from 'crypto';
16
-
17
- export const MAGIC_COOKIE = 0x2112a442;
18
-
19
- export const METHOD = Object.freeze({ BINDING: 0x0001 });
20
- export const CLASS = Object.freeze({
21
- REQUEST: 0x000,
22
- INDICATION: 0x010,
23
- SUCCESS: 0x100,
24
- ERROR: 0x110,
25
- });
26
-
27
- export const MSG_TYPE = Object.freeze({
28
- BINDING_REQUEST: 0x0001,
29
- BINDING_SUCCESS: 0x0101,
30
- BINDING_ERROR: 0x0111,
31
- });
32
-
33
- export const ATTR = Object.freeze({
34
- MAPPED_ADDRESS: 0x0001,
35
- USERNAME: 0x0006,
36
- MESSAGE_INTEGRITY: 0x0008,
37
- ERROR_CODE: 0x0009,
38
- XOR_MAPPED_ADDRESS: 0x0020,
39
- PRIORITY: 0x0024,
40
- USE_CANDIDATE: 0x0025,
41
- FINGERPRINT: 0x8028,
42
- ICE_CONTROLLED: 0x8029,
43
- ICE_CONTROLLING: 0x802a,
44
- });
45
-
46
- /** A single STUN attribute pending serialization. */
47
- interface StunAttribute {
48
- type: number;
49
- value: Buffer;
50
- }
51
-
52
- /** Shape of a parsed STUN message. */
53
- export interface ParsedStunMessage {
54
- type: number;
55
- transactionId: Buffer;
56
- attrs: Map<number, Buffer>;
57
- raw: Buffer;
58
- }
59
-
60
- function pad4(n: number): number {
61
- return (n + 3) & ~3;
62
- }
63
-
64
- /** CRC-32 (IEEE) for the FINGERPRINT attribute. */
65
- const CRC_TABLE: Uint32Array = (() => {
66
- const t = new Uint32Array(256);
67
- for (let n = 0; n < 256; n++) {
68
- let c = n;
69
- for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
70
- t[n] = c >>> 0;
71
- }
72
- return t;
73
- })();
74
- export function crc32(buf: Buffer): number {
75
- let crc = 0xffffffff;
76
- for (let i = 0; i < buf.length; i++) crc = CRC_TABLE[(crc ^ buf[i]!) & 0xff]! ^ (crc >>> 8);
77
- return (crc ^ 0xffffffff) >>> 0;
78
- }
79
-
80
- /**
81
- * @class StunMessageBuilder
82
- * @description Incrementally builds a STUN message, then appends
83
- * MESSAGE-INTEGRITY and FINGERPRINT with the correct length pre-computation.
84
- */
85
- export class StunMessageBuilder {
86
- type: number;
87
- transactionId: Buffer;
88
- attrs: StunAttribute[];
89
-
90
- constructor(type: number, transactionId?: Buffer) {
91
- this.type = type;
92
- this.transactionId = transactionId || crypto.randomBytes(12);
93
- this.attrs = []; // {type, value}
94
- }
95
-
96
- addAttr(type: number, value: Buffer): this {
97
- this.attrs.push({ type, value });
98
- return this;
99
- }
100
-
101
- addUsername(username: string): this {
102
- return this.addAttr(ATTR.USERNAME, Buffer.from(username, 'utf8'));
103
- }
104
-
105
- addPriority(priority: number): this {
106
- const b = Buffer.alloc(4);
107
- b.writeUInt32BE(priority >>> 0, 0);
108
- return this.addAttr(ATTR.PRIORITY, b);
109
- }
110
-
111
- addIceControlling(tieBreaker: Buffer): this {
112
- return this.addAttr(ATTR.ICE_CONTROLLING, tieBreaker);
113
- }
114
-
115
- addIceControlled(tieBreaker: Buffer): this {
116
- return this.addAttr(ATTR.ICE_CONTROLLED, tieBreaker);
117
- }
118
-
119
- addUseCandidate(): this {
120
- return this.addAttr(ATTR.USE_CANDIDATE, Buffer.alloc(0));
121
- }
122
-
123
- addXorMappedAddress(address: string, port: number): this {
124
- return this.addAttr(ATTR.XOR_MAPPED_ADDRESS, encodeXorAddress(address, port, this.transactionId));
125
- }
126
-
127
- /** Serialize the attributes added so far. */
128
- #encodeBody(): Buffer {
129
- const parts: Buffer[] = [];
130
- for (const a of this.attrs) {
131
- const head = Buffer.alloc(4);
132
- head.writeUInt16BE(a.type, 0);
133
- head.writeUInt16BE(a.value.length, 2);
134
- const padded = Buffer.alloc(pad4(a.value.length));
135
- a.value.copy(padded, 0);
136
- parts.push(head, padded);
137
- }
138
- return Buffer.concat(parts);
139
- }
140
-
141
- #header(bodyLen: number): Buffer {
142
- const h = Buffer.alloc(20);
143
- h.writeUInt16BE(this.type, 0);
144
- h.writeUInt16BE(bodyLen, 2);
145
- h.writeUInt32BE(MAGIC_COOKIE, 4);
146
- this.transactionId.copy(h, 8);
147
- return h;
148
- }
149
-
150
- /**
151
- * Finalize the message, appending MESSAGE-INTEGRITY (keyed by `password`)
152
- * and FINGERPRINT. Both require the header length to include the attribute
153
- * being computed, per RFC 5389 §15.4 / §15.5.
154
- * @param {string} [password] - ICE password for MESSAGE-INTEGRITY
155
- * @returns {Buffer}
156
- */
157
- build(password?: string): Buffer {
158
- let body = this.#encodeBody();
159
-
160
- if (password) {
161
- // Length for HMAC input = current body + (4 header + 20 HMAC).
162
- const lenForMI = body.length + 24;
163
- const header = this.#header(lenForMI);
164
- const hmac = crypto
165
- .createHmac('sha1', Buffer.from(password, 'utf8'))
166
- .update(Buffer.concat([header, body]))
167
- .digest();
168
- const miHead = Buffer.alloc(4);
169
- miHead.writeUInt16BE(ATTR.MESSAGE_INTEGRITY, 0);
170
- miHead.writeUInt16BE(20, 2);
171
- body = Buffer.concat([body, miHead, hmac]);
172
- }
173
-
174
- // FINGERPRINT: CRC-32 over the message (with length including fingerprint)
175
- // Xored with 0x5354554e.
176
- const lenForFp = body.length + 8;
177
- const headerFp = this.#header(lenForFp);
178
- const fpVal = (crc32(Buffer.concat([headerFp, body])) ^ 0x5354554e) >>> 0;
179
- const fpHead = Buffer.alloc(8);
180
- fpHead.writeUInt16BE(ATTR.FINGERPRINT, 0);
181
- fpHead.writeUInt16BE(4, 2);
182
- fpHead.writeUInt32BE(fpVal, 4);
183
- body = Buffer.concat([body, fpHead]);
184
-
185
- return Buffer.concat([this.#header(body.length), body]);
186
- }
187
- }
188
-
189
- /** Encode a XOR-MAPPED-ADDRESS attribute value (IPv4). */
190
- function encodeXorAddress(address: string, port: number, _transactionId: Buffer): Buffer {
191
- const buf = Buffer.alloc(8);
192
- buf.writeUInt8(0, 0);
193
- buf.writeUInt8(0x01, 1); // family IPv4
194
- buf.writeUInt16BE(port ^ (MAGIC_COOKIE >>> 16), 2);
195
- const parts = address.split('.').map(Number);
196
- const addrInt = ((parts[0]! << 24) | (parts[1]! << 16) | (parts[2]! << 8) | parts[3]!) >>> 0;
197
- buf.writeUInt32BE((addrInt ^ MAGIC_COOKIE) >>> 0, 4);
198
- return buf;
199
- }
200
-
201
- /**
202
- * Parse a STUN message. Returns null if not a STUN message.
203
- * @param {Buffer} msg
204
- * @returns {null|{type:number,transactionId:Buffer,attrs:Map<number,Buffer>,raw:Buffer}}
205
- */
206
- export function parse(msg: Buffer): ParsedStunMessage | null {
207
- if (msg.length < 20) return null;
208
- if (msg.readUInt32BE(4) !== MAGIC_COOKIE) return null;
209
- const type = msg.readUInt16BE(0);
210
- const length = msg.readUInt16BE(2);
211
- if (20 + length > msg.length) return null;
212
- const transactionId = msg.slice(8, 20);
213
- const attrs = new Map<number, Buffer>();
214
- let off = 20;
215
- const end = 20 + length;
216
- while (off + 4 <= end) {
217
- const atype = msg.readUInt16BE(off);
218
- const alen = msg.readUInt16BE(off + 2);
219
- off += 4;
220
- if (off + alen > end) break;
221
- attrs.set(atype, msg.slice(off, off + alen));
222
- off += pad4(alen);
223
- }
224
- return { type, transactionId, attrs, raw: msg };
225
- }
226
-
227
- /**
228
- * Verify the MESSAGE-INTEGRITY of a parsed message against a password.
229
- * @param {Buffer} msg - raw message
230
- * @param {string} password
231
- * @returns {boolean}
232
- */
233
- export function verifyIntegrity(msg: Buffer, password: string): boolean {
234
- // Locate the MESSAGE-INTEGRITY attribute.
235
- const length = msg.readUInt16BE(2);
236
- let off = 20;
237
- const end = 20 + length;
238
- let miOffset = -1;
239
- while (off + 4 <= end) {
240
- const atype = msg.readUInt16BE(off);
241
- const alen = msg.readUInt16BE(off + 2);
242
- if (atype === ATTR.MESSAGE_INTEGRITY) {
243
- miOffset = off;
244
- break;
245
- }
246
- off += 4 + pad4(alen);
247
- }
248
- if (miOffset < 0) return false;
249
-
250
- const provided = msg.slice(miOffset + 4, miOffset + 4 + 20);
251
- // Recompute over header (with length up to & including MI) + body before MI.
252
- const lenUpToMI = miOffset + 24 - 20;
253
- const header = Buffer.from(msg.slice(0, 20));
254
- header.writeUInt16BE(lenUpToMI, 2);
255
- const hmac = crypto
256
- .createHmac('sha1', Buffer.from(password, 'utf8'))
257
- .update(Buffer.concat([header, msg.slice(20, miOffset)]))
258
- .digest();
259
- return provided.length === hmac.length && crypto.timingSafeEqual(provided, hmac);
260
- }
package/src/index.ts DELETED
@@ -1,72 +0,0 @@
1
- /**
2
- * @fileoverview node-rtc-connection - WebRTC DataChannel implementation for Node.js
3
- *
4
- * A from-scratch, pure-Node.js implementation of WebRTC peer connections and
5
- * data channels (no native dependencies). Interoperates with browsers.
6
- *
7
- * This implementation focuses on DataChannel functionality without media streams.
8
- * Features:
9
- * - ICE (Interactive Connectivity Establishment), RFC 8445
10
- * - STUN/TURN support for NAT traversal
11
- * - DTLS 1.2 encryption (RFC 6347)
12
- * - SCTP over DTLS + DCEP for data channels (RFC 8831 / 8832)
13
- * - W3C-compatible RTCPeerConnection / RTCDataChannel API
14
- *
15
- * @license MIT
16
- * @author nmhung1210
17
- */
18
-
19
- // Foundation
20
- import ByteBufferQueue from './foundation/ByteBufferQueue';
21
- import RTCError from './foundation/RTCError';
22
-
23
- // ICE / certificates
24
- import RTCIceCandidate from './ice/RTCIceCandidate';
25
- import RTCCertificate from './dtls/RTCCertificate';
26
-
27
- // DataChannel
28
- import { RTCDataChannel, RTCDataChannelState } from './datachannel/RTCDataChannel';
29
-
30
- // SDP
31
- import { RTCSessionDescription, RTCSdpType } from './sdp/RTCSessionDescription';
32
-
33
- // PeerConnection
34
- import {
35
- RTCPeerConnection,
36
- RTCSignalingState,
37
- RTCIceGatheringState,
38
- RTCPeerConnectionState,
39
- } from './peerconnection/RTCPeerConnection';
40
-
41
- import pkg from '../package.json';
42
-
43
- export {
44
- // Foundation
45
- ByteBufferQueue,
46
- RTCError,
47
-
48
- // ICE / certificates
49
- RTCIceCandidate,
50
- RTCCertificate,
51
-
52
- // DataChannel
53
- RTCDataChannel,
54
- RTCDataChannelState,
55
-
56
- // SDP
57
- RTCSessionDescription,
58
- RTCSdpType,
59
-
60
- // PeerConnection
61
- RTCPeerConnection,
62
- RTCSignalingState,
63
- RTCIceGatheringState,
64
- RTCPeerConnectionState,
65
- };
66
-
67
- export const version: string = pkg.version;
68
-
69
- // Re-export public types for consumers.
70
- export type { RTCDataChannelInit } from './datachannel/RTCDataChannel';
71
- export type { RTCSessionDescriptionInit } from './sdp/RTCSessionDescription';
72
- export type { TransportStackOptions } from './transport-stack';