fix patch db types and comment out future domain and proxy features

This commit is contained in:
Matt Hill
2025-02-11 21:17:20 -07:00
parent 7d1096dbd8
commit ce2842d365
12 changed files with 259 additions and 297 deletions

View File

@@ -28,7 +28,7 @@ export class NotificationsToastComponent {
readonly visible$: Observable<boolean> = merge(
this.dismiss$,
inject<PatchDB<DataModel>>(PatchDB)
.watch$('serverInfo', 'unreadNotifications', 'count')
.watch$('serverInfo', 'unreadNotificationCount')
.pipe(
pairwise(),
map(([prev, cur]) => cur > prev),

View File

@@ -22,14 +22,14 @@ export const REMOVE: Partial<TuiDialogOptions<TuiConfirmData>> = {
export function getClearnetSpec({
domains,
start9ToSubdomain,
start9To,
}: NetworkInfo): Promise<IST.InputSpec> {
const start9ToDomain = `${start9ToSubdomain?.value}.start9.to`
const base = start9ToSubdomain ? { [start9ToDomain]: start9ToDomain } : {}
const start9ToDomain = `${start9To?.subdomain}.start9.to`
const base = start9To ? { [start9ToDomain]: start9ToDomain } : {}
const values = domains.reduce((prev, curr) => {
const values = Object.keys(domains).reduce((prev, curr) => {
return {
[curr.value]: curr.value,
[curr]: curr,
...prev,
}
}, base)
@@ -38,7 +38,7 @@ export function getClearnetSpec({
ISB.InputSpec.of({
domain: ISB.Value.select({
name: 'Domain',
default: domains[0].value,
default: '',
values,
}),
subdomain: ISB.Value.text({

View File

@@ -68,23 +68,14 @@ export class SettingsDomainsComponent {
private readonly api = inject(ApiService)
private readonly dialogs = inject(TuiDialogService)
readonly domains$ = this.patch.watch$('serverInfo', 'network').pipe(
map(network => {
const start9ToSubdomain = network.start9ToSubdomain
const start9To = !start9ToSubdomain
? []
: [
{
...start9ToSubdomain,
value: `${start9ToSubdomain.value}.start9.to`,
provider: 'Start9',
},
]
return { start9To, custom: network.domains }
}),
private readonly start9To$ = this.patch.watch$(
'serverInfo',
'network',
'start9To',
)
readonly domains$ = this.patch.watch$('serverInfo', 'network', 'domains')
delete(hostname?: string) {
this.dialogs
.open(TUI_CONFIRM, {

View File

@@ -46,12 +46,12 @@ export class StartOsUiComponent {
readonly ui$: Observable<MappedServiceInterface> = inject<PatchDB<DataModel>>(
PatchDB,
)
.watch$('serverInfo')
.watch$('serverInfo', 'network', 'host')
.pipe(
map(server => ({
map(host => ({
...iface,
public: server.host.bindings[iface.addressInfo.internalPort].net.public,
addresses: getAddresses(iface, server.host, this.config),
public: host.bindings[iface.addressInfo.internalPort].net.public,
addresses: getAddresses(iface, host, this.config),
})),
)
}

View File

@@ -19,27 +19,27 @@ export default [
m => m.SettingsEmailComponent,
),
},
{
path: 'domains',
loadComponent: () =>
import('./routes/domains/domains.component').then(
m => m.SettingsDomainsComponent,
),
},
{
path: 'proxies',
loadComponent: () =>
import('./routes/proxies/proxies.component').then(
m => m.SettingsProxiesComponent,
),
},
{
path: 'router',
loadComponent: () =>
import('./routes/router/router.component').then(
m => m.SettingsRouterComponent,
),
},
// {
// path: 'domains',
// loadComponent: () =>
// import('./routes/domains/domains.component').then(
// m => m.SettingsDomainsComponent,
// ),
// },
// {
// path: 'proxies',
// loadComponent: () =>
// import('./routes/proxies/proxies.component').then(
// m => m.SettingsProxiesComponent,
// ),
// },
// {
// path: 'router',
// loadComponent: () =>
// import('./routes/router/router.component').then(
// m => m.SettingsRouterComponent,
// ),
// },
{
path: 'wifi',
loadComponent: () =>

View File

@@ -63,24 +63,24 @@ export class SettingsService {
},
],
Network: [
{
title: 'Domains',
description: 'Manage domains for clearnet connectivity',
icon: '@tui.globe',
routerLink: 'domains',
},
{
title: 'Proxies',
description: 'Manage proxies for inbound and outbound connections',
icon: '@tui.shuffle',
routerLink: 'proxies',
},
{
title: 'Router Config',
description: 'Connect or configure your router for clearnet',
icon: '@tui.radio',
routerLink: 'router',
},
// {
// title: 'Domains',
// description: 'Manage domains for clearnet connectivity',
// icon: '@tui.globe',
// routerLink: 'domains',
// },
// {
// title: 'Proxies',
// description: 'Manage proxies for inbound and outbound connections',
// icon: '@tui.shuffle',
// routerLink: 'proxies',
// },
// {
// title: 'Router Config',
// description: 'Connect or configure your router for clearnet',
// icon: '@tui.radio',
// routerLink: 'router',
// },
{
title: 'WiFi',
description: 'Add or remove WiFi networks',
@@ -109,12 +109,12 @@ export class SettingsService {
},
],
'Privacy and Security': [
{
title: 'Outbound Proxy',
description: 'Proxy outbound traffic from the StartOS main process',
icon: '@tui.shield',
action: () => this.setOutboundProxy(),
},
// {
// title: 'Outbound Proxy',
// description: 'Proxy outbound traffic from the StartOS main process',
// icon: '@tui.shield',
// action: () => this.setOutboundProxy(),
// },
{
title: 'SSH',
description:
@@ -154,12 +154,12 @@ export class SettingsService {
],
}
private async setOutboundProxy(): Promise<void> {
const proxy = await firstValueFrom(
this.patch.watch$('serverInfo', 'network', 'outboundProxy'),
)
await this.proxyService.presentModalSetOutboundProxy(proxy)
}
// private async setOutboundProxy(): Promise<void> {
// const proxy = await firstValueFrom(
// this.patch.watch$('serverInfo', 'network', 'outboundProxy'),
// )
// await this.proxyService.presentModalSetOutboundProxy(proxy)
// }
private promptResetTor() {
this.wipe = false

View File

@@ -1,7 +1,4 @@
import {
DomainInfo,
NetworkStrategy,
} from 'src/app/services/patch-db/data-model'
import { DomainInfo } from 'src/app/services/patch-db/data-model'
import { FetchLogsReq, FetchLogsRes } from '@start9labs/shared'
import { Dump } from 'patch-db-client'
import { DataModel } from 'src/app/services/patch-db/data-model'
@@ -184,7 +181,7 @@ export module RR {
// domains
export type ClaimStart9ToReq = { networkStrategy: NetworkStrategy } // net.domain.me.claim
export type ClaimStart9ToReq = { networkInterfaceId: string } // net.domain.me.claim
export type ClaimStart9ToRes = null
export type DeleteStart9ToReq = {} // net.domain.me.delete
@@ -197,7 +194,7 @@ export module RR {
username: string | null
password: string | null
}
networkStrategy: NetworkStrategy
networkInterfaceId: string
} // net.domain.add
export type AddDomainRes = null
@@ -677,10 +674,10 @@ export type ServerNotification<T extends number> = {
export type NotificationData<T> = T extends 0
? null
: T extends 1
? BackupReport
: T extends 2
? string
: any
? BackupReport
: T extends 2
? string
: any
export type BackupReport = {
server: {

View File

@@ -13,7 +13,6 @@ import {
import {
InstallingState,
PackageDataEntry,
Proxy,
StateInfo,
UpdatingState,
} from 'src/app/services/patch-db/data-model'
@@ -574,25 +573,22 @@ export class MockApiService extends ApiService {
async addProxy(params: RR.AddProxyReq): Promise<RR.AddProxyRes> {
await pauseFor(2000)
const type: Proxy['type'] = 'inbound-outbound'
const patch = [
{
op: PatchOp.REPLACE,
path: '/serverInfo/network/proxies',
value: [
{
id: 'abcd-efgh-ijkl-mnop',
op: PatchOp.ADD,
path: `/serverInfo/network/networkInterfaces/wga1`,
value: {
inbound: true,
outbound: true,
ipInfo: {
name: params.name,
createdAt: new Date(),
type,
endpoint: '10.25.2.17',
usedBy: {
domains: [],
services: [],
},
scopeId: 3,
deviceType: 'wireguard',
subnets: [],
wanIp: '1.1.1.1',
ntpServers: [],
},
],
},
},
]
this.mockRevision(patch)
@@ -639,12 +635,10 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/serverInfo/network/start9ToSubdomain',
path: '/serverInfo/network/start9To',
value: {
value: 'xyz',
createdAt: new Date(),
networkStrategy: params.networkStrategy,
usedBy: [],
subdomain: 'xyz',
networkInterfaceId: params.networkInterfaceId,
},
},
]
@@ -660,7 +654,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/serverInfo/network/start9ToSubdomain',
path: '/serverInfo/network/start9To',
value: null,
},
]
@@ -675,16 +669,13 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/serverInfo/network/domains',
value: [
{
value: params.hostname,
createdAt: new Date(),
path: `/serverInfo/network/domains`,
value: {
[params.hostname]: {
networkInterfaceId: params.networkInterfaceId,
provider: params.provider.name,
networkStrategy: params.networkStrategy,
usedBy: [],
},
],
},
},
]
this.mockRevision(patch)
@@ -698,7 +689,7 @@ export class MockApiService extends ApiService {
{
op: PatchOp.REPLACE,
path: '/serverInfo/network/domains',
value: [],
value: {},
},
]
this.mockRevision(patch)

View File

@@ -39,37 +39,142 @@ export const mockPatchData: DataModel = {
selected: null,
lastRegion: null,
},
start9ToSubdomain: null,
domains: [],
start9To: null,
domains: {},
wanConfig: {
upnp: true,
forwards: [],
},
proxies: [],
outboundProxy: null,
},
networkInterfaces: {
eth0: {
public: false,
ipInfo: {
scopeId: 1,
deviceType: 'ethernet',
subnets: ['10.0.0.2/24'],
wanIp: null,
ntpServers: [],
host: {
bindings: {
80: {
enabled: true,
net: {
assignedPort: null,
assignedSslPort: 443,
public: false,
},
options: {
preferredExternalPort: 80,
addSsl: {
preferredExternalPort: 443,
alpn: { specified: ['http/1.1', 'h2'] },
},
secure: null,
},
},
},
domains: {},
onions: ['myveryownspecialtoraddress'],
hostnameInfo: {
80: [
{
kind: 'ip',
networkInterfaceId: 'eth0',
public: false,
hostname: {
kind: 'local',
value: 'adjective-noun.local',
port: null,
sslPort: 443,
},
},
{
kind: 'ip',
networkInterfaceId: 'wlan0',
public: false,
hostname: {
kind: 'local',
value: 'adjective-noun.local',
port: null,
sslPort: 443,
},
},
{
kind: 'ip',
networkInterfaceId: 'eth0',
public: false,
hostname: {
kind: 'ipv4',
value: '10.0.0.1',
port: null,
sslPort: 443,
},
},
{
kind: 'ip',
networkInterfaceId: 'wlan0',
public: false,
hostname: {
kind: 'ipv4',
value: '10.0.0.2',
port: null,
sslPort: 443,
},
},
{
kind: 'ip',
networkInterfaceId: 'eth0',
public: false,
hostname: {
kind: 'ipv6',
value: 'fe80::cd00:0000:0cde:1257:0000:211e:72cd',
scopeId: 2,
port: null,
sslPort: 443,
},
},
{
kind: 'ip',
networkInterfaceId: 'wlan0',
public: false,
hostname: {
kind: 'ipv6',
value: 'fe80::cd00:0000:0cde:1257:0000:211e:1234',
scopeId: 3,
port: null,
sslPort: 443,
},
},
{
kind: 'onion',
hostname: {
value: 'myveryownspecialtoraddress.onion',
port: 80,
sslPort: 443,
},
},
],
},
},
wlan0: {
public: false,
ipInfo: {
scopeId: 2,
deviceType: 'wireless',
subnets: [
'10.0.90.12/24',
'fe80::cd00:0000:0cde:1257:0000:211e:72cd/64',
],
wanIp: null,
ntpServers: [],
networkInterfaces: {
eth0: {
inbound: false,
outbound: true,
ipInfo: {
name: 'Wired Connection 1',
scopeId: 1,
deviceType: 'ethernet',
subnets: ['10.0.0.2/24'],
wanIp: null,
ntpServers: [],
},
},
wlan0: {
inbound: false,
outbound: true,
ipInfo: {
name: 'Wireless Connection 1',
scopeId: 2,
deviceType: 'wireless',
subnets: [
'10.0.90.12/24',
'fe80::cd00:0000:0cde:1257:0000:211e:72cd/64',
],
wanIp: null,
ntpServers: [],
},
},
},
},
@@ -78,10 +183,7 @@ export const mockPatchData: DataModel = {
contact: ['mailto:support@start9.com'],
},
},
unreadNotifications: {
count: 4,
recent: Mock.Notifications,
},
unreadNotificationCount: 4,
// password is asdfasdf
passwordHash:
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
@@ -96,108 +198,6 @@ export const mockPatchData: DataModel = {
backupProgress: {},
},
hostname: 'random-words',
host: {
bindings: {
80: {
enabled: true,
net: {
assignedPort: null,
assignedSslPort: 443,
public: false,
},
options: {
preferredExternalPort: 80,
addSsl: {
preferredExternalPort: 443,
alpn: { specified: ['http/1.1', 'h2'] },
},
secure: null,
},
},
},
domains: {},
onions: ['myveryownspecialtoraddress'],
hostnameInfo: {
80: [
{
kind: 'ip',
networkInterfaceId: 'eth0',
public: false,
hostname: {
kind: 'local',
value: 'adjective-noun.local',
port: null,
sslPort: 443,
},
},
{
kind: 'ip',
networkInterfaceId: 'wlan0',
public: false,
hostname: {
kind: 'local',
value: 'adjective-noun.local',
port: null,
sslPort: 443,
},
},
{
kind: 'ip',
networkInterfaceId: 'eth0',
public: false,
hostname: {
kind: 'ipv4',
value: '10.0.0.1',
port: null,
sslPort: 443,
},
},
{
kind: 'ip',
networkInterfaceId: 'wlan0',
public: false,
hostname: {
kind: 'ipv4',
value: '10.0.0.2',
port: null,
sslPort: 443,
},
},
{
kind: 'ip',
networkInterfaceId: 'eth0',
public: false,
hostname: {
kind: 'ipv6',
value: 'fe80::cd00:0000:0cde:1257:0000:211e:72cd',
scopeId: 2,
port: null,
sslPort: 443,
},
},
{
kind: 'ip',
networkInterfaceId: 'wlan0',
public: false,
hostname: {
kind: 'ipv6',
value: 'fe80::cd00:0000:0cde:1257:0000:211e:1234',
scopeId: 3,
port: null,
sslPort: 443,
},
},
{
kind: 'onion',
hostname: {
value: 'myveryownspecialtoraddress.onion',
port: 80,
sslPort: 443,
},
},
],
},
},
pubkey: 'npub1sg6plzptd64u62a878hep2kev88swjh3tw00gjsfl8f237lmu63q0uf63m',
caFingerprint: 'SHA-256: 63 2B 11 99 44 40 17 DF 37 FC C3 DF 0F 3D 15',
ntpSynced: false,

View File

@@ -20,7 +20,7 @@ export class NotificationService {
private readonly localUnreadCount$ = new Subject<number>()
readonly unreadCount$ = merge(
this.patch.watch$('serverInfo', 'unreadNotifications', 'count'),
this.patch.watch$('serverInfo', 'unreadNotificationCount'),
this.localUnreadCount$,
).pipe(shareReplay(1))

View File

@@ -1,17 +1,13 @@
import { BackupJob, ServerNotifications } from '../api/api.types'
import { BackupJob } from '../api/api.types'
import { T } from '@start9labs/start-sdk'
export type DataModel = {
ui: UIData
serverInfo: Omit<
T.Public['serverInfo'],
'wifi' | 'unreadNotificationCount'
'wifi' | 'networkInterfaces' | 'host'
> & {
network: NetworkInfo
unreadNotifications: {
count: number
recent: ServerNotifications
}
}
packageData: Record<string, PackageDataEntry>
}
@@ -42,14 +38,30 @@ export type UIStore = {
}
export type NetworkInfo = {
wifi: WiFiInfo
start9ToSubdomain: Omit<Domain, 'provider'> | null
domains: Domain[]
wifi: T.WifiInfo & { enabled: boolean }
host: T.Host
networkInterfaces: {
[id: string]: {
inbound: boolean | null
outbound: boolean | null
ipInfo:
| (T.IpInfo & {
name: string
})
| null
}
}
start9To: {
subdomain: string
networkInterfaceId: string
} | null
domains: {
[key: string]: Domain
}
wanConfig: {
upnp: boolean
forwards: PortForward[]
}
proxies: Proxy[]
outboundProxy: string | null
}
@@ -65,40 +77,9 @@ export type PortForward = {
error: string | null
}
export type WiFiInfo = {
enabled: boolean
lastRegion: string | null
interface: string | null
ssids: Array<string>
selected: string | null
}
export type Domain = {
value: string
createdAt: string
provider: string
networkStrategy: NetworkStrategy
usedBy: {
service: { id: string | null; title: string } // null means startos
interfaces: { id: string | null; title: string }[] // null means startos
}[]
}
export type NetworkStrategy =
| { proxy: string }
| { ipStrategy: 'ipv4' | 'ipv6' | 'dualstack' }
export type Proxy = {
id: string
name: string
createdAt: string
type: 'outbound' | 'inbound-outbound' | 'vlan' | { error: string }
endpoint: string
// below is overlay only
usedBy: {
services: { id: string | null; title: string }[] // implies outbound - null means startos
domains: string[] // implies inbound
}
networkInterfaceId: string
}
export interface ServerStatusInfo {

View File

@@ -26,18 +26,20 @@ export class ProxyService {
) {}
async presentModalSetOutboundProxy(current: string | null, pkgId?: string) {
const network = await firstValueFrom(
this.patch.watch$('serverInfo', 'network'),
const networkInterfaces = await firstValueFrom(
this.patch.watch$('serverInfo', 'network', 'networkInterfaces'),
)
const config = ISB.InputSpec.of({
proxyId: ISB.Value.select({
name: 'Select Proxy',
default: current || '',
values: network.proxies
.filter(p => p.type === 'outbound' || p.type === 'inbound-outbound')
values: Object.entries(networkInterfaces)
.filter(
([_, n]) => n.outbound && n.ipInfo?.deviceType === 'wireguard',
)
.reduce<Record<string, string>>(
(prev, curr) => ({
[curr.id]: curr.name,
(prev, [id, n]) => ({
[id]: n.ipInfo!.name,
...prev,
}),
{},