fix all types

This commit is contained in:
Matt Hill
2025-08-16 23:14:19 -06:00
parent f7f0b7dc1a
commit a0a2c20b08
12 changed files with 83 additions and 91 deletions

View File

@@ -42,7 +42,7 @@ function cmpLan(host: T.Host, a: LanAddress, b: LanAddress): -1 | 0 | 1 {
return cmpWithRankedPredicates(a, b, [ return cmpWithRankedPredicates(a, b, [
x => x =>
x.info.hostname.kind === 'domain' && x.info.hostname.kind === 'domain' &&
!!host.privateDomains[x.info.hostname.value], // private domain !!host.privateDomains.find(d => d === x.info.hostname.value), // private domain
x => x.info.hostname.kind === 'local', // .local x => x.info.hostname.kind === 'local', // .local
x => x.info.hostname.kind === 'ipv4', // ipv4 x => x.info.hostname.kind === 'ipv4', // ipv4
x => x.info.hostname.kind === 'ipv6', // ipv6 x => x.info.hostname.kind === 'ipv6', // ipv6
@@ -66,7 +66,7 @@ function cmpVpn(host: T.Host, a: VpnAddress, b: VpnAddress): -1 | 0 | 1 {
return cmpWithRankedPredicates(a, b, [ return cmpWithRankedPredicates(a, b, [
x => x =>
x.info.hostname.kind === 'domain' && x.info.hostname.kind === 'domain' &&
!!host.privateDomains[x.info.hostname.value], // private domain !!host.privateDomains.find(d => d === x.info.hostname.value), // private domain
x => x.info.hostname.kind === 'ipv4', // ipv4 x => x.info.hostname.kind === 'ipv4', // ipv4
x => x.info.hostname.kind === 'ipv6', // ipv6 x => x.info.hostname.kind === 'ipv6', // ipv6
// remainder: public domains accessible privately // remainder: public domains accessible privately
@@ -102,7 +102,7 @@ function cmpClearnet(
function toDisplayAddress( function toDisplayAddress(
{ info, url }: AddressWithInfo, { info, url }: AddressWithInfo,
gateways: GatewayPlus[], gateways: GatewayPlus[],
publicDomains: Record<string, T.DomainConfig>, publicDomains: Record<string, T.PublicDomainConfig>,
): DisplayAddress { ): DisplayAddress {
let access: DisplayAddress['access'] let access: DisplayAddress['access']
let gatewayName: DisplayAddress['gatewayName'] let gatewayName: DisplayAddress['gatewayName']
@@ -248,11 +248,13 @@ function toDisplayAddress(
} }
export function getPublicDomains( export function getPublicDomains(
publicDomains: Record<string, T.DomainConfig>, publicDomains: Record<string, T.PublicDomainConfig>,
gateways: GatewayPlus[],
): PublicDomain[] { ): PublicDomain[] {
return Object.entries(publicDomains).map(([fqdn, info]) => ({ return Object.entries(publicDomains).map(([fqdn, info]) => ({
fqdn, fqdn,
...info, acme: info.acme,
gateway: gateways.find(g => g.id === info.gateway) || null,
})) }))
} }
@@ -302,18 +304,11 @@ export class InterfaceService {
return { return {
common: bestAddrs.map(a => common: bestAddrs.map(a =>
toDisplayAddress(a, gateways, host.publicDomains, host.privateDomains), toDisplayAddress(a, gateways, host.publicDomains),
), ),
uncommon: allAddressesWithInfo uncommon: allAddressesWithInfo
.filter(a => !bestAddrs.includes(a)) .filter(a => !bestAddrs.includes(a))
.map(a => .map(a => toDisplayAddress(a, gateways, host.publicDomains)),
toDisplayAddress(
a,
gateways,
host.publicDomains,
host.privateDomains,
),
),
} }
} }

View File

@@ -150,9 +150,8 @@ export class DnsComponent {
this.loading.set(true) this.loading.set(true)
try { try {
const ip = await this.api.testDns({ const ip = await this.api.queryDns({
fqdn: this.context.data.fqdn, fqdn: this.context.data.fqdn,
gateway: this.context.data.gateway.id,
}) })
this.pass.set(ip === this.context.data.gateway.ipInfo.wanIp) this.pass.set(ip === this.context.data.gateway.ipInfo.wanIp)

View File

@@ -39,7 +39,7 @@ import { PublicDomain, PublicDomainService } from './pd.service'
</header> </header>
<table [appTable]="['Domain', 'Gateway', 'Certificate Authority', null]"> <table [appTable]="['Domain', 'Gateway', 'Certificate Authority', null]">
@for (domain of publicDomains(); track $index) { @for (domain of publicDomains(); track $index) {
<tr [domain]="domain"></tr> <tr [publicDomain]="domain"></tr>
} @empty { } @empty {
@if (publicDomains()) { @if (publicDomains()) {
<tr> <tr>

View File

@@ -16,10 +16,10 @@ import { PublicDomain, PublicDomainService } from './pd.service'
import { toAuthorityName } from 'src/app/utils/acme' import { toAuthorityName } from 'src/app/utils/acme'
@Component({ @Component({
selector: 'tr[domain]', selector: 'tr[publicDomain]',
template: ` template: `
<td>{{ domain().fqdn }}</td> <td>{{ publicDomain().fqdn }}</td>
<td>{{ domain().gateway }}</td> <td>{{ publicDomain().gateway?.ipInfo?.name }}</td>
<td>{{ authority() }}</td> <td>{{ authority() }}</td>
<td> <td>
<button <button
@@ -39,7 +39,11 @@ import { toAuthorityName } from 'src/app/utils/acme'
new new
iconStart="@tui.eye" iconStart="@tui.eye"
(click)=" (click)="
service.showDns(domain().fqdn, domain().gateway, dnsMessage()) service.showDns(
publicDomain().fqdn,
publicDomain().gateway!,
dnsMessage()
)
" "
> >
{{ 'View DNS' | i18n }} {{ 'View DNS' | i18n }}
@@ -48,7 +52,7 @@ import { toAuthorityName } from 'src/app/utils/acme'
tuiOption tuiOption
new new
iconStart="@tui.pencil" iconStart="@tui.pencil"
(click)="service.edit(domain())" (click)="service.edit(publicDomain())"
> >
{{ 'Edit' | i18n }} {{ 'Edit' | i18n }}
</button> </button>
@@ -59,7 +63,7 @@ import { toAuthorityName } from 'src/app/utils/acme'
new new
iconStart="@tui.trash" iconStart="@tui.trash"
class="g-negative" class="g-negative"
(click)="service.remove(domain().fqdn)" (click)="service.remove(publicDomain().fqdn)"
> >
{{ 'Delete' | i18n }} {{ 'Delete' | i18n }}
</button> </button>
@@ -99,11 +103,11 @@ export class PublicDomainsItemComponent {
open = false open = false
readonly domain = input.required<PublicDomain>() readonly publicDomain = input.required<PublicDomain>()
readonly authority = computed(() => toAuthorityName(this.domain().acme)) readonly authority = computed(() => toAuthorityName(this.publicDomain().acme))
readonly dnsMessage = computed<i18nKey>( readonly dnsMessage = computed<i18nKey>(
() => () =>
`Create one of the DNS records below to cause ${this.domain().fqdn} to resolve to ${this.domain().gateway.ipInfo.wanIp}` as i18nKey, `Create one of the DNS records below to cause ${this.publicDomain().fqdn} to resolve to ${this.publicDomain().gateway?.ipInfo.wanIp}` as i18nKey,
) )
} }

View File

@@ -15,7 +15,6 @@ import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
import { PatchDB } from 'patch-db-client' import { PatchDB } from 'patch-db-client'
import { DataModel } from 'src/app/services/patch-db/data-model' import { DataModel } from 'src/app/services/patch-db/data-model'
import { toAuthorityName } from 'src/app/utils/acme' import { toAuthorityName } from 'src/app/utils/acme'
import { GatewayPlus } from 'src/app/services/gateway.service'
import { InterfaceComponent } from '../interface.component' import { InterfaceComponent } from '../interface.component'
import { DNS } from './dns.component' import { DNS } from './dns.component'
@@ -23,7 +22,7 @@ import { DNS } from './dns.component'
export type PublicDomain = { export type PublicDomain = {
fqdn: string fqdn: string
gateway: GatewayPlus gateway: GatewayWithId | null
acme: string | null acme: string | null
} }
@@ -104,7 +103,7 @@ export class PublicDomainService {
}, },
], ],
value: { value: {
gateway: domain.gateway.id, gateway: domain.gateway!.id,
authority: domain.acme, authority: domain.acme,
}, },
}, },

View File

@@ -48,7 +48,7 @@ export class ServiceInterfacesComponent {
readonly pkg = input.required<PackageDataEntry>() readonly pkg = input.required<PackageDataEntry>()
readonly disabled = input(false) readonly disabled = input(false)
readonly interfaces = computed(({ serviceInterfaces, hosts } = this.pkg()) => readonly interfaces = computed(({ serviceInterfaces } = this.pkg()) =>
Object.entries(serviceInterfaces) Object.entries(serviceInterfaces)
.sort((a, b) => tuiDefaultSort(a[1], b[1])) .sort((a, b) => tuiDefaultSort(a[1], b[1]))
.map(([id, value]) => { .map(([id, value]) => {

View File

@@ -100,10 +100,6 @@ export default class ServiceInterfaceRoute {
readonly pkg = toSignal(this.patch.watch$('packageData', this.pkgId)) readonly pkg = toSignal(this.patch.watch$('packageData', this.pkgId))
readonly domains = toSignal(
this.patch.watch$('serverInfo', 'network', 'domains'),
)
readonly isRunning = computed(() => { readonly isRunning = computed(() => {
return this.pkg()?.status.main === 'running' return this.pkg()?.status.main === 'running'
}) })
@@ -111,9 +107,8 @@ export default class ServiceInterfaceRoute {
readonly serviceInterface = computed(() => { readonly serviceInterface = computed(() => {
const pkg = this.pkg() const pkg = this.pkg()
const id = this.interfaceId() const id = this.interfaceId()
const domains = this.domains()
if (!pkg || !id || !domains) { if (!pkg || !id) {
return return
} }
@@ -131,20 +126,15 @@ export default class ServiceInterfaceRoute {
return { return {
...iFace, ...iFace,
addresses: this.interfaceService.getAddresses( addresses: this.interfaceService.getAddresses(iFace, host, gateways),
iFace,
host,
domains,
gateways,
),
gateways: gateways:
gateways.map(g => ({ gateways.map(g => ({
enabled: true, enabled: true,
...g, ...g,
})) || [], })) || [],
torDomains: host.onions.map(o => `${o}.onion`), torDomains: host.onions.map(o => `${o}.onion`),
publicDomains: getPublicDomains(host.domains.public), publicDomains: getPublicDomains(host.publicDomains, gateways),
privateDomains: host.domains.private, privateDomains: host.privateDomains,
isOs: false, isOs: false,
} }
}) })

View File

@@ -158,19 +158,27 @@ export default class SystemDnsComponent {
switchMap(async ([pkgs, { gateways, dns }]) => { switchMap(async ([pkgs, { gateways, dns }]) => {
const spec = await configBuilderToSpec(this.dnsSpec) const spec = await configBuilderToSpec(this.dnsSpec)
const selection = dns.static ? 'custom' : 'defaults' const current = dns.staticServers
? {
selection: 'custom',
value: dns.staticServers,
}
: { selection: 'defaults', value: dns.dhcpServers }
const form = this.formService.createForm(spec, { const form = this.formService.createForm(spec, current)
strategy: { selection, value: dns.servers },
})
return { return {
spec, spec,
form, form,
warn: warn:
(Object.values(pkgs).some(p => p) || []) && (Object.values(pkgs).some(p =>
Object.values(p.hosts).some(h => h?.privateDomains.length),
) ||
[]) &&
Object.values(gateways) Object.values(gateways)
.filter(g => dns.servers.includes(g.ipInfo?.lanIp)) .filter(g =>
dns.dhcpServers.some(d => g.ipInfo?.lanIp.includes(d)),
)
.map(g => g.ipInfo?.name), .map(g => g.ipInfo?.name),
} }
}), }),

View File

@@ -89,7 +89,6 @@ export default class StartOsUiComponent {
addresses: this.interfaceService.getAddresses( addresses: this.interfaceService.getAddresses(
this.iface, this.iface,
network.host, network.host,
network.domains,
gateways, gateways,
), ),
gateways: gateways.map(g => ({ gateways: gateways.map(g => ({
@@ -97,8 +96,8 @@ export default class StartOsUiComponent {
...g, ...g,
})), })),
torDomains: network.host.onions.map(o => `${o}.onion`), torDomains: network.host.onions.map(o => `${o}.onion`),
publicDomains: getPublicDomains(network.host.domains.public), publicDomains: getPublicDomains(network.host.publicDomains, gateways),
privateDomains: network.host.domains.private, privateDomains: network.host.privateDomains,
isOs: true, isOs: true,
} }
}) })

View File

@@ -2069,11 +2069,9 @@ export namespace Mock {
}, },
}, },
}, },
publicDomains: {},
privateDomains: [],
onions: [], onions: [],
domains: {
public: {},
private: {},
},
hostnameInfo: { hostnameInfo: {
80: [ 80: [
{ {
@@ -2172,11 +2170,9 @@ export namespace Mock {
}, },
}, },
}, },
publicDomains: {},
privateDomains: [],
onions: [], onions: [],
domains: {
public: {},
private: {},
},
hostnameInfo: { hostnameInfo: {
8332: [], 8332: [],
}, },
@@ -2198,11 +2194,9 @@ export namespace Mock {
}, },
}, },
}, },
publicDomains: {},
privateDomains: [],
onions: [], onions: [],
domains: {
public: {},
private: {},
},
hostnameInfo: { hostnameInfo: {
8333: [], 8333: [],
}, },

View File

@@ -582,9 +582,11 @@ export class MockApiService extends ApiService {
name: params.name, name: params.name,
scopeId: 3, scopeId: 3,
deviceType: 'wireguard', deviceType: 'wireguard',
subnets: [], subnets: ['192.168.1.10/24'],
wanIp: '1.1.1.1', wanIp: '203.0.113.45',
ntpServers: [], ntpServers: [],
lanIp: ['192.168.1.10'],
dnsServers: [],
}, },
}, },
}, },
@@ -1417,7 +1419,7 @@ export class MockApiService extends ApiService {
const patch: Operation<any>[] = [ const patch: Operation<any>[] = [
{ {
op: PatchOp.ADD, op: PatchOp.ADD,
path: `/serverInfo/host/domains/public`, path: `/serverInfo/host/publicDomains`,
value: { value: {
[params.fqdn]: { gateway: params.gateway, acme: params.acme }, [params.fqdn]: { gateway: params.gateway, acme: params.acme },
}, },
@@ -1452,7 +1454,7 @@ export class MockApiService extends ApiService {
const patch: RemoveOperation[] = [ const patch: RemoveOperation[] = [
{ {
op: PatchOp.REMOVE, op: PatchOp.REMOVE,
path: `/serverInfo/host/domains/public/${params.fqdn}`, path: `/serverInfo/host/publicDomains/${params.fqdn}`,
}, },
{ {
op: PatchOp.REMOVE, op: PatchOp.REMOVE,
@@ -1472,7 +1474,7 @@ export class MockApiService extends ApiService {
const patch: Operation<any>[] = [ const patch: Operation<any>[] = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: `/serverInfo/host/domains/private`, path: `/serverInfo/host/privateDomains`,
value: [params.fqdn], value: [params.fqdn],
}, },
{ {
@@ -1505,7 +1507,7 @@ export class MockApiService extends ApiService {
const patch: Operation<any>[] = [ const patch: Operation<any>[] = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: `/serverInfo/host/domains/private`, path: `/serverInfo/host/privateDomains`,
value: [], value: [],
}, },
{ {
@@ -1590,7 +1592,7 @@ export class MockApiService extends ApiService {
const patch: Operation<any>[] = [ const patch: Operation<any>[] = [
{ {
op: PatchOp.ADD, op: PatchOp.ADD,
path: `/packageData/${params.package}/hosts/${params.host}/domains/public`, path: `/packageData/${params.package}/hosts/${params.host}/publicDomains`,
value: { value: {
[params.fqdn]: { gateway: params.gateway, acme: params.acme }, [params.fqdn]: { gateway: params.gateway, acme: params.acme },
}, },
@@ -1625,7 +1627,7 @@ export class MockApiService extends ApiService {
const patch: RemoveOperation[] = [ const patch: RemoveOperation[] = [
{ {
op: PatchOp.REMOVE, op: PatchOp.REMOVE,
path: `/packageData/${params.package}/hosts/${params.host}/domains/public/${params.fqdn}`, path: `/packageData/${params.package}/hosts/${params.host}/publicDomains/${params.fqdn}`,
}, },
{ {
op: PatchOp.REMOVE, op: PatchOp.REMOVE,
@@ -1645,7 +1647,7 @@ export class MockApiService extends ApiService {
const patch: Operation<any>[] = [ const patch: Operation<any>[] = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: `/packageData/${params.package}/hosts/${params.host}/domains/private`, path: `/packageData/${params.package}/hosts/${params.host}/privateDomains`,
value: [params.fqdn], value: [params.fqdn],
}, },
{ {
@@ -1678,7 +1680,7 @@ export class MockApiService extends ApiService {
const patch: Operation<any>[] = [ const patch: Operation<any>[] = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: `/packageData/${params.package}/hosts/${params.host}/domains/private`, path: `/packageData/${params.package}/hosts/${params.host}/privateDomains`,
value: [], value: [],
}, },
{ {

View File

@@ -52,10 +52,8 @@ export const mockPatchData: DataModel = {
}, },
}, },
}, },
domains: { publicDomains: {},
public: {}, privateDomains: [],
private: {},
},
onions: ['myveryownspecialtoraddress'], onions: ['myveryownspecialtoraddress'],
hostnameInfo: { hostnameInfo: {
80: [ 80: [
@@ -149,6 +147,8 @@ export const mockPatchData: DataModel = {
subnets: ['10.0.0.2/24'], subnets: ['10.0.0.2/24'],
wanIp: '203.0.113.45', wanIp: '203.0.113.45',
ntpServers: [], ntpServers: [],
lanIp: ['10.0.2.12'],
dnsServers: [],
}, },
}, },
wlan0: { wlan0: {
@@ -164,6 +164,8 @@ export const mockPatchData: DataModel = {
], ],
wanIp: '203.0.113.45', wanIp: '203.0.113.45',
ntpServers: [], ntpServers: [],
lanIp: ['10.0.90.12'],
dnsServers: ['8.8.8.8'],
}, },
}, },
wireguard1: { wireguard1: {
@@ -179,9 +181,15 @@ export const mockPatchData: DataModel = {
], ],
wanIp: '203.0.113.45', wanIp: '203.0.113.45',
ntpServers: [], ntpServers: [],
lanIp: ['10.0.90.12'],
dnsServers: ['1.1.1.1'],
}, },
}, },
}, },
dns: {
dhcpServers: ['1.1.1.1', '8.8.8.8'],
staticServers: null,
},
}, },
unreadNotificationCount: 4, unreadNotificationCount: 4,
// password is asdfasdf // password is asdfasdf
@@ -338,11 +346,9 @@ export const mockPatchData: DataModel = {
}, },
}, },
}, },
publicDomains: {},
privateDomains: [],
onions: [], onions: [],
domains: {
public: {},
private: {},
},
hostnameInfo: { hostnameInfo: {
80: [ 80: [
{ {
@@ -441,11 +447,9 @@ export const mockPatchData: DataModel = {
}, },
}, },
}, },
publicDomains: {},
privateDomains: [],
onions: [], onions: [],
domains: {
public: {},
private: {},
},
hostnameInfo: { hostnameInfo: {
8332: [], 8332: [],
}, },
@@ -467,11 +471,9 @@ export const mockPatchData: DataModel = {
}, },
}, },
}, },
publicDomains: {},
privateDomains: [],
onions: [], onions: [],
domains: {
public: {},
private: {},
},
hostnameInfo: { hostnameInfo: {
8333: [], 8333: [],
}, },