mirror of
https://github.com/vacp2p/nim-libp2p.git
synced 2026-01-10 12:58:05 -05:00
Compare commits
6 Commits
chore/rela
...
websocket-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e82c61bf53 | ||
|
|
437490efa0 | ||
|
|
71797fb9ee | ||
|
|
1c54746b83 | ||
|
|
eed555437d | ||
|
|
1f7e121fcb |
33
libp2p/autotls/mockservice.nim
Normal file
33
libp2p/autotls/mockservice.nim
Normal file
@@ -0,0 +1,33 @@
|
||||
import ./service, ./acme/client, ../peeridauth/client
|
||||
|
||||
import ../crypto/crypto, ../crypto/rsa, websock/websock
|
||||
|
||||
type MockAutotlsService* = ref object of AutotlsService
|
||||
mockedCert*: TLSCertificate
|
||||
mockedKey*: TLSPrivateKey
|
||||
|
||||
proc new*(
|
||||
T: typedesc[MockAutotlsService],
|
||||
rng: ref HmacDrbgContext = newRng(),
|
||||
config: AutotlsConfig = AutotlsConfig.new(),
|
||||
): T =
|
||||
T(
|
||||
acmeClient: ACMEClient.new(api = ACMEApi.new(acmeServerURL = config.acmeServerURL)),
|
||||
brokerClient: PeerIDAuthClient.new(),
|
||||
bearer: Opt.none(BearerToken),
|
||||
cert: Opt.none(AutotlsCert),
|
||||
certReady: newAsyncEvent(),
|
||||
config: config,
|
||||
rng: rng,
|
||||
)
|
||||
|
||||
proc getTLSPrivkey*(self: MockAutotlsService): TLSPrivateKey =
|
||||
self.mockedKey
|
||||
|
||||
method getCertWhenReady*(
|
||||
self: MockAutotlsService, timeout: Duration = DefaultWaitTimeout
|
||||
): Future[TLSCertificate] {.async: (raises: [AutoTLSError, CancelledError]).} =
|
||||
return self.mockedCert
|
||||
|
||||
method setup*(self: MockAutotlsService) {.base, async.} =
|
||||
discard
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import net, results, json, sequtils
|
||||
|
||||
import chronos/apps/http/httpclient, chronos, chronicles, bearssl/rand
|
||||
import chronos/apps/http/httpclient, chronos, chronicles, bearssl/rand, bearssl/pem
|
||||
|
||||
import
|
||||
./acme/client,
|
||||
@@ -23,7 +23,9 @@ import
|
||||
../peerinfo,
|
||||
../switch,
|
||||
../utils/heartbeat,
|
||||
../wire
|
||||
../wire,
|
||||
../crypto/crypto,
|
||||
../crypto/rsa
|
||||
|
||||
logScope:
|
||||
topics = "libp2p autotls"
|
||||
@@ -39,6 +41,10 @@ const
|
||||
]
|
||||
DefaultRenewCheckTime* = 1.hours
|
||||
DefaultRenewBufferTime = 1.hours
|
||||
DefaultMaCheckTime = 1.seconds
|
||||
DefaultIssueRetryTime = 10.seconds
|
||||
DefaultIssueRetryAttemps = 6
|
||||
DefaultWaitTimeout* = 3.seconds
|
||||
|
||||
AutoTLSBroker* = "registration.libp2p.direct"
|
||||
AutoTLSDNSServer* = "libp2p.direct"
|
||||
@@ -61,27 +67,24 @@ type AutotlsConfig* = ref object
|
||||
ipAddress: Opt[IpAddress]
|
||||
renewCheckTime*: Duration
|
||||
renewBufferTime*: Duration
|
||||
maCheckTime: Duration
|
||||
issueRetryTime: Duration
|
||||
issueRetryAttemps: int
|
||||
|
||||
type AutotlsService* = ref object of Service
|
||||
acmeClient: ACMEClient
|
||||
acmeClient*: ACMEClient
|
||||
bearer*: Opt[BearerToken]
|
||||
brokerClient: PeerIDAuthClient
|
||||
brokerClient*: PeerIDAuthClient
|
||||
cert*: Opt[AutotlsCert]
|
||||
certReady*: AsyncEvent
|
||||
config: AutotlsConfig
|
||||
config*: AutotlsConfig
|
||||
managerFut: Future[void]
|
||||
peerInfo: PeerInfo
|
||||
rng: ref HmacDrbgContext
|
||||
rng*: ref HmacDrbgContext
|
||||
|
||||
proc new*(T: typedesc[AutotlsCert], cert: TLSCertificate, expiry: Moment): T =
|
||||
T(cert: cert, expiry: expiry)
|
||||
|
||||
proc getCertWhenReady*(
|
||||
self: AutotlsService
|
||||
): Future[TLSCertificate] {.async: (raises: [AutoTLSError, CancelledError]).} =
|
||||
await self.certReady.wait()
|
||||
return self.cert.get.cert
|
||||
|
||||
proc new*(
|
||||
T: typedesc[AutotlsConfig],
|
||||
ipAddress: Opt[IpAddress] = NoneIp,
|
||||
@@ -89,6 +92,9 @@ proc new*(
|
||||
acmeServerURL: Uri = parseUri(LetsEncryptURL),
|
||||
renewCheckTime: Duration = DefaultRenewCheckTime,
|
||||
renewBufferTime: Duration = DefaultRenewBufferTime,
|
||||
maCheckTime: Duration = DefaultMaCheckTime,
|
||||
issueRetryTime: Duration = DefaultIssueRetryTime,
|
||||
issueRetryAttemps: int = DefaultIssueRetryAttemps,
|
||||
): T =
|
||||
T(
|
||||
dnsResolver: DnsResolver.new(nameServers),
|
||||
@@ -96,6 +102,9 @@ proc new*(
|
||||
ipAddress: ipAddress,
|
||||
renewCheckTime: renewCheckTime,
|
||||
renewBufferTime: renewBufferTime,
|
||||
maCheckTime: maCheckTime,
|
||||
issueRetryTime: issueRetryTime,
|
||||
issueRetryAttemps: issueRetryAttemps,
|
||||
)
|
||||
|
||||
proc new*(
|
||||
@@ -115,6 +124,117 @@ proc new*(
|
||||
rng: rng,
|
||||
)
|
||||
|
||||
method getCertWhenReady*(
|
||||
self: AutotlsService, timeout: Duration = DefaultWaitTimeout
|
||||
): Future[TLSCertificate] {.base, async: (raises: [AutoTLSError, CancelledError]).} =
|
||||
# if await self.certReady.wait().withTimeout(timeout):
|
||||
await self.certReady.wait()
|
||||
self.certReady.clear()
|
||||
return self.cert.get.cert
|
||||
# raise newException(CancelledError, "timed out waiting for cert to be ready")
|
||||
|
||||
method getTLSPrivkey*(
|
||||
self: AutotlsService
|
||||
): TLSPrivateKey {.base, gcsafe, raises: [AutoTLSError, TLSStreamProtocolError].} =
|
||||
let derPrivKey =
|
||||
try:
|
||||
self.acmeClient.key.seckey.rsakey.getBytes.get
|
||||
except ValueError as exc:
|
||||
raise newException(AutoTLSError, "Unable to get TLS private key", exc)
|
||||
let pemPrivKey: string = pemEncode(derPrivKey, "PRIVATE KEY")
|
||||
TLSPrivateKey.init(pemPrivKey)
|
||||
|
||||
method issueCertificate(
|
||||
self: AutotlsService
|
||||
): Future[bool] {.
|
||||
base, async: (raises: [AutoTLSError, ACMEError, PeerIDAuthError, CancelledError])
|
||||
.} =
|
||||
trace "Issuing certificate"
|
||||
|
||||
if self.peerInfo.isNil():
|
||||
error "peerInfo not set"
|
||||
return false
|
||||
|
||||
# generate autotls domain string: "*.{peerID}.libp2p.direct"
|
||||
let baseDomain =
|
||||
api.Domain(encodePeerId(self.peerInfo.peerId) & "." & AutoTLSDNSServer)
|
||||
let domain = api.Domain("*." & baseDomain)
|
||||
|
||||
let acmeClient = self.acmeClient
|
||||
|
||||
trace "Requesting ACME challenge"
|
||||
let dns01Challenge = await acmeClient.getChallenge(@[domain])
|
||||
let keyAuth = acmeClient.genKeyAuthorization(dns01Challenge.dns01.token)
|
||||
let strMultiaddresses: seq[string] = self.peerInfo.addrs.mapIt($it)
|
||||
echo strMultiaddresses
|
||||
let payload = %*{"value": keyAuth, "addresses": strMultiaddresses}
|
||||
let registrationURL = parseUri("https://" & AutoTLSBroker & "/v1/_acme-challenge")
|
||||
|
||||
trace "Sending challenge to AutoTLS broker"
|
||||
# before this runs we need to make sure mutiaddresses are available
|
||||
let (bearer, response) =
|
||||
await self.brokerClient.send(registrationURL, self.peerInfo, payload, self.bearer)
|
||||
debug "Broker response", status = response.status
|
||||
if response.status != HttpOk:
|
||||
error "Failed to authenticate with AutoTLS Broker"
|
||||
return false
|
||||
if self.bearer.isNone():
|
||||
# save bearer token for future
|
||||
self.bearer = Opt.some(bearer)
|
||||
|
||||
trace "Waiting for DNS record to be set"
|
||||
let dnsSet = await checkDNSRecords(
|
||||
self.config.dnsResolver, self.config.ipAddress.get(), baseDomain, keyAuth
|
||||
)
|
||||
if not dnsSet:
|
||||
error "DNS records not set"
|
||||
return false
|
||||
|
||||
trace "Notifying challenge completion to ACME and downloading cert"
|
||||
let certResponse = await acmeClient.getCertificate(domain, dns01Challenge)
|
||||
|
||||
trace "Installing certificate"
|
||||
let newCert =
|
||||
try:
|
||||
AutotlsCert.new(
|
||||
TLSCertificate.init(certResponse.rawCertificate),
|
||||
asMoment(certResponse.certificateExpiry),
|
||||
)
|
||||
except TLSStreamProtocolError:
|
||||
raise newException(AutoTLSError, "Could not parse downloaded certificates")
|
||||
self.cert = Opt.some(newCert)
|
||||
self.certReady.fire()
|
||||
trace "Certificate installed"
|
||||
return true
|
||||
|
||||
proc issueWithRetries(
|
||||
self: AutotlsService
|
||||
): Future[bool] {.async: (raises: [CancelledError]).} =
|
||||
for _ in 0 ..< self.config.issueRetryAttemps:
|
||||
try:
|
||||
if await self.issueCertificate():
|
||||
return true
|
||||
await sleepAsync(self.config.issueRetryTime)
|
||||
except CancelledError as exc:
|
||||
raise exc
|
||||
except CatchableError as exc:
|
||||
error "Failed to issue certificate", err = exc.msg
|
||||
break
|
||||
return false
|
||||
|
||||
proc manage(self: AutotlsService) {.async: (raises: [CancelledError]).} =
|
||||
heartbeat "Certificate Management", self.config.renewCheckTime:
|
||||
if self.cert.isNone():
|
||||
if not await self.issueWithRetries():
|
||||
return
|
||||
|
||||
# AutotlsService will renew the cert 1h before it expires
|
||||
let cert = self.cert.get
|
||||
let waitTime = cert.expiry - Moment.now - self.config.renewBufferTime
|
||||
if waitTime <= self.config.renewBufferTime:
|
||||
if not await self.issueWithRetries():
|
||||
return
|
||||
|
||||
method setup*(
|
||||
self: AutotlsService, switch: Switch
|
||||
): Future[bool] {.async: (raises: [CancelledError]).} =
|
||||
@@ -128,89 +248,9 @@ method setup*(
|
||||
except AutoTLSError as exc:
|
||||
error "Failed to get public IP address", err = exc.msg
|
||||
return false
|
||||
self.managerFut = self.run(switch)
|
||||
self.managerFut = self.manage()
|
||||
return hasBeenSetup
|
||||
|
||||
method issueCertificate(
|
||||
self: AutotlsService
|
||||
) {.base, async: (raises: [AutoTLSError, ACMEError, PeerIDAuthError, CancelledError]).} =
|
||||
trace "Issuing certificate"
|
||||
|
||||
assert not self.peerInfo.isNil(), "Cannot issue new certificate: peerInfo not set"
|
||||
|
||||
# generate autotls domain string: "*.{peerID}.libp2p.direct"
|
||||
let baseDomain =
|
||||
api.Domain(encodePeerId(self.peerInfo.peerId) & "." & AutoTLSDNSServer)
|
||||
let domain = api.Domain("*." & baseDomain)
|
||||
|
||||
let acmeClient = self.acmeClient
|
||||
|
||||
trace "Requesting ACME challenge"
|
||||
let dns01Challenge = await acmeClient.getChallenge(@[domain])
|
||||
let keyAuth = acmeClient.genKeyAuthorization(dns01Challenge.dns01.token)
|
||||
let strMultiaddresses: seq[string] = self.peerInfo.addrs.mapIt($it)
|
||||
let payload = %*{"value": keyAuth, "addresses": strMultiaddresses}
|
||||
let registrationURL = parseUri("https://" & AutoTLSBroker & "/v1/_acme-challenge")
|
||||
|
||||
trace "Sending challenge to AutoTLS broker"
|
||||
let (bearer, response) =
|
||||
await self.brokerClient.send(registrationURL, self.peerInfo, payload, self.bearer)
|
||||
if self.bearer.isNone():
|
||||
# save bearer token for future
|
||||
self.bearer = Opt.some(bearer)
|
||||
if response.status != HttpOk:
|
||||
raise newException(
|
||||
AutoTLSError, "Failed to authenticate with AutoTLS Broker at " & AutoTLSBroker
|
||||
)
|
||||
|
||||
debug "Waiting for DNS record to be set"
|
||||
let dnsSet = await checkDNSRecords(
|
||||
self.config.dnsResolver, self.config.ipAddress.get(), baseDomain, keyAuth
|
||||
)
|
||||
if not dnsSet:
|
||||
raise newException(AutoTLSError, "DNS records not set")
|
||||
|
||||
debug "Notifying challenge completion to ACME and downloading cert"
|
||||
let certResponse = await acmeClient.getCertificate(domain, dns01Challenge)
|
||||
|
||||
debug "Installing certificate"
|
||||
let newCert =
|
||||
try:
|
||||
AutotlsCert.new(
|
||||
TLSCertificate.init(certResponse.rawCertificate),
|
||||
asMoment(certResponse.certificateExpiry),
|
||||
)
|
||||
except TLSStreamProtocolError:
|
||||
raise newException(AutoTLSError, "Could not parse downloaded certificates")
|
||||
self.cert = Opt.some(newCert)
|
||||
self.certReady.fire()
|
||||
debug "Certificate installed"
|
||||
|
||||
method run*(
|
||||
self: AutotlsService, switch: Switch
|
||||
) {.async: (raises: [CancelledError]).} =
|
||||
heartbeat "Certificate Management", self.config.renewCheckTime:
|
||||
if self.cert.isNone():
|
||||
try:
|
||||
await self.issueCertificate()
|
||||
except CancelledError as exc:
|
||||
raise exc
|
||||
except CatchableError as exc:
|
||||
error "Failed to issue certificate", err = exc.msg
|
||||
break
|
||||
|
||||
# AutotlsService will renew the cert 1h before it expires
|
||||
let cert = self.cert.get
|
||||
let waitTime = cert.expiry - Moment.now - self.config.renewBufferTime
|
||||
if waitTime <= self.config.renewBufferTime:
|
||||
try:
|
||||
await self.issueCertificate()
|
||||
except CancelledError as exc:
|
||||
raise exc
|
||||
except CatchableError as exc:
|
||||
error "Failed to renew certificate", err = exc.msg
|
||||
break
|
||||
|
||||
method stop*(
|
||||
self: AutotlsService, switch: Switch
|
||||
): Future[bool] {.async: (raises: [CancelledError]).} =
|
||||
|
||||
@@ -185,7 +185,7 @@ proc withWsTransport*(
|
||||
): SwitchBuilder =
|
||||
b.withTransport(
|
||||
proc(upgr: Upgrade, privateKey: PrivateKey, autotls: AutotlsService): Transport =
|
||||
WsTransport.new(upgr, tlsPrivateKey, tlsCertificate, tlsFlags, flags)
|
||||
WsTransport.new(upgr, tlsPrivateKey, tlsCertificate, autotls, tlsFlags, flags)
|
||||
)
|
||||
|
||||
when defined(libp2p_quic_support):
|
||||
|
||||
@@ -302,6 +302,8 @@ proc sendWithoutBearer(
|
||||
):
|
||||
raise newException(PeerIDAuthError, "Failed to validate server's signature")
|
||||
|
||||
echo $authorizationResponse.response
|
||||
echo $authorizationResponse.response.status
|
||||
return (authorizationResponse.bearer, authorizationResponse.response)
|
||||
|
||||
proc sendWithBearer(
|
||||
|
||||
@@ -31,7 +31,7 @@ type RelayTransport* = ref object of Transport
|
||||
|
||||
method start*(
|
||||
self: RelayTransport, ma: seq[MultiAddress]
|
||||
) {.async: (raises: [LPError, transport.TransportError]).} =
|
||||
) {.async: (raises: [LPError, transport.TransportError, CancelledError]).} =
|
||||
if self.selfRunning:
|
||||
trace "Relay transport already running"
|
||||
return
|
||||
|
||||
@@ -344,8 +344,11 @@ proc start*(s: Switch) {.public, async: (raises: [CancelledError, LPError]).} =
|
||||
return
|
||||
|
||||
debug "starting switch for peer", peerInfo = s.peerInfo
|
||||
|
||||
var startFuts: seq[Future[void]]
|
||||
for t in s.transports:
|
||||
echo "here1"
|
||||
echo s.peerInfo.listenAddrs
|
||||
let addrs = s.peerInfo.listenAddrs.filterIt(t.handles(it))
|
||||
|
||||
s.peerInfo.listenAddrs.keepItIf(it notin addrs)
|
||||
@@ -365,10 +368,11 @@ proc start*(s: Switch) {.public, async: (raises: [CancelledError, LPError]).} =
|
||||
s.acceptFuts.add(s.accept(t))
|
||||
s.peerInfo.listenAddrs &= t.addrs
|
||||
|
||||
await s.peerInfo.update()
|
||||
|
||||
for service in s.services:
|
||||
discard await service.setup(s)
|
||||
|
||||
await s.peerInfo.update()
|
||||
await s.ms.start()
|
||||
s.started = true
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ proc listenAddress(self: MemoryTransport, ma: MultiAddress): MultiAddress =
|
||||
|
||||
method start*(
|
||||
self: MemoryTransport, addrs: seq[MultiAddress]
|
||||
) {.async: (raises: [LPError, transport.TransportError]).} =
|
||||
) {.async: (raises: [LPError, transport.TransportError, CancelledError]).} =
|
||||
if self.running:
|
||||
return
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ method handles*(transport: QuicTransport, address: MultiAddress): bool {.raises:
|
||||
|
||||
method start*(
|
||||
self: QuicTransport, addrs: seq[MultiAddress]
|
||||
) {.async: (raises: [LPError, transport.TransportError]).} =
|
||||
) {.async: (raises: [LPError, transport.TransportError, CancelledError]).} =
|
||||
doAssert self.listener.isNil, "start() already called"
|
||||
#TODO handle multiple addr
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ proc new*(
|
||||
|
||||
method start*(
|
||||
self: TcpTransport, addrs: seq[MultiAddress]
|
||||
): Future[void] {.async: (raises: [LPError, transport.TransportError]).} =
|
||||
): Future[void] {.async: (raises: [LPError, transport.TransportError, CancelledError]).} =
|
||||
## Start transport listening to the given addresses - for dial-only transports,
|
||||
## start with an empty list
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ method dial*(
|
||||
|
||||
method start*(
|
||||
self: TorTransport, addrs: seq[MultiAddress]
|
||||
) {.async: (raises: [LPError, transport.TransportError]).} =
|
||||
) {.async: (raises: [LPError, transport.TransportError, CancelledError]).} =
|
||||
## listen on the transport
|
||||
##
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ proc newTransportClosedError*(parent: ref Exception = nil): ref TransportError =
|
||||
|
||||
method start*(
|
||||
self: Transport, addrs: seq[MultiAddress]
|
||||
) {.base, async: (raises: [LPError, TransportError]).} =
|
||||
) {.base, async: (raises: [LPError, TransportError, CancelledError]).} =
|
||||
## start the transport
|
||||
##
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import results
|
||||
import chronos, chronicles
|
||||
import
|
||||
transport,
|
||||
../autotls/service,
|
||||
../errors,
|
||||
../wire,
|
||||
../multicodec,
|
||||
@@ -108,8 +109,9 @@ type WsTransport* = ref object of Transport
|
||||
|
||||
acceptFuts: seq[Future[HttpRequest]]
|
||||
|
||||
tlsPrivateKey: TLSPrivateKey
|
||||
tlsCertificate: TLSCertificate
|
||||
tlsPrivateKey*: TLSPrivateKey
|
||||
tlsCertificate*: TLSCertificate
|
||||
autotls: AutotlsService
|
||||
tlsFlags: set[TLSFlags]
|
||||
flags: set[ServerFlags]
|
||||
handshakeTimeout: Duration
|
||||
@@ -121,7 +123,7 @@ proc secure*(self: WsTransport): bool =
|
||||
|
||||
method start*(
|
||||
self: WsTransport, addrs: seq[MultiAddress]
|
||||
) {.async: (raises: [LPError, transport.TransportError]).} =
|
||||
) {.async: (raises: [LPError, transport.TransportError, CancelledError]).} =
|
||||
## listen on the transport
|
||||
##
|
||||
|
||||
@@ -132,6 +134,20 @@ method start*(
|
||||
await procCall Transport(self).start(addrs)
|
||||
trace "Starting WS transport"
|
||||
|
||||
# use autotls if possible (and if cert/key not specified)
|
||||
if not self.secure and not self.autotls.isNil():
|
||||
try:
|
||||
echo "cert.isSome() == " & $self.autotls.cert.isSome()
|
||||
echo "before getCertWhenReady"
|
||||
self.tlsCertificate = await self.autotls.getCertWhenReady()
|
||||
echo "after getCertWhenReady"
|
||||
self.tlsPrivateKey = self.autotls.getTLSPrivkey()
|
||||
echo "after getTLSPrivkey"
|
||||
except AutoTLSError as exc:
|
||||
raise newException(LPError, exc.msg, exc)
|
||||
except TLSStreamProtocolError as exc:
|
||||
raise newException(LPError, exc.msg, exc)
|
||||
|
||||
self.wsserver = WSServer.new(factories = self.factories, rng = self.rng)
|
||||
|
||||
for i, ma in addrs:
|
||||
@@ -356,6 +372,7 @@ proc new*(
|
||||
upgrade: Upgrade,
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate,
|
||||
autotls: AutotlsService,
|
||||
tlsFlags: set[TLSFlags] = {},
|
||||
flags: set[ServerFlags] = {},
|
||||
factories: openArray[ExtFactory] = [],
|
||||
@@ -368,6 +385,7 @@ proc new*(
|
||||
upgrader: upgrade,
|
||||
tlsPrivateKey: tlsPrivateKey,
|
||||
tlsCertificate: tlsCertificate,
|
||||
autotls: autotls,
|
||||
tlsFlags: tlsFlags,
|
||||
flags: flags,
|
||||
factories: @factories,
|
||||
@@ -389,6 +407,7 @@ proc new*(
|
||||
upgrade = upgrade,
|
||||
tlsPrivateKey = nil,
|
||||
tlsCertificate = nil,
|
||||
autotls = nil,
|
||||
flags = flags,
|
||||
factories = @factories,
|
||||
rng = rng,
|
||||
|
||||
@@ -10,4 +10,4 @@ when defined(linux) and defined(amd64):
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import testpeeridauth_integration, testautotls_integration
|
||||
import testpeeridauth_integration, testautotls_integration, testwstransport_integration
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
import chronos, stew/byteutils
|
||||
import
|
||||
../libp2p/[
|
||||
autotls/service,
|
||||
autotls/mockservice,
|
||||
stream/connection,
|
||||
transports/transport,
|
||||
transports/wstransport,
|
||||
@@ -23,6 +25,98 @@ import
|
||||
import ./helpers, ./commontransport
|
||||
|
||||
const
|
||||
AutoTLSCertificate =
|
||||
"""
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID5DCCA2mgAwIBAgISLHPA5xRAjh3ZwYmBw4ISA+7LMAoGCCqGSM49BAMDMFIx
|
||||
CzAJBgNVBAYTAlVTMSAwHgYDVQQKExcoU1RBR0lORykgTGV0J3MgRW5jcnlwdDEh
|
||||
MB8GA1UEAxMYKFNUQUdJTkcpIFBzZXVkbyBQbHVtIEU1MB4XDTI1MDcwMjE3NDQ1
|
||||
M1oXDTI1MDkzMDE3NDQ1MlowADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAh4
|
||||
VNa76Ycl6RpoZ2qfM7biZzC/nz4G7lArKBMPyMUh0EX6U22VaZdxOvTfglRUxtJa
|
||||
NMleBtUhDcZd4HCkNZGjggJvMIICazAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYw
|
||||
FAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFJgN
|
||||
WGKp9N/2bWsjD2ugSkt/8jlBMB8GA1UdIwQYMBaAFPxG0QFDX7t7pj0waK4RuuC8
|
||||
bcnTMDYGCCsGAQUFBwEBBCowKDAmBggrBgEFBQcwAoYaaHR0cDovL3N0Zy1lNS5p
|
||||
LmxlbmNyLm9yZy8wXAYDVR0RAQH/BFIwUIJOKi5rNTFxemk1dXF1NWRoOGRpY3ps
|
||||
bzJwZDc3djBic2Vkb2tzaXo1dnk4ZXF3MnJwaWpnZ2ozdzlnNm81ejlpcy5saWJw
|
||||
MnAuZGlyZWN0MBMGA1UdIAQMMAowCAYGZ4EMAQIBMDEGA1UdHwQqMCgwJqAkoCKG
|
||||
IGh0dHA6Ly9zdGctZTUuYy5sZW5jci5vcmcvNzYuY3JsMIIBDAYKKwYBBAHWeQIE
|
||||
AgSB/QSB+gD4AHYA3Zk0/KXnJIDJVmh9gTSZCEmySfe1adjHvKs/XMHzbmQAAAGX
|
||||
zHNiGAAABAMARzBFAiBVH0V4L9LG5ksU+hOvFVgT51WUpStneTVwdSdOGbdm6gIh
|
||||
ANdv5EQZI1vOVxok4D1lh1Z7hS7nfTG5HCIBbZ19iAKOAH4A2KJiliJSBM2181NJ
|
||||
WC5O1mWiRRsPJ6i2iWE2s7n8BwgAAAGXzHNnWwAIAAAFAD6beWUEAwBHMEUCIAOv
|
||||
AXuiujBNXne+BzzivJGbr3F0wKK7xhxIBfr/jGgyAiEA/xpSIMMcxZmH5Q4UlZj+
|
||||
EH9kAlEXwmI/MFemd7pdH54wCgYIKoZIzj0EAwMDaQAwZgIxAJXdmvcIxiLPx33H
|
||||
4WgXbDfjzZHiqyn+5t+73GZUDfyVotuiOvoRPpAp0L+WRS33iQIxAPWcAtrmyb7M
|
||||
/BXH2ccVFRUtAJTxajwBcN9un7GJUIAb9Fbz6EOBGTT7pukEc155Zw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEljCCAn6gAwIBAgIQRzEp1D1mDiVVv4b1zlB56jANBgkqhkiG9w0BAQsFADBm
|
||||
MQswCQYDVQQGEwJVUzEzMDEGA1UEChMqKFNUQUdJTkcpIEludGVybmV0IFNlY3Vy
|
||||
aXR5IFJlc2VhcmNoIEdyb3VwMSIwIAYDVQQDExkoU1RBR0lORykgUHJldGVuZCBQ
|
||||
ZWFyIFgxMB4XDTI0MDMxMzAwMDAwMFoXDTI3MDMxMjIzNTk1OVowUjELMAkGA1UE
|
||||
BhMCVVMxIDAeBgNVBAoTFyhTVEFHSU5HKSBMZXQncyBFbmNyeXB0MSEwHwYDVQQD
|
||||
ExgoU1RBR0lORykgUHNldWRvIFBsdW0gRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
|
||||
AATljbbcV+mqWZa3g+z0bDOuBpZOtbi48iK9rjLtPdRU0WsgVp53MW3nXFU6qVYV
|
||||
zEYaYd6PSmec0Tj3R5zEp5/F+cuOjTdh3AkTMzYm1tkflocPBN5APHYZ+76WxZad
|
||||
q+WjggEAMIH9MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAgYI
|
||||
KwYBBQUHAwEwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU/EbRAUNfu3um
|
||||
PTBorhG64LxtydMwHwYDVR0jBBgwFoAUtfNl8v6wCpIf+zx980SgrGMlwxQwNgYI
|
||||
KwYBBQUHAQEEKjAoMCYGCCsGAQUFBzAChhpodHRwOi8vc3RnLXgxLmkubGVuY3Iu
|
||||
b3JnLzATBgNVHSAEDDAKMAgGBmeBDAECATArBgNVHR8EJDAiMCCgHqAchhpodHRw
|
||||
Oi8vc3RnLXgxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAAtCGn4iG
|
||||
cupruhkCTcoDqSIVTFgVR8JJ3GvGL7SYwIc4Fn0As66nQgnkATIzF5+gFb+CXEQD
|
||||
qR2Jo+R38OeT7lQ1rNDcaJcbY6hL8cNRku3QlcfdYODZ5pgTVH04gTZUJISZKLjD
|
||||
kMMcQIDZlF7iYqTvmHbn2ISSKorsJ3QKAvWhHwMoJtocSz3VeDJIep5QtbHnoXh1
|
||||
/dyDx7sp8RuhC0eO9ElTgDtiA2V6JxigLPzqcnibBBR4bFLGtMNE4EvOOD/Fkd0L
|
||||
hdGDbAMNd+O06n+b0rgmDvg75IgOV6fpDrdZFoiNfCckOEJh9v10uYt4pTc3B6lf
|
||||
zI/X3EWP1H4VJmsYuy+OA29jPeP831sAObZtd3RWv0LQPrMfx6FCmy4AaeYEMvul
|
||||
FrF6OX+JbssE+bn83F+sGEMZu/eVBwwKh3db7+2UduMdTOb8DePE3Aqlg9zofS8X
|
||||
9fJXrrp+PPrdQyvM3e8DxuioWa9GLG30yD9WD6WTlSiiOrdWGOzisWpW4shFoL8u
|
||||
0EfmeLVU4JVbauhOYZASQXABNeXewe9lqJWwfqaARYpRjyf+jRibn22H5NVK4Vog
|
||||
l55Iq1rUgjc8r493NaNrlNwG7va7Ztkch5lJ3oL/FEVlVSK4snTbgb0b5qjQz3SA
|
||||
i7rA/8QRZvOLnKNtdEUlDZNrzkZwHNluLGw=
|
||||
-----END CERTIFICATE-----
|
||||
"""
|
||||
|
||||
AutoTLSKey =
|
||||
"""
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
-----END PRIVATE KEY-----
|
||||
"""
|
||||
|
||||
SecureKey =
|
||||
"""
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
@@ -78,6 +172,7 @@ suite "WebSocket transport":
|
||||
Upgrade(),
|
||||
TLSPrivateKey.init(SecureKey),
|
||||
TLSCertificate.init(SecureCert),
|
||||
nil, # autotls
|
||||
{TLSFlags.NoVerifyHost, TLSFlags.NoVerifyServerName},
|
||||
)
|
||||
except CatchableError:
|
||||
@@ -91,6 +186,7 @@ suite "WebSocket transport":
|
||||
Upgrade(),
|
||||
TLSPrivateKey.init(SecureKey),
|
||||
TLSCertificate.init(SecureCert),
|
||||
nil, # autotls
|
||||
{TLSFlags.NoVerifyHost},
|
||||
)
|
||||
|
||||
@@ -136,3 +232,72 @@ suite "WebSocket transport":
|
||||
await closing
|
||||
|
||||
await transport1.stop()
|
||||
|
||||
asyncTest "autotls certificate is used when manual tlscertificate is not specified":
|
||||
let ma = @[MultiAddress.init("/ip4/0.0.0.0/tcp/0/tls/ws").tryGet()]
|
||||
|
||||
let autotls = MockAutotlsService.new()
|
||||
autotls.mockedKey = TLSPrivateKey.init(AutoTLSKey)
|
||||
autotls.mockedCert = TLSCertificate.init(AutoTLSCertificate)
|
||||
await autotls.setup()
|
||||
|
||||
let wstransport = WsTransport.new(
|
||||
Upgrade(),
|
||||
nil, # TLSPrivateKey
|
||||
nil, # TLSCertificate
|
||||
autotls,
|
||||
{TLSFlags.NoVerifyHost, TLSFlags.NoVerifyServerName},
|
||||
)
|
||||
await wstransport.start(ma)
|
||||
defer:
|
||||
await wstransport.stop()
|
||||
|
||||
# TLSPrivateKey and TLSCertificate should be set
|
||||
check wstransport.secure
|
||||
|
||||
# autotls should be used
|
||||
check wstransport.tlsCertificate == await autotls.getCertWhenReady()
|
||||
|
||||
asyncTest "manually set tlscertificate is preferred over autotls when both are specified":
|
||||
let ma = @[MultiAddress.init("/ip4/0.0.0.0/tcp/0/tls/ws").tryGet()]
|
||||
|
||||
let autotls = MockAutotlsService.new()
|
||||
autotls.mockedKey = TLSPrivateKey.init(AutoTLSKey)
|
||||
autotls.mockedCert = TLSCertificate.init(AutoTLSCertificate)
|
||||
await autotls.setup()
|
||||
let secureCert = TLSCertificate.init(SecureCert)
|
||||
let secureKey = TLSPrivateKey.init(SecureKey)
|
||||
|
||||
let wstransport = WsTransport.new(
|
||||
Upgrade(),
|
||||
secureKey,
|
||||
secureCert,
|
||||
autotls,
|
||||
{TLSFlags.NoVerifyHost, TLSFlags.NoVerifyServerName},
|
||||
)
|
||||
await wstransport.start(ma)
|
||||
defer:
|
||||
await wstransport.stop()
|
||||
|
||||
# TLSPrivateKey and TLSCertificate should be set
|
||||
check wstransport.secure
|
||||
|
||||
# autotls should be ignored
|
||||
check wstransport.tlsCertificate == secureCert
|
||||
check wstransport.tlsPrivateKey == secureKey
|
||||
|
||||
asyncTest "wstransport is not secure when both manual tlscertificate and autotls are not specified":
|
||||
let ma = @[MultiAddress.init("/ip4/0.0.0.0/tcp/0/tls/ws").tryGet()]
|
||||
let wstransport = WsTransport.new(
|
||||
Upgrade(),
|
||||
nil, # TLSPrivateKey
|
||||
nil, # TLSCertificate
|
||||
nil, # autotls
|
||||
{TLSFlags.NoVerifyHost, TLSFlags.NoVerifyServerName},
|
||||
)
|
||||
await wstransport.start(ma)
|
||||
defer:
|
||||
await wstransport.stop()
|
||||
|
||||
# TLSPrivateKey and TLSCertificate should not be set
|
||||
check not wstransport.secure
|
||||
|
||||
83
tests/testwstransport_integration.nim
Normal file
83
tests/testwstransport_integration.nim
Normal file
@@ -0,0 +1,83 @@
|
||||
{.used.}
|
||||
|
||||
# Nim-Libp2p
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
import chronos
|
||||
import chronos/apps/http/httpclient
|
||||
import
|
||||
../libp2p/[
|
||||
stream/connection,
|
||||
upgrademngrs/upgrade,
|
||||
autotls/acme/client,
|
||||
autotls/service,
|
||||
autotls/utils,
|
||||
multiaddress,
|
||||
switch,
|
||||
builders,
|
||||
wire,
|
||||
protocols/ping,
|
||||
]
|
||||
|
||||
from ./helpers import suite, asyncTest, asyncTeardown, checkTrackers, skip, check
|
||||
|
||||
suite "WebSocket transport integration":
|
||||
teardown:
|
||||
checkTrackers()
|
||||
|
||||
asyncTest "autotls certificate is used when manual tlscertificate is not specified":
|
||||
try:
|
||||
discard getPublicIPAddress()
|
||||
except:
|
||||
skip() # host doesn't have public IPv4 address
|
||||
return
|
||||
|
||||
let pingProtocol = Ping.new(rng = newRng())
|
||||
|
||||
let switch1 = SwitchBuilder
|
||||
.new()
|
||||
.withRng(newRng())
|
||||
.withAddress(MultiAddress.init("/ip4/0.0.0.0/tcp/0/wss").tryGet())
|
||||
.withTcpTransport()
|
||||
.withWsTransport()
|
||||
.withAutotls(
|
||||
config = AutotlsConfig.new(acmeServerURL = parseUri(LetsEncryptURLStaging))
|
||||
)
|
||||
.withYamux()
|
||||
.withNoise()
|
||||
.build()
|
||||
|
||||
# let switch2 = SwitchBuilder
|
||||
# .new()
|
||||
# .withRng(newRng())
|
||||
# .withAddress(MultiAddress.init("/ip4/0.0.0.0/tcp/0/wss").tryGet())
|
||||
# .withWsTransport()
|
||||
# .withAutotls(
|
||||
# config = AutotlsConfig.new(acmeServerURL = parseUri(LetsEncryptURLStaging))
|
||||
# )
|
||||
# .withYamux()
|
||||
# .withNoise()
|
||||
# .build()
|
||||
|
||||
await switch1.start()
|
||||
# await switch2.start()
|
||||
|
||||
# # should succeed
|
||||
# let conn =
|
||||
# await switch2.dial(switch1.peerInfo.peerId, switch1.peerInfo.addrs, PingCodec)
|
||||
# echo "7"
|
||||
# discard await pingProtocol.ping(conn)
|
||||
# echo "8"
|
||||
|
||||
defer:
|
||||
# await conn.close()
|
||||
await switch1.stop()
|
||||
# await switch2.stop()
|
||||
Reference in New Issue
Block a user