@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.
@@ -1,20 +1,37 @@
1
- import { serviceCapabilities, transportSymbol } from '@libp2p/interface';
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":"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"}
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.9-fc5122110",
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/interface": "2.7.0-fc5122110",
58
- "@libp2p/interface-internal": "2.3.9-fc5122110",
59
- "@libp2p/peer-id": "5.1.0-fc5122110",
60
- "@libp2p/utils": "6.6.0-fc5122110",
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/crypto": "5.0.15-fc5122110",
87
- "@libp2p/interface-compliance-tests": "6.4.2-fc5122110",
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
- certificates?: TransportCertificate[]
33
+ certificate: TransportCertificate
33
34
  maxInboundStreams?: number
34
35
  dataChannel?: DataChannelOptions
35
36
  rtcConfiguration?: RTCConfiguration | (() => RTCConfiguration | Promise<RTCConfiguration>)
36
- useLibjuice?: boolean
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?: TransportCertificate
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