Skip to content

Commit fefb696

Browse files
fix: enforce secure truenas websocket api key transport (#94)
1 parent 6c5fde9 commit fefb696

File tree

3 files changed

+48
-16
lines changed

3 files changed

+48
-16
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
All notable changes to portracker will be documented in this file.
44

5+
## [Unreleased]
6+
7+
### Fixed
8+
9+
- **TrueNAS API Key Transport Security**: Enforced secure WebSocket usage for TrueNAS API key authentication by restricting secure mode to `wss://` endpoints and skipping insecure `ws://` endpoints.
10+
- **TrueNAS WebSocket Base Handling**: In secure mode, `TRUENAS_WS_BASE` now upgrades insecure `ws://` values to `wss://` and ignores insecure explicit URLs.
11+
512
## [1.3.4] - 2026-02-05
613

714
### Fixed

backend/lib/tn-ws.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,15 @@ async function connectWs(options = {}) {
9696

9797
isConnecting = true;
9898
const currentUrl = urls[i++];
99+
if (currentUrl.startsWith("ws://")) {
100+
if (appDebugEnabled) {
101+
debugWS(
102+
`Skipping insecure WebSocket URL for API-key authentication: ${currentUrl}`
103+
);
104+
}
105+
return next(resolve, reject);
106+
}
107+
99108
if (appDebugEnabled) {
100109
debugWS(`Attempting connection to ${currentUrl}`);
101110
}

backend/lib/truenas-auto-discover.js

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,28 @@ function generateWebSocketURLs(uiConfig = null, options = {}) {
246246

247247
const explicitBase = process.env.TRUENAS_WS_BASE;
248248
if (explicitBase) {
249-
const wsBase = explicitBase.replace(/^http/, "ws");
250-
urls.push(`${wsBase}/websocket`);
249+
const normalizedBase = explicitBase.replace(/\/+$/, "");
250+
let wsBase = normalizedBase.replace(/^http/i, "ws");
251+
if (requireSecure && /^ws:\/\//i.test(wsBase)) {
252+
wsBase = wsBase.replace(/^ws:\/\//i, "wss://");
253+
if (appDebugEnabled) {
254+
debugDiscovery(
255+
`TRUENAS_WS_BASE uses insecure scheme; upgrading to secure WebSocket base: ${wsBase}`
256+
);
257+
}
258+
}
259+
260+
const explicitWsUrl = `${wsBase}/websocket`;
261+
if (!requireSecure || /^wss:\/\//i.test(explicitWsUrl)) {
262+
urls.push(explicitWsUrl);
263+
} else if (appDebugEnabled) {
264+
debugDiscovery(
265+
`Ignoring insecure explicit WebSocket URL in secure mode: ${explicitWsUrl}`
266+
);
267+
}
268+
251269
if (appDebugEnabled) {
252-
debugDiscovery(`Added explicit WebSocket URL: ${wsBase}/websocket`);
270+
debugDiscovery(`Added explicit WebSocket URL: ${explicitWsUrl}`);
253271
}
254272
if (urls.length > 0) {
255273
return urls;
@@ -276,15 +294,6 @@ function generateWebSocketURLs(uiConfig = null, options = {}) {
276294
}
277295
}
278296
}
279-
for (const host of hostAddresses) {
280-
if (uiConfig.httpPort) {
281-
const url = `ws://${host}:${uiConfig.httpPort}/websocket`;
282-
urls.push(url);
283-
if (appDebugEnabled) {
284-
debugDiscovery(`Added discovered HTTP WebSocket (fallback): ${url}`);
285-
}
286-
}
287-
}
288297
} else {
289298
for (const host of hostAddresses) {
290299
if (uiConfig.httpsEnabled && uiConfig.httpsPort) {
@@ -306,16 +315,23 @@ function generateWebSocketURLs(uiConfig = null, options = {}) {
306315
}
307316
}
308317

309-
if (!uiConfig) {
318+
const shouldUseFallbackPorts =
319+
!uiConfig || (requireSecure && urls.length === 0);
320+
321+
if (shouldUseFallbackPorts) {
310322
if (appDebugEnabled) {
311-
debugDiscovery("No UI config discovered, using generic fallback ports");
323+
if (!uiConfig) {
324+
debugDiscovery("No UI config discovered, using generic fallback ports");
325+
} else {
326+
debugDiscovery(
327+
"No secure WebSocket URL discovered from UI config, using secure fallback ports"
328+
);
329+
}
312330
}
313331

314332
const commonPorts = requireSecure ? [
315333
{ port: 443, protocol: "wss" },
316334
{ port: 8443, protocol: "wss" },
317-
{ port: 80, protocol: "ws" },
318-
{ port: 8080, protocol: "ws" },
319335
] : [
320336
{ port: 443, protocol: "wss" },
321337
{ port: 80, protocol: "ws" },

0 commit comments

Comments
 (0)