@libp2p/webrtc 5.2.9-fc5122110 → 5.2.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 +54 -0
- package/dist/index.min.js +153 -18
- package/dist/src/constants.d.ts +20 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +20 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +54 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +54 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/private-to-public/listener.d.ts +9 -4
- package/dist/src/private-to-public/listener.d.ts.map +1 -1
- package/dist/src/private-to-public/listener.js +7 -18
- package/dist/src/private-to-public/listener.js.map +1 -1
- package/dist/src/private-to-public/transport.d.ts +67 -5
- package/dist/src/private-to-public/transport.d.ts.map +1 -1
- package/dist/src/private-to-public/transport.js +181 -2
- package/dist/src/private-to-public/transport.js.map +1 -1
- package/dist/src/private-to-public/utils/pem.d.ts +6 -0
- package/dist/src/private-to-public/utils/pem.d.ts.map +1 -0
- package/dist/src/private-to-public/utils/pem.js +15 -0
- package/dist/src/private-to-public/utils/pem.js.map +1 -0
- package/dist/typedoc-urls.json +14 -0
- package/package.json +11 -8
- package/src/constants.ts +25 -0
- package/src/index.ts +54 -0
- package/src/private-to-public/listener.ts +17 -26
- package/src/private-to-public/transport.ts +281 -7
- package/src/private-to-public/utils/pem.ts +18 -0
@@ -1,20 +1,37 @@
|
|
1
|
-
import {
|
1
|
+
import { generateKeyPair, privateKeyToCryptoKeyPair } from '@libp2p/crypto/keys';
|
2
|
+
import { InvalidParametersError, NotFoundError, NotStartedError, TypedEventEmitter, serviceCapabilities, transportSymbol } from '@libp2p/interface';
|
2
3
|
import { peerIdFromString } from '@libp2p/peer-id';
|
3
4
|
import { WebRTCDirect } from '@multiformats/multiaddr-matcher';
|
5
|
+
import { BasicConstraintsExtension, X509Certificate, X509CertificateGenerator } from '@peculiar/x509';
|
6
|
+
import { Key } from 'interface-datastore';
|
7
|
+
import { base64url } from 'multiformats/bases/base64';
|
8
|
+
import { sha256 } from 'multiformats/hashes/sha2';
|
4
9
|
import { raceSignal } from 'race-signal';
|
10
|
+
import { equals as uint8ArrayEquals } from 'uint8arrays/equals';
|
11
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
|
12
|
+
import { DEFAULT_CERTIFICATE_DATASTORE_KEY, DEFAULT_CERTIFICATE_LIFESPAN, DEFAULT_CERTIFICATE_PRIVATE_KEY_NAME, DEFAULT_CERTIFICATE_RENEWAL_THRESHOLD } from '../constants.js';
|
5
13
|
import { genUfrag } from '../util.js';
|
6
14
|
import { WebRTCDirectListener } from './listener.js';
|
7
15
|
import { connect } from './utils/connect.js';
|
8
16
|
import { createDialerRTCPeerConnection } from './utils/get-rtcpeerconnection.js';
|
17
|
+
import { formatAsPem } from './utils/pem.js';
|
9
18
|
export class WebRTCDirectTransport {
|
10
19
|
log;
|
11
20
|
metrics;
|
12
21
|
components;
|
13
22
|
init;
|
23
|
+
certificate;
|
24
|
+
privateKey;
|
25
|
+
emitter;
|
26
|
+
renewCertificateTask;
|
14
27
|
constructor(components, init = {}) {
|
15
28
|
this.log = components.logger.forComponent('libp2p:webrtc-direct');
|
16
29
|
this.components = components;
|
17
30
|
this.init = init;
|
31
|
+
this.emitter = new TypedEventEmitter();
|
32
|
+
if (init.certificateLifespan != null && init.certificateRenewalThreshold != null && init.certificateRenewalThreshold >= init.certificateLifespan) {
|
33
|
+
throw new InvalidParametersError('Certificate renewal threshold must be less than certificate lifespan');
|
34
|
+
}
|
18
35
|
if (components.metrics != null) {
|
19
36
|
this.metrics = {
|
20
37
|
dialerEvents: components.metrics.registerCounterGroup('libp2p_webrtc-direct_dialer_events_total', {
|
@@ -29,6 +46,15 @@ export class WebRTCDirectTransport {
|
|
29
46
|
[serviceCapabilities] = [
|
30
47
|
'@libp2p/transport'
|
31
48
|
];
|
49
|
+
async start() {
|
50
|
+
this.certificate = await this.getCertificate();
|
51
|
+
}
|
52
|
+
async stop() {
|
53
|
+
if (this.renewCertificateTask != null) {
|
54
|
+
clearTimeout(this.renewCertificateTask);
|
55
|
+
}
|
56
|
+
this.certificate = undefined;
|
57
|
+
}
|
32
58
|
/**
|
33
59
|
* Dial a given multiaddr
|
34
60
|
*/
|
@@ -41,9 +67,14 @@ export class WebRTCDirectTransport {
|
|
41
67
|
* Create transport listeners no supported by browsers
|
42
68
|
*/
|
43
69
|
createListener(options) {
|
70
|
+
if (this.certificate == null) {
|
71
|
+
throw new NotStartedError();
|
72
|
+
}
|
44
73
|
return new WebRTCDirectListener(this.components, {
|
45
74
|
...this.init,
|
46
|
-
...options
|
75
|
+
...options,
|
76
|
+
certificate: this.certificate,
|
77
|
+
emitter: this.emitter
|
47
78
|
});
|
48
79
|
}
|
49
80
|
/**
|
@@ -93,5 +124,153 @@ export class WebRTCDirectTransport {
|
|
93
124
|
throw err;
|
94
125
|
}
|
95
126
|
}
|
127
|
+
async getCertificate(forceRenew) {
|
128
|
+
if (isTransportCertificate(this.init.certificate)) {
|
129
|
+
this.log('using provided TLS certificate');
|
130
|
+
return this.init.certificate;
|
131
|
+
}
|
132
|
+
const privateKey = await this.loadOrCreatePrivateKey();
|
133
|
+
const { pem, certhash } = await this.loadOrCreateCertificate(privateKey, forceRenew);
|
134
|
+
return {
|
135
|
+
privateKey: await formatAsPem(privateKey),
|
136
|
+
pem,
|
137
|
+
certhash
|
138
|
+
};
|
139
|
+
}
|
140
|
+
async loadOrCreatePrivateKey() {
|
141
|
+
if (this.privateKey != null) {
|
142
|
+
return this.privateKey;
|
143
|
+
}
|
144
|
+
const keychainName = this.init.certificateKeychainName ?? DEFAULT_CERTIFICATE_PRIVATE_KEY_NAME;
|
145
|
+
const keychain = this.getKeychain();
|
146
|
+
try {
|
147
|
+
if (keychain == null) {
|
148
|
+
this.log('no keychain configured - not checking for stored private key');
|
149
|
+
throw new NotFoundError();
|
150
|
+
}
|
151
|
+
this.log.trace('checking for stored private key');
|
152
|
+
this.privateKey = await keychain.exportKey(keychainName);
|
153
|
+
}
|
154
|
+
catch (err) {
|
155
|
+
if (err.name !== 'NotFoundError') {
|
156
|
+
throw err;
|
157
|
+
}
|
158
|
+
this.log.trace('generating private key');
|
159
|
+
this.privateKey = await generateKeyPair('ECDSA', 'P-256');
|
160
|
+
if (keychain != null) {
|
161
|
+
this.log.trace('storing private key');
|
162
|
+
await keychain.importKey(keychainName, this.privateKey);
|
163
|
+
}
|
164
|
+
else {
|
165
|
+
this.log('no keychain configured - not storing private key');
|
166
|
+
}
|
167
|
+
}
|
168
|
+
return this.privateKey;
|
169
|
+
}
|
170
|
+
async loadOrCreateCertificate(privateKey, forceRenew) {
|
171
|
+
if (this.certificate != null && forceRenew !== true) {
|
172
|
+
return this.certificate;
|
173
|
+
}
|
174
|
+
let cert;
|
175
|
+
const dsKey = new Key(this.init.certificateDatastoreKey ?? DEFAULT_CERTIFICATE_DATASTORE_KEY);
|
176
|
+
const keyPair = await privateKeyToCryptoKeyPair(privateKey);
|
177
|
+
try {
|
178
|
+
if (forceRenew === true) {
|
179
|
+
this.log.trace('forcing renewal of TLS certificate');
|
180
|
+
throw new NotFoundError();
|
181
|
+
}
|
182
|
+
this.log.trace('checking for stored TLS certificate');
|
183
|
+
cert = await this.loadCertificate(dsKey, keyPair);
|
184
|
+
}
|
185
|
+
catch (err) {
|
186
|
+
if (err.name !== 'NotFoundError') {
|
187
|
+
throw err;
|
188
|
+
}
|
189
|
+
this.log.trace('generating new TLS certificate');
|
190
|
+
cert = await this.createCertificate(dsKey, keyPair);
|
191
|
+
}
|
192
|
+
// set timeout to renew certificate
|
193
|
+
let renewTime = (cert.notAfter.getTime() - (this.init.certificateRenewalThreshold ?? DEFAULT_CERTIFICATE_RENEWAL_THRESHOLD)) - Date.now();
|
194
|
+
if (renewTime < 0) {
|
195
|
+
renewTime = 100;
|
196
|
+
}
|
197
|
+
this.log('will renew TLS certificate after %d ms', renewTime);
|
198
|
+
this.renewCertificateTask = setTimeout(() => {
|
199
|
+
this.log('renewing TLS certificate');
|
200
|
+
this.getCertificate(true)
|
201
|
+
.then(cert => {
|
202
|
+
this.certificate = cert;
|
203
|
+
this.emitter.safeDispatchEvent('certificate:renew', {
|
204
|
+
detail: cert
|
205
|
+
});
|
206
|
+
})
|
207
|
+
.catch(err => {
|
208
|
+
this.log.error('could not renew certificate - %e', err);
|
209
|
+
});
|
210
|
+
}, renewTime);
|
211
|
+
return {
|
212
|
+
pem: cert.toString('pem'),
|
213
|
+
certhash: base64url.encode((await sha256.digest(new Uint8Array(cert.rawData))).bytes)
|
214
|
+
};
|
215
|
+
}
|
216
|
+
async loadCertificate(dsKey, keyPair) {
|
217
|
+
const buf = await this.components.datastore.get(dsKey);
|
218
|
+
const cert = new X509Certificate(buf);
|
219
|
+
// check expiry date
|
220
|
+
const expiryTime = cert.notAfter.getTime() - (this.init.certificateRenewalThreshold ?? DEFAULT_CERTIFICATE_RENEWAL_THRESHOLD);
|
221
|
+
if (Date.now() > expiryTime) {
|
222
|
+
this.log('stored TLS certificate has expired');
|
223
|
+
// act as if no certificate was present
|
224
|
+
throw new NotFoundError();
|
225
|
+
}
|
226
|
+
this.log('loaded certificate, expires in %d ms', expiryTime);
|
227
|
+
// check public keys match
|
228
|
+
const exportedCertKey = await cert.publicKey.export(crypto);
|
229
|
+
const rawCertKey = await crypto.subtle.exportKey('raw', exportedCertKey);
|
230
|
+
const rawKeyPairKey = await crypto.subtle.exportKey('raw', keyPair.publicKey);
|
231
|
+
if (!uint8ArrayEquals(new Uint8Array(rawCertKey, 0, rawCertKey.byteLength), new Uint8Array(rawKeyPairKey, 0, rawKeyPairKey.byteLength))) {
|
232
|
+
this.log('stored TLS certificate public key did not match public key from private key');
|
233
|
+
throw new NotFoundError();
|
234
|
+
}
|
235
|
+
this.log('loaded certificate, expiry time is %o', expiryTime);
|
236
|
+
return cert;
|
237
|
+
}
|
238
|
+
async createCertificate(dsKey, keyPair) {
|
239
|
+
const notBefore = new Date();
|
240
|
+
const notAfter = new Date(Date.now() + (this.init.certificateLifespan ?? DEFAULT_CERTIFICATE_LIFESPAN));
|
241
|
+
// have to set ms to 0 to work around https://github.com/PeculiarVentures/x509/issues/73
|
242
|
+
notBefore.setMilliseconds(0);
|
243
|
+
notAfter.setMilliseconds(0);
|
244
|
+
const cert = await X509CertificateGenerator.createSelfSigned({
|
245
|
+
serialNumber: (BigInt(Math.random().toString().replace('.', '')) * 100000n).toString(16),
|
246
|
+
name: 'CN=example.com, C=US, L=CA, O=example, ST=CA',
|
247
|
+
notBefore,
|
248
|
+
notAfter,
|
249
|
+
keys: keyPair,
|
250
|
+
extensions: [
|
251
|
+
new BasicConstraintsExtension(false, undefined, true)
|
252
|
+
]
|
253
|
+
}, crypto);
|
254
|
+
if (this.getKeychain() != null) {
|
255
|
+
this.log.trace('storing TLS certificate');
|
256
|
+
await this.components.datastore.put(dsKey, uint8ArrayFromString(cert.toString('pem')));
|
257
|
+
}
|
258
|
+
else {
|
259
|
+
this.log('no keychain is configured so not storing TLS certificate since the private key will not be reused');
|
260
|
+
}
|
261
|
+
return cert;
|
262
|
+
}
|
263
|
+
getKeychain() {
|
264
|
+
try {
|
265
|
+
return this.components.keychain;
|
266
|
+
}
|
267
|
+
catch { }
|
268
|
+
}
|
269
|
+
}
|
270
|
+
function isTransportCertificate(obj) {
|
271
|
+
if (obj == null) {
|
272
|
+
return false;
|
273
|
+
}
|
274
|
+
return typeof obj.privateKey === 'string' && typeof obj.pem === 'string' && typeof obj.certhash === 'string';
|
96
275
|
}
|
97
276
|
//# sourceMappingURL=transport.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../src/private-to-public/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../src/private-to-public/transport.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,6 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
/// <reference types="node" />
|
3
|
+
import type { PrivateKey } from '@libp2p/interface';
|
4
|
+
export declare function toBuffer(uint8Array: Uint8Array): Buffer;
|
5
|
+
export declare function formatAsPem(privateKey: PrivateKey): Promise<string>;
|
6
|
+
//# sourceMappingURL=pem.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"pem.d.ts","sourceRoot":"","sources":["../../../../src/private-to-public/utils/pem.ts"],"names":[],"mappings":";;AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAEnD,wBAAgB,QAAQ,CAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CAExD;AAED,wBAAsB,WAAW,CAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAS1E"}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { privateKeyToCryptoKeyPair } from '@libp2p/crypto/keys';
|
2
|
+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
|
3
|
+
export function toBuffer(uint8Array) {
|
4
|
+
return Buffer.from(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength);
|
5
|
+
}
|
6
|
+
export async function formatAsPem(privateKey) {
|
7
|
+
const keyPair = await privateKeyToCryptoKeyPair(privateKey);
|
8
|
+
const exported = await crypto.subtle.exportKey('pkcs8', keyPair.privateKey);
|
9
|
+
return [
|
10
|
+
'-----BEGIN PRIVATE KEY-----',
|
11
|
+
...uint8ArrayToString(new Uint8Array(exported), 'base64pad').split(/(.{64})/).filter(Boolean),
|
12
|
+
'-----END PRIVATE KEY-----'
|
13
|
+
].join('\n');
|
14
|
+
}
|
15
|
+
//# sourceMappingURL=pem.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"pem.js","sourceRoot":"","sources":["../../../../src/private-to-public/utils/pem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAGtE,MAAM,UAAU,QAAQ,CAAE,UAAsB;IAC9C,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,CAAA;AACrF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAE,UAAsB;IACvD,MAAM,OAAO,GAAG,MAAM,yBAAyB,CAAC,UAAU,CAAC,CAAA;IAC3D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;IAE3E,OAAO;QACL,6BAA6B;QAC7B,GAAG,kBAAkB,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QAC7F,2BAA2B;KAC5B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACd,CAAC"}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"DataChannelOptions": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webrtc.DataChannelOptions.html",
|
3
|
+
".:DataChannelOptions": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webrtc.DataChannelOptions.html",
|
4
|
+
"TransportCertificate": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webrtc.TransportCertificate.html",
|
5
|
+
".:TransportCertificate": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webrtc.TransportCertificate.html",
|
6
|
+
"WebRTCDirectTransportComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webrtc.WebRTCDirectTransportComponents.html",
|
7
|
+
"WebRTCTransportComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webrtc.WebRTCTransportComponents.html",
|
8
|
+
"WebRTCTransportDirectInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webrtc.WebRTCTransportDirectInit.html",
|
9
|
+
"WebRTCTransportInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webrtc.WebRTCTransportInit.html",
|
10
|
+
"webRTC": "https://libp2p.github.io/js-libp2p/functions/_libp2p_webrtc.webRTC.html",
|
11
|
+
".:webRTC": "https://libp2p.github.io/js-libp2p/functions/_libp2p_webrtc.webRTC.html",
|
12
|
+
"webRTCDirect": "https://libp2p.github.io/js-libp2p/functions/_libp2p_webrtc.webRTCDirect.html",
|
13
|
+
".:webRTCDirect": "https://libp2p.github.io/js-libp2p/functions/_libp2p_webrtc.webRTCDirect.html"
|
14
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@libp2p/webrtc",
|
3
|
-
"version": "5.2.
|
3
|
+
"version": "5.2.10",
|
4
4
|
"description": "A libp2p transport using WebRTC connections",
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
6
6
|
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/transport-webrtc#readme",
|
@@ -54,10 +54,12 @@
|
|
54
54
|
"@chainsafe/is-ip": "^2.0.2",
|
55
55
|
"@chainsafe/libp2p-noise": "^16.0.0",
|
56
56
|
"@ipshipyard/node-datachannel": "^0.26.4",
|
57
|
-
"@libp2p/
|
58
|
-
"@libp2p/interface
|
59
|
-
"@libp2p/
|
60
|
-
"@libp2p/
|
57
|
+
"@libp2p/crypto": "^5.1.0",
|
58
|
+
"@libp2p/interface": "^2.8.0",
|
59
|
+
"@libp2p/interface-internal": "^2.3.10",
|
60
|
+
"@libp2p/keychain": "^5.2.0",
|
61
|
+
"@libp2p/peer-id": "^5.1.1",
|
62
|
+
"@libp2p/utils": "^6.6.1",
|
61
63
|
"@multiformats/multiaddr": "^12.4.0",
|
62
64
|
"@multiformats/multiaddr-matcher": "^1.6.0",
|
63
65
|
"@peculiar/webcrypto": "^1.5.0",
|
@@ -65,6 +67,7 @@
|
|
65
67
|
"any-signal": "^4.1.1",
|
66
68
|
"detect-browser": "^5.3.0",
|
67
69
|
"get-port": "^7.1.0",
|
70
|
+
"interface-datastore": "^8.3.1",
|
68
71
|
"it-length-prefixed": "^10.0.1",
|
69
72
|
"it-protobuf-stream": "^2.0.1",
|
70
73
|
"it-pushable": "^3.2.3",
|
@@ -83,11 +86,11 @@
|
|
83
86
|
"uint8arrays": "^5.1.0"
|
84
87
|
},
|
85
88
|
"devDependencies": {
|
86
|
-
"@libp2p/
|
87
|
-
"@libp2p/
|
88
|
-
"@libp2p/logger": "5.1.13-fc5122110",
|
89
|
+
"@libp2p/interface-compliance-tests": "^6.4.3",
|
90
|
+
"@libp2p/logger": "^5.1.14",
|
89
91
|
"@types/sinon": "^17.0.3",
|
90
92
|
"aegir": "^45.1.1",
|
93
|
+
"datastore-core": "^10.0.2",
|
91
94
|
"delay": "^6.0.0",
|
92
95
|
"it-length": "^3.0.6",
|
93
96
|
"it-pair": "^2.0.6",
|
package/src/constants.ts
CHANGED
@@ -110,3 +110,28 @@ export const MUXER_PROTOCOL = '/webrtc'
|
|
110
110
|
* The protocol used for the signalling stream protocol
|
111
111
|
*/
|
112
112
|
export const SIGNALING_PROTOCOL = '/webrtc-signaling/0.0.1'
|
113
|
+
|
114
|
+
/**
|
115
|
+
* Used to store generated certificates in the datastore
|
116
|
+
*/
|
117
|
+
export const DEFAULT_CERTIFICATE_DATASTORE_KEY = '/libp2p/webrtc-direct/certificate'
|
118
|
+
|
119
|
+
/**
|
120
|
+
* Used to store the certificate private key in the keychain
|
121
|
+
*/
|
122
|
+
export const DEFAULT_CERTIFICATE_PRIVATE_KEY_NAME = 'webrtc-direct-certificate-private-key'
|
123
|
+
|
124
|
+
/**
|
125
|
+
* The default type of certificate private key
|
126
|
+
*/
|
127
|
+
export const DEFAULT_CERTIFICATE_PRIVATE_KEY_TYPE = 'ECDSA'
|
128
|
+
|
129
|
+
/**
|
130
|
+
* How long the certificate is valid for
|
131
|
+
*/
|
132
|
+
export const DEFAULT_CERTIFICATE_LIFESPAN = 1_209_600_000
|
133
|
+
|
134
|
+
/**
|
135
|
+
* Renew the certificate this long before it expires
|
136
|
+
*/
|
137
|
+
export const DEFAULT_CERTIFICATE_RENEWAL_THRESHOLD = 86_400_000
|
package/src/index.ts
CHANGED
@@ -206,6 +206,60 @@
|
|
206
206
|
* }
|
207
207
|
* )
|
208
208
|
* ```
|
209
|
+
*
|
210
|
+
* ## WebRTC Direct certificate hashes
|
211
|
+
*
|
212
|
+
* WebRTC Direct listeners publish the hash of their TLS certificate as part of
|
213
|
+
* the listening multiaddr.
|
214
|
+
*
|
215
|
+
* By default these certificates are generated at start up using an ephemeral
|
216
|
+
* keypair that only exists while the node is running.
|
217
|
+
*
|
218
|
+
* This means that the certificate hashes change when the node is restarted,
|
219
|
+
* which can be undesirable if multiaddrs are intended to be long lived (e.g.
|
220
|
+
* if the node is used as a network bootstrapper).
|
221
|
+
*
|
222
|
+
* To reuse the same certificate and keypair, configure a persistent datastore
|
223
|
+
* and the [@libp2p/keychain](https://www.npmjs.com/package/@libp2p/keychain)
|
224
|
+
* service as part of your service map:
|
225
|
+
*
|
226
|
+
* @example Reuse TLS certificates after restart
|
227
|
+
*
|
228
|
+
* ```ts
|
229
|
+
* import { LevelDatastore } from 'datastore-level'
|
230
|
+
* import { webRTCDirect } from '@libp2p/webrtc'
|
231
|
+
* import { keychain } from '@libp2p/keychain'
|
232
|
+
* import { createLibp2p } from 'libp2p'
|
233
|
+
*
|
234
|
+
* // store data on disk between restarts
|
235
|
+
* const datastore = new LevelDatastore('/path/to/store')
|
236
|
+
*
|
237
|
+
* const listener = await createLibp2p({
|
238
|
+
* addresses: {
|
239
|
+
* listen: [
|
240
|
+
* '/ip4/0.0.0.0/udp/0/webrtc-direct'
|
241
|
+
* ]
|
242
|
+
* },
|
243
|
+
* datastore,
|
244
|
+
* transports: [
|
245
|
+
* webRTCDirect()
|
246
|
+
* ],
|
247
|
+
* services: {
|
248
|
+
* keychain: keychain()
|
249
|
+
* }
|
250
|
+
* })
|
251
|
+
*
|
252
|
+
* await listener.start()
|
253
|
+
*
|
254
|
+
* console.info(listener.getMultiaddrs())
|
255
|
+
* // /ip4/...../udp/../webrtc-direct/certhash/foo
|
256
|
+
*
|
257
|
+
* await listener.stop()
|
258
|
+
* await listener.start()
|
259
|
+
*
|
260
|
+
* console.info(listener.getMultiaddrs())
|
261
|
+
* // /ip4/...../udp/../webrtc-direct/certhash/foo
|
262
|
+
* ```
|
209
263
|
*/
|
210
264
|
|
211
265
|
import { WebRTCTransport } from './private-to-private/transport.js'
|
@@ -3,37 +3,38 @@ import { InvalidParametersError, TypedEventEmitter } from '@libp2p/interface'
|
|
3
3
|
import { getThinWaistAddresses } from '@libp2p/utils/get-thin-waist-addresses'
|
4
4
|
import { multiaddr, fromStringTuples } from '@multiformats/multiaddr'
|
5
5
|
import { WebRTCDirect } from '@multiformats/multiaddr-matcher'
|
6
|
-
import { Crypto } from '@peculiar/webcrypto'
|
7
6
|
import getPort from 'get-port'
|
8
7
|
import pWaitFor from 'p-wait-for'
|
9
8
|
import { CODEC_CERTHASH, CODEC_WEBRTC_DIRECT } from '../constants.js'
|
10
9
|
import { connect } from './utils/connect.js'
|
11
|
-
import { generateTransportCertificate } from './utils/generate-certificates.js'
|
12
10
|
import { createDialerRTCPeerConnection } from './utils/get-rtcpeerconnection.js'
|
13
11
|
import { stunListener } from './utils/stun-listener.js'
|
14
12
|
import type { DataChannelOptions, TransportCertificate } from '../index.js'
|
13
|
+
import type { WebRTCDirectTransportCertificateEvents } from './transport.js'
|
15
14
|
import type { DirectRTCPeerConnection } from './utils/get-rtcpeerconnection.js'
|
16
15
|
import type { StunServer } from './utils/stun-listener.js'
|
17
|
-
import type { PeerId, ListenerEvents, Listener, Upgrader, ComponentLogger, Logger, CounterGroup, Metrics, PrivateKey } from '@libp2p/interface'
|
16
|
+
import type { PeerId, ListenerEvents, Listener, Upgrader, ComponentLogger, Logger, CounterGroup, Metrics, PrivateKey, TypedEventTarget } from '@libp2p/interface'
|
17
|
+
import type { Keychain } from '@libp2p/keychain'
|
18
18
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
19
|
-
|
20
|
-
const crypto = new Crypto()
|
19
|
+
import type { Datastore } from 'interface-datastore'
|
21
20
|
|
22
21
|
export interface WebRTCDirectListenerComponents {
|
23
22
|
peerId: PeerId
|
24
23
|
privateKey: PrivateKey
|
25
24
|
logger: ComponentLogger
|
26
25
|
upgrader: Upgrader
|
26
|
+
keychain?: Keychain
|
27
|
+
datastore: Datastore
|
27
28
|
metrics?: Metrics
|
28
29
|
}
|
29
30
|
|
30
31
|
export interface WebRTCDirectListenerInit {
|
31
32
|
upgrader: Upgrader
|
32
|
-
|
33
|
+
certificate: TransportCertificate
|
33
34
|
maxInboundStreams?: number
|
34
35
|
dataChannel?: DataChannelOptions
|
35
36
|
rtcConfiguration?: RTCConfiguration | (() => RTCConfiguration | Promise<RTCConfiguration>)
|
36
|
-
|
37
|
+
emitter: TypedEventTarget<WebRTCDirectTransportCertificateEvents>
|
37
38
|
}
|
38
39
|
|
39
40
|
export interface WebRTCListenerMetrics {
|
@@ -53,7 +54,7 @@ let UDP_MUX_LISTENERS: UDPMuxServer[] = []
|
|
53
54
|
|
54
55
|
export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> implements Listener {
|
55
56
|
private listeningMultiaddr?: Multiaddr
|
56
|
-
private certificate
|
57
|
+
private certificate: TransportCertificate
|
57
58
|
private stunServer?: StunServer
|
58
59
|
private readonly connections: Map<string, DirectRTCPeerConnection>
|
59
60
|
private readonly log: Logger
|
@@ -69,8 +70,8 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
|
|
69
70
|
this.components = components
|
70
71
|
this.connections = new Map()
|
71
72
|
this.log = components.logger.forComponent('libp2p:webrtc-direct:listener')
|
72
|
-
this.certificate = init.certificates?.[0]
|
73
73
|
this.shutdownController = new AbortController()
|
74
|
+
this.certificate = init.certificate
|
74
75
|
|
75
76
|
if (components.metrics != null) {
|
76
77
|
this.metrics = {
|
@@ -80,6 +81,13 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
|
|
80
81
|
})
|
81
82
|
}
|
82
83
|
}
|
84
|
+
|
85
|
+
// inform the transport manager our addresses have changed
|
86
|
+
init.emitter.addEventListener('certificate:renew', evt => {
|
87
|
+
this.log('received new TLS certificate', evt.detail.certhash)
|
88
|
+
this.certificate = evt.detail
|
89
|
+
this.safeDispatchEvent('listening')
|
90
|
+
})
|
83
91
|
}
|
84
92
|
|
85
93
|
async listen (ma: Multiaddr): Promise<void> {
|
@@ -132,23 +140,6 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
|
|
132
140
|
isIPv6: family === 6,
|
133
141
|
server: Promise.resolve()
|
134
142
|
.then(async (): Promise<StunServer> => {
|
135
|
-
// ensure we have a certificate
|
136
|
-
if (this.certificate == null) {
|
137
|
-
this.log.trace('creating TLS certificate')
|
138
|
-
const keyPair = await crypto.subtle.generateKey({
|
139
|
-
name: 'ECDSA',
|
140
|
-
namedCurve: 'P-256'
|
141
|
-
}, true, ['sign', 'verify'])
|
142
|
-
|
143
|
-
const certificate = await generateTransportCertificate(keyPair, {
|
144
|
-
days: 365 * 10
|
145
|
-
})
|
146
|
-
|
147
|
-
if (this.certificate == null) {
|
148
|
-
this.certificate = certificate
|
149
|
-
}
|
150
|
-
}
|
151
|
-
|
152
143
|
if (port === 0) {
|
153
144
|
// libjuice doesn't map 0 to a random free port so we have to do it
|
154
145
|
// ourselves
|