mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
chore: flatten HostnameInfo from enum to struct
HostnameInfo only had one variant (Ip) after removing Tor. Flatten it into a plain struct with fields gateway, public, hostname. Remove all kind === 'ip' type guards and narrowing across SDK, frontend, and container runtime. Update DB migration to strip the kind field.
This commit is contained in:
@@ -93,7 +93,7 @@ export class DockerProcedureContainer extends Drop {
|
|||||||
)?.hostnameInfo || {},
|
)?.hostnameInfo || {},
|
||||||
)
|
)
|
||||||
.flatMap((h) => h)
|
.flatMap((h) => h)
|
||||||
.flatMap((h) => (h.kind === "onion" ? [h.hostname.value] : [])),
|
.map((h) => h.hostname.value),
|
||||||
).values(),
|
).values(),
|
||||||
]
|
]
|
||||||
const certChain = await effects.getSslCertificate({
|
const certChain = await effects.getSslCertificate({
|
||||||
|
|||||||
@@ -1244,12 +1244,8 @@ async function updateConfig(
|
|||||||
? ""
|
? ""
|
||||||
: catchFn(
|
: catchFn(
|
||||||
() =>
|
() =>
|
||||||
(specValue.target === "lan-address"
|
filled.addressInfo!.filter({ kind: "mdns" })!
|
||||||
? filled.addressInfo!.filter({ kind: "mdns" }) ||
|
.hostnames[0].hostname.value,
|
||||||
filled.addressInfo!.onion
|
|
||||||
: filled.addressInfo!.onion ||
|
|
||||||
filled.addressInfo!.filter({ kind: "mdns" })
|
|
||||||
).hostnames[0].hostname.value,
|
|
||||||
) || ""
|
) || ""
|
||||||
mutConfigValue[key] = url
|
mutConfigValue[key] = url
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -481,7 +481,7 @@ impl NetServiceData {
|
|||||||
i.device_type != Some(NetworkInterfaceType::Wireguard)
|
i.device_type != Some(NetworkInterfaceType::Wireguard)
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
bind_hostname_info.push(HostnameInfo::Ip {
|
bind_hostname_info.push(HostnameInfo {
|
||||||
gateway: gateway.clone(),
|
gateway: gateway.clone(),
|
||||||
public: false,
|
public: false,
|
||||||
hostname: IpHostname::Local {
|
hostname: IpHostname::Local {
|
||||||
@@ -514,7 +514,7 @@ impl NetServiceData {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(false, |ssl| ssl.preferred_external_port == 443)
|
.map_or(false, |ssl| ssl.preferred_external_port == 443)
|
||||||
{
|
{
|
||||||
bind_hostname_info.push(HostnameInfo::Ip {
|
bind_hostname_info.push(HostnameInfo {
|
||||||
gateway: gateway.clone(),
|
gateway: gateway.clone(),
|
||||||
public,
|
public,
|
||||||
hostname: IpHostname::Domain {
|
hostname: IpHostname::Domain {
|
||||||
@@ -524,7 +524,7 @@ impl NetServiceData {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
bind_hostname_info.push(HostnameInfo::Ip {
|
bind_hostname_info.push(HostnameInfo {
|
||||||
gateway: gateway.clone(),
|
gateway: gateway.clone(),
|
||||||
public,
|
public,
|
||||||
hostname: IpHostname::Domain {
|
hostname: IpHostname::Domain {
|
||||||
@@ -540,7 +540,7 @@ impl NetServiceData {
|
|||||||
if let Some(ip_info) = &info.ip_info {
|
if let Some(ip_info) = &info.ip_info {
|
||||||
let public = info.public();
|
let public = info.public();
|
||||||
if let Some(wan_ip) = ip_info.wan_ip {
|
if let Some(wan_ip) = ip_info.wan_ip {
|
||||||
bind_hostname_info.push(HostnameInfo::Ip {
|
bind_hostname_info.push(HostnameInfo {
|
||||||
gateway: gateway.clone(),
|
gateway: gateway.clone(),
|
||||||
public: true,
|
public: true,
|
||||||
hostname: IpHostname::Ipv4 {
|
hostname: IpHostname::Ipv4 {
|
||||||
@@ -554,7 +554,7 @@ impl NetServiceData {
|
|||||||
match ipnet {
|
match ipnet {
|
||||||
IpNet::V4(net) => {
|
IpNet::V4(net) => {
|
||||||
if !public {
|
if !public {
|
||||||
bind_hostname_info.push(HostnameInfo::Ip {
|
bind_hostname_info.push(HostnameInfo {
|
||||||
gateway: gateway.clone(),
|
gateway: gateway.clone(),
|
||||||
public,
|
public,
|
||||||
hostname: IpHostname::Ipv4 {
|
hostname: IpHostname::Ipv4 {
|
||||||
@@ -566,7 +566,7 @@ impl NetServiceData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
IpNet::V6(net) => {
|
IpNet::V6(net) => {
|
||||||
bind_hostname_info.push(HostnameInfo::Ip {
|
bind_hostname_info.push(HostnameInfo {
|
||||||
gateway: gateway.clone(),
|
gateway: gateway.clone(),
|
||||||
public: public && !ipv6_is_local(net.addr()),
|
public: public && !ipv6_is_local(net.addr()),
|
||||||
hostname: IpHostname::Ipv6 {
|
hostname: IpHostname::Ipv6 {
|
||||||
|
|||||||
@@ -9,20 +9,14 @@ use crate::{GatewayId, HostId, ServiceInterfaceId};
|
|||||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[serde(rename_all_fields = "camelCase")]
|
pub struct HostnameInfo {
|
||||||
#[serde(tag = "kind")]
|
pub gateway: GatewayInfo,
|
||||||
pub enum HostnameInfo {
|
pub public: bool,
|
||||||
Ip {
|
pub hostname: IpHostname,
|
||||||
gateway: GatewayInfo,
|
|
||||||
public: bool,
|
|
||||||
hostname: IpHostname,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
impl HostnameInfo {
|
impl HostnameInfo {
|
||||||
pub fn to_san_hostname(&self) -> InternedString {
|
pub fn to_san_hostname(&self) -> InternedString {
|
||||||
match self {
|
self.hostname.to_san_hostname()
|
||||||
Self::Ip { hostname, .. } => hostname.to_san_hostname(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ impl VersionT for Version {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove onion entries from hostnameInfo in server host
|
// Remove onion entries from hostnameInfo in server host
|
||||||
remove_onion_hostname_info(
|
migrate_hostname_info(
|
||||||
db.get_mut("public")
|
db.get_mut("public")
|
||||||
.and_then(|p| p.get_mut("serverInfo"))
|
.and_then(|p| p.get_mut("serverInfo"))
|
||||||
.and_then(|s| s.get_mut("network"))
|
.and_then(|s| s.get_mut("network"))
|
||||||
@@ -74,7 +74,7 @@ impl VersionT for Version {
|
|||||||
for (_, package) in packages.iter_mut() {
|
for (_, package) in packages.iter_mut() {
|
||||||
if let Some(hosts) = package.get_mut("hosts").and_then(|h| h.as_object_mut()) {
|
if let Some(hosts) = package.get_mut("hosts").and_then(|h| h.as_object_mut()) {
|
||||||
for (_, host) in hosts.iter_mut() {
|
for (_, host) in hosts.iter_mut() {
|
||||||
remove_onion_hostname_info(Some(host));
|
migrate_hostname_info(Some(host));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,14 +96,21 @@ impl VersionT for Version {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_onion_hostname_info(host: Option<&mut Value>) {
|
fn migrate_hostname_info(host: Option<&mut Value>) {
|
||||||
if let Some(hostname_info) = host
|
if let Some(hostname_info) = host
|
||||||
.and_then(|h| h.get_mut("hostnameInfo"))
|
.and_then(|h| h.get_mut("hostnameInfo"))
|
||||||
.and_then(|h| h.as_object_mut())
|
.and_then(|h| h.as_object_mut())
|
||||||
{
|
{
|
||||||
for (_, infos) in hostname_info.iter_mut() {
|
for (_, infos) in hostname_info.iter_mut() {
|
||||||
if let Some(arr) = infos.as_array_mut() {
|
if let Some(arr) = infos.as_array_mut() {
|
||||||
|
// Remove onion entries
|
||||||
arr.retain(|info| info.get("kind").and_then(|k| k.as_str()) != Some("onion"));
|
arr.retain(|info| info.get("kind").and_then(|k| k.as_str()) != Some("onion"));
|
||||||
|
// Strip "kind" field from remaining entries (HostnameInfo flattened from enum to struct)
|
||||||
|
for info in arr.iter_mut() {
|
||||||
|
if let Some(obj) = info.as_object_mut() {
|
||||||
|
obj.remove("kind");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import type { GatewayInfo } from './GatewayInfo'
|
|||||||
import type { IpHostname } from './IpHostname'
|
import type { IpHostname } from './IpHostname'
|
||||||
|
|
||||||
export type HostnameInfo = {
|
export type HostnameInfo = {
|
||||||
kind: 'ip'
|
|
||||||
gateway: GatewayInfo
|
gateway: GatewayInfo
|
||||||
public: boolean
|
public: boolean
|
||||||
hostname: IpHostname
|
hostname: IpHostname
|
||||||
|
|||||||
@@ -43,19 +43,19 @@ type VisibilityFilter<V extends 'public' | 'private'> = V extends 'public'
|
|||||||
: never
|
: never
|
||||||
type KindFilter<K extends FilterKinds> = K extends 'mdns'
|
type KindFilter<K extends FilterKinds> = K extends 'mdns'
|
||||||
?
|
?
|
||||||
| (HostnameInfo & { kind: 'ip'; hostname: { kind: 'local' } })
|
| (HostnameInfo & { hostname: { kind: 'local' } })
|
||||||
| KindFilter<Exclude<K, 'mdns'>>
|
| KindFilter<Exclude<K, 'mdns'>>
|
||||||
: K extends 'domain'
|
: K extends 'domain'
|
||||||
?
|
?
|
||||||
| (HostnameInfo & { kind: 'ip'; hostname: { kind: 'domain' } })
|
| (HostnameInfo & { hostname: { kind: 'domain' } })
|
||||||
| KindFilter<Exclude<K, 'domain'>>
|
| KindFilter<Exclude<K, 'domain'>>
|
||||||
: K extends 'ipv4'
|
: K extends 'ipv4'
|
||||||
?
|
?
|
||||||
| (HostnameInfo & { kind: 'ip'; hostname: { kind: 'ipv4' } })
|
| (HostnameInfo & { hostname: { kind: 'ipv4' } })
|
||||||
| KindFilter<Exclude<K, 'ipv4'>>
|
| KindFilter<Exclude<K, 'ipv4'>>
|
||||||
: K extends 'ipv6'
|
: K extends 'ipv6'
|
||||||
?
|
?
|
||||||
| (HostnameInfo & { kind: 'ip'; hostname: { kind: 'ipv6' } })
|
| (HostnameInfo & { hostname: { kind: 'ipv6' } })
|
||||||
| KindFilter<Exclude<K, 'ipv6'>>
|
| KindFilter<Exclude<K, 'ipv6'>>
|
||||||
: K extends 'ip'
|
: K extends 'ip'
|
||||||
? KindFilter<Exclude<K, 'ip'> | 'ipv4' | 'ipv6'>
|
? KindFilter<Exclude<K, 'ip'> | 'ipv4' | 'ipv6'>
|
||||||
@@ -154,16 +154,14 @@ export const addressHostToUrl = (
|
|||||||
scheme in knownProtocols &&
|
scheme in knownProtocols &&
|
||||||
port === knownProtocols[scheme as keyof typeof knownProtocols].defaultPort
|
port === knownProtocols[scheme as keyof typeof knownProtocols].defaultPort
|
||||||
let hostname
|
let hostname
|
||||||
if (host.kind === 'ip') {
|
if (host.hostname.kind === 'domain') {
|
||||||
if (host.hostname.kind === 'domain') {
|
hostname = host.hostname.value
|
||||||
hostname = host.hostname.value
|
} else if (host.hostname.kind === 'ipv6') {
|
||||||
} else if (host.hostname.kind === 'ipv6') {
|
hostname = IPV6_LINK_LOCAL.contains(host.hostname.value)
|
||||||
hostname = IPV6_LINK_LOCAL.contains(host.hostname.value)
|
? `[${host.hostname.value}%${host.hostname.scopeId}]`
|
||||||
? `[${host.hostname.value}%${host.hostname.scopeId}]`
|
: `[${host.hostname.value}]`
|
||||||
: `[${host.hostname.value}]`
|
} else {
|
||||||
} else {
|
hostname = host.hostname.value
|
||||||
hostname = host.hostname.value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return `${scheme ? `${scheme}://` : ''}${
|
return `${scheme ? `${scheme}://` : ''}${
|
||||||
username ? `${username}@` : ''
|
username ? `${username}@` : ''
|
||||||
@@ -205,16 +203,13 @@ function filterRec(
|
|||||||
hostnames = hostnames.filter(
|
hostnames = hostnames.filter(
|
||||||
(h) =>
|
(h) =>
|
||||||
invert !==
|
invert !==
|
||||||
((kind.has('mdns') && h.kind === 'ip' && h.hostname.kind === 'local') ||
|
((kind.has('mdns') && h.hostname.kind === 'local') ||
|
||||||
(kind.has('domain') &&
|
(kind.has('domain') && h.hostname.kind === 'domain') ||
|
||||||
h.kind === 'ip' &&
|
(kind.has('ipv4') && h.hostname.kind === 'ipv4') ||
|
||||||
h.hostname.kind === 'domain') ||
|
(kind.has('ipv6') && h.hostname.kind === 'ipv6') ||
|
||||||
(kind.has('ipv4') && h.kind === 'ip' && h.hostname.kind === 'ipv4') ||
|
|
||||||
(kind.has('ipv6') && h.kind === 'ip' && h.hostname.kind === 'ipv6') ||
|
|
||||||
(kind.has('localhost') &&
|
(kind.has('localhost') &&
|
||||||
['localhost', '127.0.0.1', '::1'].includes(h.hostname.value)) ||
|
['localhost', '127.0.0.1', '::1'].includes(h.hostname.value)) ||
|
||||||
(kind.has('link-local') &&
|
(kind.has('link-local') &&
|
||||||
h.kind === 'ip' &&
|
|
||||||
h.hostname.kind === 'ipv6' &&
|
h.hostname.kind === 'ipv6' &&
|
||||||
IPV6_LINK_LOCAL.contains(IpAddress.parse(h.hostname.value)))),
|
IPV6_LINK_LOCAL.contains(IpAddress.parse(h.hostname.value)))),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ function cmpWithRankedPredicates<T extends AddressWithInfo>(
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type LanAddress = AddressWithInfo & { info: { kind: 'ip'; public: false } }
|
type LanAddress = AddressWithInfo & { info: { public: false } }
|
||||||
function filterLan(a: AddressWithInfo): a is LanAddress {
|
function filterLan(a: AddressWithInfo): a is LanAddress {
|
||||||
return a.info.kind === 'ip' && !a.info.public
|
return !a.info.public
|
||||||
}
|
}
|
||||||
function cmpLan(host: T.Host, a: LanAddress, b: LanAddress): -1 | 0 | 1 {
|
function cmpLan(host: T.Host, a: LanAddress, b: LanAddress): -1 | 0 | 1 {
|
||||||
return cmpWithRankedPredicates(a, b, [
|
return cmpWithRankedPredicates(a, b, [
|
||||||
@@ -45,15 +45,12 @@ function cmpLan(host: T.Host, a: LanAddress, b: LanAddress): -1 | 0 | 1 {
|
|||||||
|
|
||||||
type VpnAddress = AddressWithInfo & {
|
type VpnAddress = AddressWithInfo & {
|
||||||
info: {
|
info: {
|
||||||
kind: 'ip'
|
|
||||||
public: false
|
public: false
|
||||||
hostname: { kind: 'ipv4' | 'ipv6' | 'domain' }
|
hostname: { kind: 'ipv4' | 'ipv6' | 'domain' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function filterVpn(a: AddressWithInfo): a is VpnAddress {
|
function filterVpn(a: AddressWithInfo): a is VpnAddress {
|
||||||
return (
|
return !a.info.public && a.info.hostname.kind !== 'local'
|
||||||
a.info.kind === 'ip' && !a.info.public && a.info.hostname.kind !== 'local'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
function cmpVpn(host: T.Host, a: VpnAddress, b: VpnAddress): -1 | 0 | 1 {
|
function cmpVpn(host: T.Host, a: VpnAddress, b: VpnAddress): -1 | 0 | 1 {
|
||||||
return cmpWithRankedPredicates(a, b, [
|
return cmpWithRankedPredicates(a, b, [
|
||||||
@@ -68,13 +65,12 @@ function cmpVpn(host: T.Host, a: VpnAddress, b: VpnAddress): -1 | 0 | 1 {
|
|||||||
|
|
||||||
type ClearnetAddress = AddressWithInfo & {
|
type ClearnetAddress = AddressWithInfo & {
|
||||||
info: {
|
info: {
|
||||||
kind: 'ip'
|
|
||||||
public: true
|
public: true
|
||||||
hostname: { kind: 'ipv4' | 'ipv6' | 'domain' }
|
hostname: { kind: 'ipv4' | 'ipv6' | 'domain' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function filterClearnet(a: AddressWithInfo): a is ClearnetAddress {
|
function filterClearnet(a: AddressWithInfo): a is ClearnetAddress {
|
||||||
return a.info.kind === 'ip' && a.info.public
|
return a.info.public
|
||||||
}
|
}
|
||||||
function cmpClearnet(
|
function cmpClearnet(
|
||||||
host: T.Host,
|
host: T.Host,
|
||||||
@@ -134,10 +130,7 @@ export class InterfaceService {
|
|||||||
h,
|
h,
|
||||||
)
|
)
|
||||||
const info = h
|
const info = h
|
||||||
const gateway =
|
const gateway = gateways.find(g => h.gateway.id === g.id)
|
||||||
h.kind === 'ip'
|
|
||||||
? gateways.find(g => h.gateway.id === g.id)
|
|
||||||
: undefined
|
|
||||||
const res = []
|
const res = []
|
||||||
if (url) {
|
if (url) {
|
||||||
res.push({
|
res.push({
|
||||||
@@ -266,10 +259,9 @@ export class InterfaceService {
|
|||||||
h =>
|
h =>
|
||||||
this.config.accessType === 'localhost' ||
|
this.config.accessType === 'localhost' ||
|
||||||
!(
|
!(
|
||||||
h.kind === 'ip' &&
|
(h.hostname.kind === 'ipv6' &&
|
||||||
((h.hostname.kind === 'ipv6' &&
|
|
||||||
utils.IPV6_LINK_LOCAL.contains(h.hostname.value)) ||
|
utils.IPV6_LINK_LOCAL.contains(h.hostname.value)) ||
|
||||||
h.gateway.id === 'lo')
|
h.gateway.id === 'lo'
|
||||||
),
|
),
|
||||||
) || []
|
) || []
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user