From bff0b05b90683d95e0369148fc8a934cc7f2fe70 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Fri, 8 Nov 2024 17:44:43 -0500 Subject: [PATCH] More cleanup --- client/src/www/app/app.ts | 6 ++-- .../app/outline_server_repository/config.ts | 34 ++++++++++++++++--- .../app/outline_server_repository/index.ts | 27 +++------------ 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/client/src/www/app/app.ts b/client/src/www/app/app.ts index e5645c9e91..b32b3a9521 100644 --- a/client/src/www/app/app.ts +++ b/client/src/www/app/app.ts @@ -19,6 +19,7 @@ import {Clipboard} from './clipboard'; import {EnvironmentVariables} from './environment'; import {localizeErrorCode} from './error_localizer'; import {OutlineServerRepository} from './outline_server_repository'; +import * as config from './outline_server_repository/config'; import {Settings, SettingsKey} from './settings'; import {Updater} from './updater'; import {UrlInterceptor} from './url_interceptor'; @@ -226,8 +227,7 @@ export class App { this.eventQueue.startPublishing(); - this.rootEl.$.addServerView.validateAccessKey = - serverRepo.validateAccessKey; + this.rootEl.$.addServerView.validateAccessKey = config.validateAccessKey; if (!this.arePrivacyTermsAcked()) { this.displayPrivacyView(); } else if (this.rootEl.$.serversView.shouldShowZeroState) { @@ -471,7 +471,7 @@ export class App { } } try { - this.serverRepo.validateAccessKey(accessKey); + config.validateAccessKey(accessKey); addServerView.accessKey = accessKey; addServerView.open = true; } catch (e) { diff --git a/client/src/www/app/outline_server_repository/config.ts b/client/src/www/app/outline_server_repository/config.ts index 5a677aeffb..26e8fc2af5 100644 --- a/client/src/www/app/outline_server_repository/config.ts +++ b/client/src/www/app/outline_server_repository/config.ts @@ -68,6 +68,11 @@ export function setTransportConfigHost( return {...transport, host: newHost}; } +/** + * parseTunnelConfig parses the given tunnel config as text and returns a new TransportConfigJson. + * The config text may be a "ss://" link or a JSON object. + * This is used by the server to parse the config fetched from the dynamic key. + */ export function parseTunnelConfig( tunnelConfigText: string ): TunnelConfigJson | null { @@ -118,7 +123,20 @@ export function staticKeyToTunnelConfig(staticKey: string): TunnelConfigJson { } } -export function validateStaticKey(staticKey: string) { +export function validateAccessKey(accessKey: string) { + if (!isDynamicAccessKey(accessKey)) { + return validateStaticKey(accessKey); + } + + try { + // URL does not parse the hostname if the protocol is non-standard (e.g. non-http) + new URL(accessKey.replace(/^ssconf:\/\//, 'https://')); + } catch (error) { + throw new errors.ServerUrlInvalid(error.message); + } +} + +function validateStaticKey(staticKey: string) { let config = null; try { config = SHADOWSOCKS_URI.parse(staticKey); @@ -143,7 +161,7 @@ const SUPPORTED_SHADOWSOCKS_CIPHERS = [ 'aes-256-gcm', ]; -export function isShadowsocksCipherSupported(cipher?: string): boolean { +function isShadowsocksCipherSupported(cipher?: string): boolean { return cipher !== undefined && SUPPORTED_SHADOWSOCKS_CIPHERS.includes(cipher); } @@ -153,9 +171,15 @@ export function isDynamicAccessKey(accessKey: string): boolean { return accessKey.startsWith('ssconf://') || accessKey.startsWith('https://'); } -// NOTE: For extracting a name that the user has explicitly set, only. -// (Currenly done by setting the hash on the URI) -export function serverNameFromAccessKey(accessKey: string): string | undefined { +/** + * serviceNameFromAccessKey extracts the service name from the access key. + * This is done by getting parsing the fragment hash in the URL and returning the + * entry that is not a key=value pair. + * This is used to name the service card in the UI when the service is added. + */ +export function serviceNameFromAccessKey( + accessKey: string +): string | undefined { const {hash} = new URL(accessKey.replace(/^ss(?:conf)?:\/\//, 'https://')); if (!hash) return; diff --git a/client/src/www/app/outline_server_repository/index.ts b/client/src/www/app/outline_server_repository/index.ts index 3da25ea860..0e19a61ad2 100644 --- a/client/src/www/app/outline_server_repository/index.ts +++ b/client/src/www/app/outline_server_repository/index.ts @@ -16,11 +16,7 @@ import {Localizer} from '@outline/infrastructure/i18n'; import {makeConfig, SIP002_URI} from 'ShadowsocksConfig'; import uuidv4 from 'uuidv4'; -import { - isDynamicAccessKey, - serverNameFromAccessKey, - validateStaticKey, -} from './config'; +import * as config from './config'; import {OutlineServer} from './server'; import {TunnelStatus, VpnApi} from './vpn'; import * as errors from '../../model/errors'; @@ -125,10 +121,10 @@ export class OutlineServerRepository implements ServerRepository { if (alreadyAddedServer) { throw new errors.ServerAlreadyAdded(alreadyAddedServer); } - this.validateAccessKey(accessKey); + config.validateAccessKey(accessKey); // Note that serverNameFromAccessKey depends on the fact that the Access Key is a URL. - const serverName = serverNameFromAccessKey(accessKey); + const serverName = config.serviceNameFromAccessKey(accessKey); const server = this.createServer(uuidv4(), accessKey, serverName); this.serverById.set(server.id, server); @@ -180,19 +176,6 @@ export class OutlineServerRepository implements ServerRepository { this.lastForgottenServer = null; } - validateAccessKey(accessKey: string) { - if (!isDynamicAccessKey(accessKey)) { - return validateStaticKey(accessKey); - } - - try { - // URL does not parse the hostname if the protocol is non-standard (e.g. non-http) - new URL(accessKey.replace(/^ssconf:\/\//, 'https://')); - } catch (error) { - throw new errors.ServerUrlInvalid(error.message); - } - } - private serverFromAccessKey(accessKey: string): OutlineServer | undefined { for (const server of this.serverById.values()) { if (accessKey === server.accessKey) { @@ -301,14 +284,14 @@ export class OutlineServerRepository implements ServerRepository { id, name, accessKey, - isDynamicAccessKey(accessKey) + config.isDynamicAccessKey(accessKey) ? ServerType.DYNAMIC_CONNECTION : ServerType.STATIC_CONNECTION, this.localize ); try { - this.validateAccessKey(accessKey); + config.validateAccessKey(accessKey); } catch (e) { if (e instanceof errors.ShadowsocksUnsupportedCipher) { // Don't throw for backward-compatibility.