Skip to content

Commit

Permalink
fix: access components via property (#2912)
Browse files Browse the repository at this point in the history
To allow declaring services in any order, access components via
a components property after all services are constructed.
  • Loading branch information
achingbrain authored Jan 13, 2025
1 parent fe8af37 commit c90984e
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 27 deletions.
39 changes: 13 additions & 26 deletions packages/auto-tls/src/auto-tls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,9 @@ import { DEFAULT_ACCOUNT_PRIVATE_KEY_BITS, DEFAULT_ACCOUNT_PRIVATE_KEY_NAME, DEF
import { DomainMapper } from './domain-mapper.js'
import { createCsr, importFromPem, loadOrCreateKey, supportedAddressesFilter } from './utils.js'
import type { AutoTLSComponents, AutoTLSInit, AutoTLS as AutoTLSInterface } from './index.js'
import type { PeerId, PrivateKey, Logger, TypedEventTarget, Libp2pEvents, AbortOptions } from '@libp2p/interface'
import type { AddressManager } from '@libp2p/interface-internal'
import type { Keychain } from '@libp2p/keychain'
import type { Logger, AbortOptions } from '@libp2p/interface'
import type { DebouncedFunction } from '@libp2p/utils/debounce'
import type { Multiaddr } from '@multiformats/multiaddr'
import type { Datastore } from 'interface-datastore'

const RETRY_DELAY = 5_000

Expand All @@ -33,12 +30,7 @@ interface Certificate {

export class AutoTLS implements AutoTLSInterface {
private readonly log: Logger
private readonly addressManager: AddressManager
private readonly keychain: Keychain
private readonly datastore: Datastore
private readonly privateKey: PrivateKey
private readonly peerId: PeerId
private readonly events: TypedEventTarget<Libp2pEvents>
private readonly components: AutoTLSComponents
private readonly forgeEndpoint: URL
private readonly forgeDomain: string
private readonly acmeDirectory: URL
Expand All @@ -64,12 +56,7 @@ export class AutoTLS implements AutoTLSInterface {

constructor (components: AutoTLSComponents, init: AutoTLSInit = {}) {
this.log = components.logger.forComponent('libp2p:auto-tls')
this.addressManager = components.addressManager
this.privateKey = components.privateKey
this.peerId = components.peerId
this.events = components.events
this.keychain = components.keychain
this.datastore = components.datastore
this.components = components
this.forgeEndpoint = new URL(init.forgeEndpoint ?? DEFAULT_FORGE_ENDPOINT)
this.forgeDomain = init.forgeDomain ?? DEFAULT_FORGE_DOMAIN
this.acmeDirectory = new URL(init.acmeDirectory ?? DEFAULT_ACME_DIRECTORY)
Expand All @@ -82,12 +69,12 @@ export class AutoTLS implements AutoTLSInterface {
this.certificatePrivateKeyBits = init.certificatePrivateKeyBits ?? DEFAULT_CERTIFICATE_PRIVATE_KEY_BITS
this.certificateDatastoreKey = init.certificateDatastoreKey ?? DEFAULT_CERTIFICATE_DATASTORE_KEY
this.autoConfirmAddress = init.autoConfirmAddress ?? DEFAULT_AUTO_CONFIRM_ADDRESS
this.clientAuth = new ClientAuth(this.privateKey)
this.clientAuth = new ClientAuth(this.components.privateKey)
this.started = false
this.fetching = false
this.onSelfPeerUpdate = debounce(this._onSelfPeerUpdate.bind(this), init.provisionDelay ?? DEFAULT_PROVISION_DELAY)

const base36EncodedPeer = base36.encode(this.peerId.toCID().bytes)
const base36EncodedPeer = base36.encode(this.components.peerId.toCID().bytes)
this.domain = `${base36EncodedPeer}.${this.forgeDomain}`
this.email = `${base36EncodedPeer}@${this.forgeDomain}`

Expand Down Expand Up @@ -120,22 +107,22 @@ export class AutoTLS implements AutoTLSInterface {
}

await start(this.domainMapper)
this.events.addEventListener('self:peer:update', this.onSelfPeerUpdate)
this.components.events.addEventListener('self:peer:update', this.onSelfPeerUpdate)
this.shutdownController = new AbortController()
setMaxListeners(Infinity, this.shutdownController.signal)
this.started = true
}

async stop (): Promise<void> {
this.events.removeEventListener('self:peer:update', this.onSelfPeerUpdate)
this.components.events.removeEventListener('self:peer:update', this.onSelfPeerUpdate)
this.shutdownController?.abort()
clearTimeout(this.renewTimeout)
await stop(this.onSelfPeerUpdate, this.domainMapper)
this.started = false
}

private _onSelfPeerUpdate (): void {
const addresses = this.addressManager.getAddresses()
const addresses = this.components.addressManager.getAddresses()
.filter(supportedAddressesFilter)

if (addresses.length === 0) {
Expand Down Expand Up @@ -187,7 +174,7 @@ export class AutoTLS implements AutoTLSInterface {
private async fetchCertificate (multiaddrs: Multiaddr[], options?: AbortOptions): Promise<void> {
this.log('fetching certificate')

const certificatePrivateKey = await loadOrCreateKey(this.keychain, this.certificatePrivateKeyName, this.certificatePrivateKeyBits)
const certificatePrivateKey = await loadOrCreateKey(this.components.keychain, this.certificatePrivateKeyName, this.certificatePrivateKeyBits)
const { pem, cert } = await this.loadOrCreateCertificate(certificatePrivateKey, multiaddrs, options)

let event: CertificateEvent = 'certificate:provision'
Expand Down Expand Up @@ -221,7 +208,7 @@ export class AutoTLS implements AutoTLSInterface {

// emit a certificate event
this.log('dispatching %s', event)
this.events.safeDispatchEvent(event, {
this.components.events.safeDispatchEvent(event, {
detail: {
...this.certificate
}
Expand All @@ -247,7 +234,7 @@ export class AutoTLS implements AutoTLSInterface {
const cert = new X509Certificate(pem)

// cache cert
await this.datastore.put(new Key(this.certificateDatastoreKey), uint8ArrayFromString(pem))
await this.components.datastore.put(new Key(this.certificateDatastoreKey), uint8ArrayFromString(pem))

return {
pem,
Expand All @@ -260,7 +247,7 @@ export class AutoTLS implements AutoTLSInterface {

try {
this.log.trace('try to load existing certificate')
const buf = await this.datastore.get(key)
const buf = await this.components.datastore.get(key)
const pem = uint8ArrayToString(buf)
const cert = new X509Certificate(pem)

Expand Down Expand Up @@ -297,7 +284,7 @@ export class AutoTLS implements AutoTLSInterface {
async fetchAcmeCertificate (csr: string, multiaddrs: Multiaddr[], options?: AbortOptions): Promise<string> {
const client = new acme.Client({
directoryUrl: this.acmeDirectory.toString(),
accountKey: await loadOrCreateKey(this.keychain, this.accountPrivateKeyName, this.accountPrivateKeyBits)
accountKey: await loadOrCreateKey(this.components.keychain, this.accountPrivateKeyName, this.accountPrivateKeyBits)
})

return client.auto({
Expand Down
2 changes: 1 addition & 1 deletion packages/auto-tls/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @packageDocumentation
*
* When a publicly dialable address is detected, use the p2p-forge service at
* https://registration.libp2p.direct to acquire a valid Let's Encrypted-backed
* https://registration.libp2p.direct to acquire a valid Let's Encrypt-backed
* TLS certificate, which the node can then use with the relevant transports.
*
* The node must be configured with a listener for at least one of the following
Expand Down

0 comments on commit c90984e

Please sign in to comment.