From 5ed322d281e1660bd08c2bd6158223277dc093d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20Talbot?= <108630700+fetchfern@users.noreply.github.com> Date: Tue, 16 Jun 2026 17:39:38 -0400 Subject: [PATCH] feat(frontend): don't assume secure protocol for kyros websocket/fs (#6420) * feat(frontend): don't assume https as websocket/fs protocol * fix(frontend): actually do the same for websocket * fix(frontend): don't strip ws path --- packages/api-client/src/features/node-auth.ts | 3 ++- packages/api-client/src/modules/kyros/files/v0.ts | 3 ++- .../api-client/src/platform/websocket-generic.ts | 3 ++- packages/api-client/src/utils/node-url.ts | 12 ++++++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 packages/api-client/src/utils/node-url.ts diff --git a/packages/api-client/src/features/node-auth.ts b/packages/api-client/src/features/node-auth.ts index 62424d5d0..c526b68f9 100644 --- a/packages/api-client/src/features/node-auth.ts +++ b/packages/api-client/src/features/node-auth.ts @@ -1,6 +1,7 @@ import { AbstractFeature, type FeatureConfig } from '../core/abstract-feature' import { ModrinthApiError } from '../core/errors' import type { RequestContext } from '../types/request' +import { getNodeBaseUrl } from '../utils/node-url' /** * Node authentication credentials @@ -107,7 +108,7 @@ export class NodeAuthFeature extends AbstractFeature { } private applyAuth(context: RequestContext, auth: NodeAuth): void { - const baseUrl = `https://${auth.url.replace(/\/modrinth\/v\d+\/fs\/?$/, '')}` + const baseUrl = getNodeBaseUrl(auth.url) context.url = this.buildUrl(context.path, baseUrl, context.options.version) context.options.headers = { diff --git a/packages/api-client/src/modules/kyros/files/v0.ts b/packages/api-client/src/modules/kyros/files/v0.ts index 693b89a81..b027294e3 100644 --- a/packages/api-client/src/modules/kyros/files/v0.ts +++ b/packages/api-client/src/modules/kyros/files/v0.ts @@ -1,5 +1,6 @@ import { AbstractModule } from '../../../core/abstract-module' import type { UploadHandle, UploadProgress } from '../../../types/upload' +import { getNodeBaseUrl } from '../../../utils/node-url' import type { Archon } from '../../archon/types' import type { Kyros } from '../types' @@ -11,7 +12,7 @@ export class KyrosFilesV0Module extends AbstractModule { } private getNodeBaseUrl(auth: NodeFsAuth): string { - return `https://${auth.url.replace(/\/modrinth\/v\d+\/fs\/?$/, '')}` + return getNodeBaseUrl(auth.url) } /** diff --git a/packages/api-client/src/platform/websocket-generic.ts b/packages/api-client/src/platform/websocket-generic.ts index 53ce9a6e1..19aa098f4 100644 --- a/packages/api-client/src/platform/websocket-generic.ts +++ b/packages/api-client/src/platform/websocket-generic.ts @@ -2,6 +2,7 @@ import mitt from 'mitt' import { AbstractWebSocketClient, type WebSocketConnection } from '../core/abstract-websocket' import type { Archon } from '../modules/archon/types' +import { getNodeWebSocketUrl } from '../utils/node-url' type WSEventMap = { [K in Archon.Websocket.v0.WSEvent as `${string}:${K['event']}`]: K @@ -19,7 +20,7 @@ export class GenericWebSocketClient extends AbstractWebSocketClient { return new Promise((resolve, reject) => { try { - const ws = new WebSocket(`wss://${auth.url}`) + const ws = new WebSocket(getNodeWebSocketUrl(auth.url)) const connection: WebSocketConnection = { serverId, diff --git a/packages/api-client/src/utils/node-url.ts b/packages/api-client/src/utils/node-url.ts new file mode 100644 index 000000000..834250e4a --- /dev/null +++ b/packages/api-client/src/utils/node-url.ts @@ -0,0 +1,12 @@ +const NODE_FS_PATH_REGEX = /\/modrinth\/v\d+\/fs\/?$/ +const HTTP_SCHEME_REGEX = /^https?:\/\//i +const WS_SCHEME_REGEX = /^wss?:\/\//i + +export function getNodeBaseUrl(url: string): string { + const baseUrl = url.replace(NODE_FS_PATH_REGEX, '') + return HTTP_SCHEME_REGEX.test(baseUrl) ? baseUrl : `https://${baseUrl}` +} + +export function getNodeWebSocketUrl(url: string): string { + return WS_SCHEME_REGEX.test(url) ? url : `wss://${url}` +}