Skip to content

Commit

Permalink
feat: auto-tls for websockets (#2800)
Browse files Browse the repository at this point in the history
Starts a tcp server on the listen port and hands connections off to internal http or https servers (depdending on connection type).

Upgrade requests from both servers are handled by a websocket server.

The https server is enabled when either a secure websocket address is listened to explicitly, or when a TLS certificate is provisioned by another libp2p component, likely `@libp2p/auto-tls`.

This means we don't need to add another port mapping for the https server since we run http and https over the same port.
  • Loading branch information
achingbrain authored Nov 27, 2024
1 parent 4761dd7 commit 8a9258a
Show file tree
Hide file tree
Showing 5 changed files with 537 additions and 133 deletions.
3 changes: 2 additions & 1 deletion packages/transport-websockets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,11 @@
"@libp2p/utils": "^6.2.1",
"@multiformats/multiaddr": "^12.2.3",
"@multiformats/multiaddr-matcher": "^1.4.0",
"@multiformats/multiaddr-to-uri": "^10.0.1",
"@multiformats/multiaddr-to-uri": "^11.0.0",
"@types/ws": "^8.5.10",
"it-ws": "^6.1.1",
"p-defer": "^4.0.1",
"p-event": "^6.0.1",
"progress-events": "^1.0.0",
"race-signal": "^1.0.2",
"ws": "^8.17.0"
Expand Down
38 changes: 31 additions & 7 deletions packages/transport-websockets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ import { raceSignal } from 'race-signal'
import * as filters from './filters.js'
import { createListener } from './listener.js'
import { socketToMaConn } from './socket-to-conn.js'
import type { Transport, MultiaddrFilter, CreateListenerOptions, DialTransportOptions, Listener, AbortOptions, ComponentLogger, Logger, Connection, OutboundConnectionUpgradeEvents, Metrics, CounterGroup } from '@libp2p/interface'
import type { Transport, MultiaddrFilter, CreateListenerOptions, DialTransportOptions, Listener, AbortOptions, ComponentLogger, Logger, Connection, OutboundConnectionUpgradeEvents, Metrics, CounterGroup, TypedEventTarget, Libp2pEvents } from '@libp2p/interface'
import type { Multiaddr } from '@multiformats/multiaddr'
import type { Server } from 'http'
import type { DuplexWebSocket } from 'it-ws/duplex'
import type http from 'node:http'
import type https from 'node:https'
import type { ProgressEvent } from 'progress-events'
import type { ClientOptions } from 'ws'

Expand All @@ -44,12 +45,34 @@ export interface WebSocketsInit extends AbortOptions, WebSocketOptions {
* @deprecated Use a ConnectionGater instead
*/
filter?: MultiaddrFilter

/**
* Options used to create WebSockets
*/
websocket?: ClientOptions
server?: Server

/**
* Options used to create the HTTP server
*/
http?: http.ServerOptions

/**
* Options used to create the HTTPs server. `options.http` will be used if
* unspecified.
*/
https?: https.ServerOptions

/**
* Inbound connections must complete their upgrade within this many ms
*
* @default 5000
*/
inboundConnectionUpgradeTimeout?: number
}

export interface WebSocketsComponents {
logger: ComponentLogger
events: TypedEventTarget<Libp2pEvents>
metrics?: Metrics
}

Expand All @@ -63,12 +86,12 @@ export type WebSocketsDialEvents =

class WebSockets implements Transport<WebSocketsDialEvents> {
private readonly log: Logger
private readonly init?: WebSocketsInit
private readonly init: WebSocketsInit
private readonly logger: ComponentLogger
private readonly metrics?: WebSocketsMetrics
private readonly components: WebSocketsComponents

constructor (components: WebSocketsComponents, init?: WebSocketsInit) {
constructor (components: WebSocketsComponents, init: WebSocketsInit = {}) {
this.log = components.logger.forComponent('libp2p:websockets')
this.logger = components.logger
this.components = components
Expand Down Expand Up @@ -148,13 +171,14 @@ class WebSockets implements Transport<WebSocketsDialEvents> {
}

/**
* Creates a Websockets listener. The provided `handler` function will be called
* Creates a WebSockets listener. The provided `handler` function will be called
* anytime a new incoming Connection has been successfully upgraded via
* `upgrader.upgradeInbound`
*/
createListener (options: CreateListenerOptions): Listener {
return createListener({
logger: this.logger,
events: this.components.events,
metrics: this.components.metrics
}, {
...this.init,
Expand All @@ -163,7 +187,7 @@ class WebSockets implements Transport<WebSocketsDialEvents> {
}

/**
* Takes a list of `Multiaddr`s and returns only valid Websockets addresses.
* Takes a list of `Multiaddr`s and returns only valid WebSockets addresses.
* By default, in a browser environment only DNS+WSS multiaddr is accepted,
* while in a Node.js environment DNS+{WS, WSS} multiaddrs are accepted.
*/
Expand Down
Loading

0 comments on commit 8a9258a

Please sign in to comment.