limit adding gateway to StartTunnel, better copy around Tor SSL (#3033)

* limit adding gateway to StartTunnel, better copy around Tor SSL

* properly differentiate ssl

* exclude disconnected gateways

* better error handling

---------

Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
Matt Hill
2025-09-24 13:22:26 -06:00
committed by GitHub
parent bc62de795e
commit 6f1900f3bb
9 changed files with 91 additions and 83 deletions

View File

@@ -135,11 +135,12 @@ impl BindInfo {
} }
impl InterfaceFilter for NetInfo { impl InterfaceFilter for NetInfo {
fn filter(&self, id: &GatewayId, info: &NetworkInterfaceInfo) -> bool { fn filter(&self, id: &GatewayId, info: &NetworkInterfaceInfo) -> bool {
if info.public() { info.ip_info.is_some()
self.public_enabled.contains(id) && if info.public() {
} else { self.public_enabled.contains(id)
!self.private_disabled.contains(id) } else {
} !self.private_disabled.contains(id)
}
} }
} }

View File

@@ -87,7 +87,10 @@ type FormatReturnTy<
export type Filled = { export type Filled = {
hostnames: HostnameInfo[] hostnames: HostnameInfo[]
toUrl: (h: HostnameInfo) => UrlString[] toUrls: (h: HostnameInfo) => {
url: UrlString | null
sslUrl: UrlString | null
}
filter: <F extends Filter, Format extends Formats = "urlstring">( filter: <F extends Filter, Format extends Formats = "urlstring">(
filter: F, filter: F,
@@ -139,7 +142,7 @@ const unique = <A>(values: A[]) => Array.from(new Set(values))
export const addressHostToUrl = ( export const addressHostToUrl = (
{ scheme, sslScheme, username, suffix }: AddressInfo, { scheme, sslScheme, username, suffix }: AddressInfo,
hostname: HostnameInfo, hostname: HostnameInfo,
): UrlString[] => { ): { url: UrlString | null; sslUrl: UrlString | null } => {
const res = [] const res = []
const fmt = (scheme: string | null, host: HostnameInfo, port: number) => { const fmt = (scheme: string | null, host: HostnameInfo, port: number) => {
const excludePort = const excludePort =
@@ -164,14 +167,16 @@ export const addressHostToUrl = (
username ? `${username}@` : "" username ? `${username}@` : ""
}${hostname}${excludePort ? "" : `:${port}`}${suffix}` }${hostname}${excludePort ? "" : `:${port}`}${suffix}`
} }
let url = null
if (hostname.hostname.sslPort !== null) { if (hostname.hostname.sslPort !== null) {
res.push(fmt(sslScheme, hostname, hostname.hostname.sslPort)) url = fmt(sslScheme, hostname, hostname.hostname.sslPort)
} }
let sslUrl = null
if (hostname.hostname.port !== null) { if (hostname.hostname.port !== null) {
res.push(fmt(scheme, hostname, hostname.hostname.port)) sslUrl = fmt(scheme, hostname, hostname.hostname.port)
} }
return res return { url, sslUrl }
} }
function filterRec( function filterRec(
@@ -223,13 +228,17 @@ export const filledAddress = (
host: Host, host: Host,
addressInfo: AddressInfo, addressInfo: AddressInfo,
): FilledAddressInfo => { ): FilledAddressInfo => {
const toUrl = addressHostToUrl.bind(null, addressInfo) const toUrls = addressHostToUrl.bind(null, addressInfo)
const toUrlArray = (h: HostnameInfo) => {
const u = toUrls(h)
return [u.url, u.sslUrl].filter((u) => u !== null)
}
const hostnames = host.hostnameInfo[addressInfo.internalPort] ?? [] const hostnames = host.hostnameInfo[addressInfo.internalPort] ?? []
return { return {
...addressInfo, ...addressInfo,
hostnames, hostnames,
toUrl, toUrls,
filter: <F extends Filter, Format extends Formats = "urlstring">( filter: <F extends Filter, Format extends Formats = "urlstring">(
filter: F, filter: F,
format?: Format, format?: Format,
@@ -237,7 +246,7 @@ export const filledAddress = (
const filtered = filterRec(hostnames, filter, false) const filtered = filterRec(hostnames, filter, false)
let res: FormatReturnTy<F, Format>[] = filtered as any let res: FormatReturnTy<F, Format>[] = filtered as any
if (format === "hostname-info") return res if (format === "hostname-info") return res
const urls = filtered.flatMap(toUrl) const urls = filtered.flatMap(toUrlArray)
if (format === "url") res = urls.map((u) => new URL(u)) as any if (format === "url") res = urls.map((u) => new URL(u)) as any
else res = urls as any else res = urls as any
return res return res
@@ -279,28 +288,28 @@ export const filledAddress = (
) )
}, },
get urls() { get urls() {
return this.hostnames.flatMap(toUrl) return this.hostnames.flatMap(toUrlArray)
}, },
get publicUrls() { get publicUrls() {
return this.publicHostnames.flatMap(toUrl) return this.publicHostnames.flatMap(toUrlArray)
}, },
get onionUrls() { get onionUrls() {
return this.onionHostnames.flatMap(toUrl) return this.onionHostnames.flatMap(toUrlArray)
}, },
get localUrls() { get localUrls() {
return this.localHostnames.flatMap(toUrl) return this.localHostnames.flatMap(toUrlArray)
}, },
get ipUrls() { get ipUrls() {
return this.ipHostnames.flatMap(toUrl) return this.ipHostnames.flatMap(toUrlArray)
}, },
get ipv4Urls() { get ipv4Urls() {
return this.ipv4Hostnames.flatMap(toUrl) return this.ipv4Hostnames.flatMap(toUrlArray)
}, },
get ipv6Urls() { get ipv6Urls() {
return this.ipv6Hostnames.flatMap(toUrl) return this.ipv6Hostnames.flatMap(toUrlArray)
}, },
get nonIpUrls() { get nonIpUrls() {
return this.nonIpHostnames.flatMap(toUrl) return this.nonIpHostnames.flatMap(toUrlArray)
}, },
} }
} }

View File

@@ -502,7 +502,7 @@ export default {
531: 'Fehler beim Initialisieren des Servers', 531: 'Fehler beim Initialisieren des Servers',
532: 'Abgeschlossen', 532: 'Abgeschlossen',
533: 'Gateways', 533: 'Gateways',
535: 'Gateway hinzufügen', 535: 'StartTunnel-Gateway hinzufügen',
536: 'Umbenennen', 536: 'Umbenennen',
537: 'Zugriff', 537: 'Zugriff',
538: 'Öffentliche Domains', 538: 'Öffentliche Domains',
@@ -535,10 +535,8 @@ export default {
569: 'Wählen Sie eine Zertifizierungsstelle aus, um SSL/TLS-Zertifikate für diese Domain auszustellen.', 569: 'Wählen Sie eine Zertifizierungsstelle aus, um SSL/TLS-Zertifikate für diese Domain auszustellen.',
570: 'Andere', 570: 'Andere',
571: 'Ein Name zur einfachen Identifizierung des Gateways', 571: 'Ein Name zur einfachen Identifizierung des Gateways',
572: 'Wählen Sie diese Option, wenn das Gateway für den privaten Zugriff nur für autorisierte Clients konfiguriert ist. StartTunnel ist ein privates Gateway.',
573: 'Wählen Sie diese Option, wenn das Gateway für uneingeschränkten öffentlichen Zugriff konfiguriert ist.',
574: 'Datei', 574: 'Datei',
575: 'Wireguard-Konfigurationsdatei', 575: 'StartTunnel-Konfigurationsdatei',
576: 'Kopieren/Einfügen', 576: 'Kopieren/Einfügen',
577: 'Dateiinhalt', 577: 'Dateiinhalt',
578: 'Öffentlicher Schlüssel', 578: 'Öffentlicher Schlüssel',
@@ -550,7 +548,7 @@ export default {
584: 'Verbindungen können manchmal langsam oder unzuverlässig sein', 584: 'Verbindungen können manchmal langsam oder unzuverlässig sein',
585: 'Öffentlich, wenn Sie die Adresse öffentlich teilen, andernfalls privat', 585: 'Öffentlich, wenn Sie die Adresse öffentlich teilen, andernfalls privat',
586: 'Erfordert ein Tor-fähiges Gerät oder einen Browser', 586: 'Erfordert ein Tor-fähiges Gerät oder einen Browser',
587: 'Nur nützlich für Clients, die HTTPS erzwingen', 587: 'Nur nützlich für Clients, die SSL erzwingen',
588: 'Ideal für anonyme, zensurresistente Bereitstellung und Fernzugriff', 588: 'Ideal für anonyme, zensurresistente Bereitstellung und Fernzugriff',
589: 'Ideal für lokalen Zugriff', 589: 'Ideal für lokalen Zugriff',
590: 'Erfordert die Verbindung mit demselben lokalen Netzwerk (LAN) wie Ihr Server, entweder physisch oder über VPN', 590: 'Erfordert die Verbindung mit demselben lokalen Netzwerk (LAN) wie Ihr Server, entweder physisch oder über VPN',
@@ -589,4 +587,5 @@ export default {
623: 'Alternative Implementierungen', 623: 'Alternative Implementierungen',
624: 'Versionen', 624: 'Versionen',
625: 'Eine andere Version auswählen', 625: 'Eine andere Version auswählen',
626: 'Hochladen',
} satisfies i18n } satisfies i18n

View File

@@ -501,7 +501,7 @@ export const ENGLISH = {
'Error initializing server': 531, 'Error initializing server': 531,
'Finished': 532, // an in, complete 'Finished': 532, // an in, complete
'Gateways': 533, // as in, a device or software that connects two different networks 'Gateways': 533, // as in, a device or software that connects two different networks
'Add gateway': 535, // as in, add a new network gateway to StartOS 'Add StartTunnel Gateway': 535, // as in, add a new StartTunnel network gateway to StartOS
'Rename': 536, 'Rename': 536,
'Access': 537, // as in, public or private access, almost "permission" 'Access': 537, // as in, public or private access, almost "permission"
'Public Domains': 538, // as in, internet domains 'Public Domains': 538, // as in, internet domains
@@ -534,10 +534,8 @@ export const ENGLISH = {
'Select a Certificate Authority to issue SSL/TLS certificates for this domain': 569, 'Select a Certificate Authority to issue SSL/TLS certificates for this domain': 569,
'Other': 570, // as in, a list option to indicate none of the options listed 'Other': 570, // as in, a list option to indicate none of the options listed
'A name to easily identify the gateway': 571, 'A name to easily identify the gateway': 571,
'select this option if the gateway is configured for private access to authorized clients only. StartTunnel is a private gateway.': 572,
'select this option if the gateway is configured for unfettered public access.': 573,
'File': 574, // as in, a computer file 'File': 574, // as in, a computer file
'Wireguard Config File': 575, 'StartTunnel Config File': 575,
'Copy/Paste': 576, 'Copy/Paste': 576,
'File Contents': 577, 'File Contents': 577,
'Public Key': 578, // as in, a cryptographic public key 'Public Key': 578, // as in, a cryptographic public key
@@ -549,7 +547,7 @@ export const ENGLISH = {
'Connections can be slow or unreliable at times': 584, 'Connections can be slow or unreliable at times': 584,
'Public if you share the address publicly, otherwise private': 585, 'Public if you share the address publicly, otherwise private': 585,
'Requires using a Tor-enabled device or browser': 586, 'Requires using a Tor-enabled device or browser': 586,
'Only useful for clients that enforce HTTPS': 587, 'Only useful for clients that require SSL': 587,
'Ideal for anonymous, censorship-resistant hosting and remote access': 588, 'Ideal for anonymous, censorship-resistant hosting and remote access': 588,
'Ideal for local access': 589, 'Ideal for local access': 589,
'Requires being connected to the same Local Area Network (LAN) as your server, either physically or via VPN': 590, 'Requires being connected to the same Local Area Network (LAN) as your server, either physically or via VPN': 590,
@@ -588,4 +586,5 @@ export const ENGLISH = {
'Alternative Implementations': 623, 'Alternative Implementations': 623,
'Versions': 624, 'Versions': 624,
'Select another version': 625, 'Select another version': 625,
'Upload': 626, // as in, upload a file
} as const } as const

View File

@@ -502,7 +502,7 @@ export default {
531: 'Error al inicializar el servidor', 531: 'Error al inicializar el servidor',
532: 'Finalizado', 532: 'Finalizado',
533: 'Puertas de enlace', 533: 'Puertas de enlace',
535: 'Agregar puerta de enlace', 535: 'Agregar puerta de enlace StartTunnel',
536: 'Renombrar', 536: 'Renombrar',
537: 'Acceso', 537: 'Acceso',
538: 'Dominios públicos', 538: 'Dominios públicos',
@@ -535,10 +535,8 @@ export default {
569: 'Selecciona una Autoridad Certificadora para emitir certificados SSL/TLS para este dominio.', 569: 'Selecciona una Autoridad Certificadora para emitir certificados SSL/TLS para este dominio.',
570: 'Otro', 570: 'Otro',
571: 'Un nombre para identificar fácilmente la puerta de enlace', 571: 'Un nombre para identificar fácilmente la puerta de enlace',
572: 'Selecciona esta opción si la puerta de enlace está configurada para acceso privado solo a clientes autorizados. StartTunnel es una puerta de enlace privada.',
573: 'Selecciona esta opción si la puerta de enlace está configurada para acceso público sin restricciones.',
574: 'Archivo', 574: 'Archivo',
575: 'Archivo de configuración de Wireguard', 575: 'Archivo de configuración de StartTunnel',
576: 'Copiar/Pegar', 576: 'Copiar/Pegar',
577: 'Contenido del archivo', 577: 'Contenido del archivo',
578: 'Clave pública', 578: 'Clave pública',
@@ -550,7 +548,7 @@ export default {
584: 'Las conexiones pueden ser lentas o poco confiables a veces', 584: 'Las conexiones pueden ser lentas o poco confiables a veces',
585: 'Público si compartes la dirección públicamente, de lo contrario privado', 585: 'Público si compartes la dirección públicamente, de lo contrario privado',
586: 'Requiere un dispositivo o navegador habilitado para Tor', 586: 'Requiere un dispositivo o navegador habilitado para Tor',
587: 'Solo útil para clientes que imponen HTTPS', 587: 'Solo útil para clientes que imponen SSL',
588: 'Ideal para alojamiento y acceso remoto anónimo y resistente a la censura', 588: 'Ideal para alojamiento y acceso remoto anónimo y resistente a la censura',
589: 'Ideal para acceso local', 589: 'Ideal para acceso local',
590: 'Requiere estar conectado a la misma red de área local (LAN) que tu servidor, ya sea físicamente o mediante VPN', 590: 'Requiere estar conectado a la misma red de área local (LAN) que tu servidor, ya sea físicamente o mediante VPN',
@@ -589,4 +587,5 @@ export default {
623: 'Implementaciones alternativas', 623: 'Implementaciones alternativas',
624: 'Versiones', 624: 'Versiones',
625: 'Seleccionar otra versión', 625: 'Seleccionar otra versión',
626: 'Subir',
} satisfies i18n } satisfies i18n

View File

@@ -502,7 +502,7 @@ export default {
531: "Erreur lors de l'initialisation du serveur", 531: "Erreur lors de l'initialisation du serveur",
532: 'Terminé', 532: 'Terminé',
533: 'Passerelles', 533: 'Passerelles',
535: 'Ajouter une passerelle', 535: 'Ajouter une passerelle StartTunnel',
536: 'Renommer', 536: 'Renommer',
537: 'Accès', 537: 'Accès',
538: 'Domaines publics', 538: 'Domaines publics',
@@ -535,10 +535,8 @@ export default {
569: 'Sélectionnez une Autorité de Certification pour émettre des certificats SSL/TLS pour ce domaine.', 569: 'Sélectionnez une Autorité de Certification pour émettre des certificats SSL/TLS pour ce domaine.',
570: 'Autre', 570: 'Autre',
571: 'Un nom pour identifier facilement la passerelle', 571: 'Un nom pour identifier facilement la passerelle',
572: 'Sélectionnez cette option si la passerelle est configurée pour un accès privé uniquement aux clients autorisés. StartTunnel est une passerelle privée.',
573: 'Sélectionnez cette option si la passerelle est configurée pour un accès public illimité.',
574: 'Fichier', 574: 'Fichier',
575: 'Fichier de configuration Wireguard', 575: 'Fichier de configuration StartTunnel',
576: 'Copier/Coller', 576: 'Copier/Coller',
577: 'Contenu du fichier', 577: 'Contenu du fichier',
578: 'Clé publique', 578: 'Clé publique',
@@ -550,7 +548,7 @@ export default {
584: 'Les connexions peuvent parfois être lentes ou peu fiables', 584: 'Les connexions peuvent parfois être lentes ou peu fiables',
585: 'Public si vous partagez ladresse publiquement, sinon privé', 585: 'Public si vous partagez ladresse publiquement, sinon privé',
586: 'Nécessite un appareil ou un navigateur compatible Tor', 586: 'Nécessite un appareil ou un navigateur compatible Tor',
587: 'Utile uniquement pour les clients qui imposent HTTPS', 587: 'Utile uniquement pour les clients qui imposent SSL',
588: 'Idéal pour lhébergement et laccès à distance anonymes et résistants à la censure', 588: 'Idéal pour lhébergement et laccès à distance anonymes et résistants à la censure',
589: 'Idéal pour un accès local', 589: 'Idéal pour un accès local',
590: 'Nécessite dêtre connecté au même réseau local (LAN) que votre serveur, soit physiquement, soit via VPN', 590: 'Nécessite dêtre connecté au même réseau local (LAN) que votre serveur, soit physiquement, soit via VPN',
@@ -589,4 +587,5 @@ export default {
623: 'Implémentations alternatives', 623: 'Implémentations alternatives',
624: 'Versions', 624: 'Versions',
625: 'Sélectionner une autre version', 625: 'Sélectionner une autre version',
626: 'Téléverser',
} satisfies i18n } satisfies i18n

View File

@@ -502,7 +502,7 @@ export default {
531: 'Błąd inicjalizacji serwera', 531: 'Błąd inicjalizacji serwera',
532: 'Zakończono', 532: 'Zakończono',
533: 'Bramy sieciowe', 533: 'Bramy sieciowe',
535: 'Dodaj bramę', 535: 'Dodaj bramę StartTunnel',
536: 'Zmień nazwę', 536: 'Zmień nazwę',
537: 'Dostęp', 537: 'Dostęp',
538: 'Domeny publiczne', 538: 'Domeny publiczne',
@@ -535,10 +535,8 @@ export default {
569: 'Wybierz Urząd Certyfikacji, aby wystawić certyfikaty SSL/TLS dla tej domeny.', 569: 'Wybierz Urząd Certyfikacji, aby wystawić certyfikaty SSL/TLS dla tej domeny.',
570: 'Inne', 570: 'Inne',
571: 'Nazwa ułatwiająca identyfikację bramy', 571: 'Nazwa ułatwiająca identyfikację bramy',
572: 'Wybierz tę opcję, jeśli brama jest skonfigurowana do prywatnego dostępu tylko dla autoryzowanych klientów. StartTunnel to prywatna brama.',
573: 'Wybierz tę opcję, jeśli brama jest skonfigurowana do nieograniczonego publicznego dostępu.',
574: 'Plik', 574: 'Plik',
575: 'Plik konfiguracyjny Wireguard', 575: 'Plik konfiguracyjny StartTunnel',
576: 'Kopiuj/Wklej', 576: 'Kopiuj/Wklej',
577: 'Zawartość pliku', 577: 'Zawartość pliku',
578: 'Klucz publiczny', 578: 'Klucz publiczny',
@@ -550,7 +548,7 @@ export default {
584: 'Połączenia mogą być czasami wolne lub niestabilne', 584: 'Połączenia mogą być czasami wolne lub niestabilne',
585: 'Publiczne, jeśli udostępniasz adres publicznie, w przeciwnym razie prywatne', 585: 'Publiczne, jeśli udostępniasz adres publicznie, w przeciwnym razie prywatne',
586: 'Wymaga urządzenia lub przeglądarki obsługującej Tor', 586: 'Wymaga urządzenia lub przeglądarki obsługującej Tor',
587: 'Przydatne tylko dla klientów wymuszających HTTPS', 587: 'Przydatne tylko dla klientów wymuszających SSL',
588: 'Idealne do anonimowego, odpornego na cenzurę hostingu i zdalnego dostępu', 588: 'Idealne do anonimowego, odpornego na cenzurę hostingu i zdalnego dostępu',
589: 'Idealne do dostępu lokalnego', 589: 'Idealne do dostępu lokalnego',
590: 'Wymaga połączenia z tą samą siecią lokalną (LAN) co serwer, fizycznie lub przez VPN', 590: 'Wymaga połączenia z tą samą siecią lokalną (LAN) co serwer, fizycznie lub przez VPN',
@@ -589,4 +587,5 @@ export default {
623: 'Alternatywne implementacje', 623: 'Alternatywne implementacje',
624: 'Wersje', 624: 'Wersje',
625: 'Wybierz inną wersję', 625: 'Wybierz inną wersję',
626: 'Prześlij',
} satisfies i18n } satisfies i18n

View File

@@ -7,6 +7,7 @@ import { i18nKey, i18nPipe } from '@start9labs/shared'
type AddressWithInfo = { type AddressWithInfo = {
url: string url: string
ssl: boolean
info: T.HostnameInfo info: T.HostnameInfo
gateway?: GatewayPlus gateway?: GatewayPlus
} }
@@ -132,12 +133,26 @@ export class InterfaceService {
if (!hostnamesInfos.length) return addresses if (!hostnamesInfos.length) return addresses
const allAddressesWithInfo: AddressWithInfo[] = hostnamesInfos.flatMap(h => const allAddressesWithInfo: AddressWithInfo[] = hostnamesInfos.flatMap(
utils.addressHostToUrl(serviceInterface.addressInfo, h).map(url => ({ h => {
url, const { url, sslUrl } = utils.addressHostToUrl(
info: h, serviceInterface.addressInfo,
gateway: gateways.find(g => h.kind === 'ip' && h.gateway.id === g.id), h,
})), )
const info = h
const gateway =
h.kind === 'ip'
? gateways.find(g => h.gateway.id === g.id)
: undefined
const res = []
if (url) {
res.push({ url, ssl: false, info, gateway })
}
if (sslUrl) {
res.push({ url: sslUrl, ssl: true, info, gateway })
}
return res
},
) )
const torAddrs = allAddressesWithInfo.filter(filterTor).sort(cmpTor) const torAddrs = allAddressesWithInfo.filter(filterTor).sort(cmpTor)
@@ -311,7 +326,7 @@ export class InterfaceService {
} }
private toDisplayAddress( private toDisplayAddress(
{ info, url, gateway }: AddressWithInfo, { info, ssl, url, gateway }: AddressWithInfo,
publicDomains: Record<string, T.PublicDomainConfig>, publicDomains: Record<string, T.PublicDomainConfig>,
): DisplayAddress { ): DisplayAddress {
let access: DisplayAddress['access'] let access: DisplayAddress['access']
@@ -335,33 +350,29 @@ export class InterfaceService {
), ),
this.i18n.transform('Requires using a Tor-enabled device or browser'), this.i18n.transform('Requires using a Tor-enabled device or browser'),
] ]
// Tor (HTTPS) // Tor (SSL)
if (url.startsWith('https:')) { if (ssl) {
type = `${type} (HTTPS)` type = `${type} (SSL)`
bullets = [ bullets = [
this.i18n.transform('Only useful for clients that enforce HTTPS'), this.i18n.transform('Only useful for clients that require SSL'),
rootCaRequired, rootCaRequired,
...bullets, ...bullets,
] ]
// Tor (HTTP) // Tor (NON-SSL)
} else { } else {
bullets.unshift( bullets.unshift(
this.i18n.transform( this.i18n.transform(
'Ideal for anonymous, censorship-resistant hosting and remote access', 'Ideal for anonymous, censorship-resistant hosting and remote access',
), ),
) )
if (url.startsWith('http:')) {
type = `${type} (HTTP)`
}
} }
// ** Not Tor ** // ** Not Tor **
} else { } else {
const port = info.hostname.sslPort || info.hostname.port const port = info.hostname.sslPort || info.hostname.port
const g = gateway! gatewayName = info.gateway.name
gatewayName = g.name
const gatewayLanIpv4 = g.lanIpv4[0] const gatewayLanIpv4 = gateway?.lanIpv4[0]
const isWireguard = g.ipInfo.deviceType === 'wireguard' const isWireguard = gateway?.ipInfo.deviceType === 'wireguard'
const localIdeal = this.i18n.transform('Ideal for local access') const localIdeal = this.i18n.transform('Ideal for local access')
const lanRequired = this.i18n.transform( const lanRequired = this.i18n.transform(
@@ -402,9 +413,9 @@ export class InterfaceService {
), ),
rootCaRequired, rootCaRequired,
] ]
if (!g.public) { if (!info.gateway.public) {
bullets.push( bullets.push(
`${portForwarding} "${gatewayName}": ${port} -> ${g.subnets.find(s => s.isIpv4())?.address}:${port}`, `${portForwarding} "${gatewayName}": ${port} -> ${gateway?.subnets.find(s => s.isIpv4())?.address}:${port}`,
) )
} }
} else { } else {
@@ -436,12 +447,12 @@ export class InterfaceService {
if (info.public) { if (info.public) {
access = 'public' access = 'public'
bullets = [ bullets = [
`${dnsFor} ${info.hostname.value} ${resolvesTo} ${g.ipInfo.wanIp}`, `${dnsFor} ${info.hostname.value} ${resolvesTo} ${gateway?.ipInfo.wanIp}`,
] ]
if (!g.public) { if (!info.gateway.public) {
bullets.push( bullets.push(
`${portForwarding} "${gatewayName}": ${port} -> ${g.subnets.find(s => s.isIpv4())?.address}:${port === 443 ? 5443 : port}`, `${portForwarding} "${gatewayName}": ${port} -> ${gateway?.subnets.find(s => s.isIpv4())?.address}:${port === 443 ? 5443 : port}`,
) )
} }

View File

@@ -83,18 +83,10 @@ export default class GatewaysComponent {
), ),
required: true, required: true,
default: null, default: null,
}), placeholder: 'StartTunnel 1',
type: ISB.Value.select({
name: this.i18n.transform('Type'),
description: `-**${this.i18n.transform('private')}**: ${this.i18n.transform('select this option if the gateway is configured for private access to authorized clients only. StartTunnel is a private gateway.')}\n-**${this.i18n.transform('public')}**: ${this.i18n.transform('select this option if the gateway is configured for unfettered public access.')}`,
default: 'private',
values: {
private: this.i18n.transform('private'),
public: this.i18n.transform('public'),
},
}), }),
config: ISB.Value.union({ config: ISB.Value.union({
name: this.i18n.transform('Wireguard Config File'), name: this.i18n.transform('StartTunnel Config File'),
default: 'paste', default: 'paste',
variants: ISB.Variants.of({ variants: ISB.Variants.of({
paste: { paste: {
@@ -108,7 +100,7 @@ export default class GatewaysComponent {
}), }),
}, },
select: { select: {
name: this.i18n.transform('Select'), name: this.i18n.transform('Upload'),
spec: ISB.InputSpec.of({ spec: ISB.InputSpec.of({
file: ISB.Value.file({ file: ISB.Value.file({
name: this.i18n.transform('File'), name: this.i18n.transform('File'),
@@ -122,7 +114,7 @@ export default class GatewaysComponent {
}) })
this.formDialog.open(FormComponent, { this.formDialog.open(FormComponent, {
label: 'Add gateway', label: 'Add StartTunnel Gateway',
data: { data: {
spec: await configBuilderToSpec(spec), spec: await configBuilderToSpec(spec),
buttons: [ buttons: [
@@ -138,7 +130,7 @@ export default class GatewaysComponent {
input.config.selection === 'paste' input.config.selection === 'paste'
? input.config.value.file ? input.config.value.file
: await (input.config.value.file as any as File).text(), : await (input.config.value.file as any as File).text(),
public: input.type === 'public', public: false,
}) })
return true return true
} catch (e: any) { } catch (e: any) {