mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-01 21:13:09 +00:00
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:
@@ -7,6 +7,7 @@ import { i18nKey, i18nPipe } from '@start9labs/shared'
|
||||
|
||||
type AddressWithInfo = {
|
||||
url: string
|
||||
ssl: boolean
|
||||
info: T.HostnameInfo
|
||||
gateway?: GatewayPlus
|
||||
}
|
||||
@@ -132,12 +133,26 @@ export class InterfaceService {
|
||||
|
||||
if (!hostnamesInfos.length) return addresses
|
||||
|
||||
const allAddressesWithInfo: AddressWithInfo[] = hostnamesInfos.flatMap(h =>
|
||||
utils.addressHostToUrl(serviceInterface.addressInfo, h).map(url => ({
|
||||
url,
|
||||
info: h,
|
||||
gateway: gateways.find(g => h.kind === 'ip' && h.gateway.id === g.id),
|
||||
})),
|
||||
const allAddressesWithInfo: AddressWithInfo[] = hostnamesInfos.flatMap(
|
||||
h => {
|
||||
const { url, sslUrl } = utils.addressHostToUrl(
|
||||
serviceInterface.addressInfo,
|
||||
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)
|
||||
@@ -311,7 +326,7 @@ export class InterfaceService {
|
||||
}
|
||||
|
||||
private toDisplayAddress(
|
||||
{ info, url, gateway }: AddressWithInfo,
|
||||
{ info, ssl, url, gateway }: AddressWithInfo,
|
||||
publicDomains: Record<string, T.PublicDomainConfig>,
|
||||
): DisplayAddress {
|
||||
let access: DisplayAddress['access']
|
||||
@@ -335,33 +350,29 @@ export class InterfaceService {
|
||||
),
|
||||
this.i18n.transform('Requires using a Tor-enabled device or browser'),
|
||||
]
|
||||
// Tor (HTTPS)
|
||||
if (url.startsWith('https:')) {
|
||||
type = `${type} (HTTPS)`
|
||||
// Tor (SSL)
|
||||
if (ssl) {
|
||||
type = `${type} (SSL)`
|
||||
bullets = [
|
||||
this.i18n.transform('Only useful for clients that enforce HTTPS'),
|
||||
this.i18n.transform('Only useful for clients that require SSL'),
|
||||
rootCaRequired,
|
||||
...bullets,
|
||||
]
|
||||
// Tor (HTTP)
|
||||
// Tor (NON-SSL)
|
||||
} else {
|
||||
bullets.unshift(
|
||||
this.i18n.transform(
|
||||
'Ideal for anonymous, censorship-resistant hosting and remote access',
|
||||
),
|
||||
)
|
||||
if (url.startsWith('http:')) {
|
||||
type = `${type} (HTTP)`
|
||||
}
|
||||
}
|
||||
// ** Not Tor **
|
||||
} else {
|
||||
const port = info.hostname.sslPort || info.hostname.port
|
||||
const g = gateway!
|
||||
gatewayName = g.name
|
||||
gatewayName = info.gateway.name
|
||||
|
||||
const gatewayLanIpv4 = g.lanIpv4[0]
|
||||
const isWireguard = g.ipInfo.deviceType === 'wireguard'
|
||||
const gatewayLanIpv4 = gateway?.lanIpv4[0]
|
||||
const isWireguard = gateway?.ipInfo.deviceType === 'wireguard'
|
||||
|
||||
const localIdeal = this.i18n.transform('Ideal for local access')
|
||||
const lanRequired = this.i18n.transform(
|
||||
@@ -402,9 +413,9 @@ export class InterfaceService {
|
||||
),
|
||||
rootCaRequired,
|
||||
]
|
||||
if (!g.public) {
|
||||
if (!info.gateway.public) {
|
||||
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 {
|
||||
@@ -436,12 +447,12 @@ export class InterfaceService {
|
||||
if (info.public) {
|
||||
access = 'public'
|
||||
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(
|
||||
`${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}`,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -83,18 +83,10 @@ export default class GatewaysComponent {
|
||||
),
|
||||
required: true,
|
||||
default: null,
|
||||
}),
|
||||
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'),
|
||||
},
|
||||
placeholder: 'StartTunnel 1',
|
||||
}),
|
||||
config: ISB.Value.union({
|
||||
name: this.i18n.transform('Wireguard Config File'),
|
||||
name: this.i18n.transform('StartTunnel Config File'),
|
||||
default: 'paste',
|
||||
variants: ISB.Variants.of({
|
||||
paste: {
|
||||
@@ -108,7 +100,7 @@ export default class GatewaysComponent {
|
||||
}),
|
||||
},
|
||||
select: {
|
||||
name: this.i18n.transform('Select'),
|
||||
name: this.i18n.transform('Upload'),
|
||||
spec: ISB.InputSpec.of({
|
||||
file: ISB.Value.file({
|
||||
name: this.i18n.transform('File'),
|
||||
@@ -122,7 +114,7 @@ export default class GatewaysComponent {
|
||||
})
|
||||
|
||||
this.formDialog.open(FormComponent, {
|
||||
label: 'Add gateway',
|
||||
label: 'Add StartTunnel Gateway',
|
||||
data: {
|
||||
spec: await configBuilderToSpec(spec),
|
||||
buttons: [
|
||||
@@ -138,7 +130,7 @@ export default class GatewaysComponent {
|
||||
input.config.selection === 'paste'
|
||||
? input.config.value.file
|
||||
: await (input.config.value.file as any as File).text(),
|
||||
public: input.type === 'public',
|
||||
public: false,
|
||||
})
|
||||
return true
|
||||
} catch (e: any) {
|
||||
|
||||
Reference in New Issue
Block a user