Adds an upgradeTLS method to the conn objects returned by dial/accept, wrapping the existing net.Conn with crypto/tls in place — the explicit upgrade needed for STARTTLS (SMTP) and AUTH TLS (FTPS).
tlsClientConfigFromJS factored out of dialTLS (behavior unchanged); when no default server name is available (the upgrade case) it requires serverName unless insecureSkipVerify is set.
upgradeTLS(opts) on wrapped conns: client mode uses the same options as dialTLS (serverName, insecureSkipVerify, caCerts); server mode via isServer: true with certPem/keyPem (same parsing as listenTLS).
Returns a new wrapped conn sharing the same underlying net.Conn; the old handle must not be used afterward. On any failure — configuration (malformed PEM) or handshake — the underlying conn is closed (721194d, after external review: previously config errors left the conn open while the JS wrapper marked it closed, leaking it).
Consumed by the corresponding @webnet/transport / @webnet/tsconnect PR on the webnet repo (webnet/webnet#63), which provides the in-place RawTransport.upgradeTls semantics one layer up.
Adds an `upgradeTLS` method to the conn objects returned by `dial`/accept, wrapping the existing `net.Conn` with `crypto/tls` in place — the explicit upgrade needed for STARTTLS (SMTP) and AUTH TLS (FTPS).
- `tlsClientConfigFromJS` factored out of `dialTLS` (behavior unchanged); when no default server name is available (the upgrade case) it requires `serverName` unless `insecureSkipVerify` is set.
- `upgradeTLS(opts)` on wrapped conns: client mode uses the same options as `dialTLS` (`serverName`, `insecureSkipVerify`, `caCerts`); server mode via `isServer: true` with `certPem`/`keyPem` (same parsing as `listenTLS`).
- Returns a new wrapped conn sharing the same underlying `net.Conn`; the old handle must not be used afterward. On **any** failure — configuration (malformed PEM) or handshake — the underlying conn is closed (721194d, after external review: previously config errors left the conn open while the JS wrapper marked it closed, leaking it).
Consumed by the corresponding `@webnet/transport` / `@webnet/tsconnect` PR on the webnet repo (webnet/webnet#63), which provides the in-place `RawTransport.upgradeTls` semantics one layer up.
Adds an upgradeTLS method to the conn objects returned by dial/accept,
wrapping the existing net.Conn with crypto/tls in place (STARTTLS /
FTPS AUTH TLS style). Client mode reuses the dialTLS options
(serverName, insecureSkipVerify, caCerts), now factored into
tlsClientConfigFromJS; server mode takes isServer with certPem/keyPem.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfRgMke8p7QDxD5QM5thxH
Reviewed alongside webnet/webnet#63 (the consumer of upgradeTLS). The Go side here looks correct in isolation, but flagging for context: the new wrapConn(tlsConn) returned by upgradeTLS (around line 1484 in cmd/tsconnect/wasm/wasm_js.go) leaves the old wrapConn's read/write closures alive, still bound to the plain net.Conn that tls.Client/tls.Server now uses internally. That's fine as long as the JS caller strictly stops using the old handle the instant it calls upgradeTLS — but webnet/webnet#63's ipn.ts Conn.upgradeTls doesn't actually enforce that (it doesn't mark itself in-flight during the handshake), so a concurrent read()/write() from the JS side can still reach the old handle and race the handshake on the same fd. Posted the detailed finding and suggested fix on webnet#63; no action needed here unless you want to harden this side too (e.g. by having the old wrapConn's closures start erroring once superseded).
Reviewed alongside webnet/webnet#63 (the consumer of upgradeTLS). The Go side here looks correct in isolation, but flagging for context: the new `wrapConn(tlsConn)` returned by `upgradeTLS` (around line 1484 in cmd/tsconnect/wasm/wasm_js.go) leaves the *old* wrapConn's read/write closures alive, still bound to the plain `net.Conn` that `tls.Client`/`tls.Server` now uses internally. That's fine as long as the JS caller strictly stops using the old handle the instant it calls upgradeTLS — but webnet/webnet#63's `ipn.ts Conn.upgradeTls` doesn't actually enforce that (it doesn't mark itself in-flight during the handshake), so a concurrent read()/write() from the JS side can still reach the old handle and race the handshake on the same fd. Posted the detailed finding and suggested fix on webnet#63; no action needed here unless you want to harden this side too (e.g. by having the old wrapConn's closures start erroring once superseded).
Previously only a handshake failure closed the underlying conn;
configuration errors (malformed caCerts PEM, bad cert/key pair)
returned with the conn still open, while the JS wrapper treats every
upgradeTLS rejection as fatal and marks the conn closed — leaking a
live Go conn that could no longer be closed from JS. Close on every
error path so the JS contract (any rejection after validation is
fatal) holds.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XfRgMke8p7QDxD5QM5thxH
codinget
marked the pull request as ready for review 2026-07-12 15:10:44 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Adds an
upgradeTLSmethod to the conn objects returned bydial/accept, wrapping the existingnet.Connwithcrypto/tlsin place — the explicit upgrade needed for STARTTLS (SMTP) and AUTH TLS (FTPS).tlsClientConfigFromJSfactored out ofdialTLS(behavior unchanged); when no default server name is available (the upgrade case) it requiresserverNameunlessinsecureSkipVerifyis set.upgradeTLS(opts)on wrapped conns: client mode uses the same options asdialTLS(serverName,insecureSkipVerify,caCerts); server mode viaisServer: truewithcertPem/keyPem(same parsing aslistenTLS).net.Conn; the old handle must not be used afterward. On any failure — configuration (malformed PEM) or handshake — the underlying conn is closed (721194d, after external review: previously config errors left the conn open while the JS wrapper marked it closed, leaking it).Consumed by the corresponding
@webnet/transport/@webnet/tsconnectPR on the webnet repo (webnet/webnet#63), which provides the in-placeRawTransport.upgradeTlssemantics one layer up.Reviewed alongside webnet/webnet#63 (the consumer of upgradeTLS). The Go side here looks correct in isolation, but flagging for context: the new
wrapConn(tlsConn)returned byupgradeTLS(around line 1484 in cmd/tsconnect/wasm/wasm_js.go) leaves the old wrapConn's read/write closures alive, still bound to the plainnet.Connthattls.Client/tls.Servernow uses internally. That's fine as long as the JS caller strictly stops using the old handle the instant it calls upgradeTLS — but webnet/webnet#63'sipn.ts Conn.upgradeTlsdoesn't actually enforce that (it doesn't mark itself in-flight during the handshake), so a concurrent read()/write() from the JS side can still reach the old handle and race the handshake on the same fd. Posted the detailed finding and suggested fix on webnet#63; no action needed here unless you want to harden this side too (e.g. by having the old wrapConn's closures start erroring once superseded).