mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
Gateways, domains, and new service interface (#3001)
* add support for inbound proxies * backend changes * fix file type * proxy -> tunnel, implement backend apis * wip start-tunneld * add domains and gateways, remove routers, fix docs links * dont show hidden actions * show and test dns * edit instead of chnage acme and change gateway * refactor: domains page * refactor: gateways page * domains and acme refactor * certificate authorities * refactor public/private gateways * fix fe types * domains mostly finished * refactor: add file control to form service * add ip util to sdk * domains api + migration * start service interface page, WIP * different options for clearnet domains * refactor: styles for interfaces page * minor * better placeholder for no addresses * start sorting addresses * best address logic * comments * fix unnecessary export * MVP of service interface page * domains preferred * fix: address comments * only translations left * wip: start-tunnel & fix build * forms for adding domain, rework things based on new ideas * fix: dns testing * public domain, max width, descriptions for dns * nix StartOS domains, implement public and private domains at interface scope * restart tor instead of reset * better icon for restart tor * dns * fix sort functions for public and private domains * with todos * update types * clean up tech debt, bump dependencies * revert to ts-rs v9 * fix all types * fix dns form * add missing translations * it builds * fix: comments (#3009) * fix: comments * undo default --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> * fix: refactor legacy components (#3010) * fix: comments * fix: refactor legacy components * remove default again --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> * more translations * wip * fix deadlock * coukd work * simple renaming * placeholder for empty service interfaces table * honor hidden form values * remove logs * reason instead of description * fix dns * misc fixes * implement toggling gateways for service interface * fix showing dns records * move status column in service list * remove unnecessary truthy check * refactor: refactor forms components and remove legacy Taiga UI package (#3012) * handle wh file uploads * wip: debugging tor * socks5 proxy working * refactor: fix multiple comments (#3013) * refactor: fix multiple comments * styling changes, add documentation to sidebar * translations for dns page * refactor: subtle colors * rearrange service page --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> * fix file_stream and remove non-terminating test * clean up logs * support for sccache * fix gha sccache * more marketplace translations * install wizard clarity * stub hostnameInfo in migration * fix address info after setup, fix styling on SI page, new 040 release notes * remove tor logs from os * misc fixes * reset tor still not functioning... * update ts * minor styling and wording * chore: some fixes (#3015) * fix gateway renames * different handling for public domains * styling fixes * whole navbar should not be clickable on service show page * timeout getState request * remove links from changelog * misc fixes from pairing * use custom name for gateway in more places * fix dns parsing * closes #3003 * closes #2999 * chore: some fixes (#3017) * small copy change * revert hardcoded error for testing * dont require port forward if gateway is public * use old wan ip when not available * fix .const hanging on undefined * fix test * fix doc test * fix renames * update deps * allow specifying dependency metadata directly * temporarily make dependencies not cliackable in marketplace listings * fix socks bind * fix test --------- Co-authored-by: Aiden McClelland <me@drbonez.dev> Co-authored-by: waterplea <alexander@inkin.ru>
This commit is contained in:
@@ -67,9 +67,9 @@ export class ActionService {
|
||||
},
|
||||
})
|
||||
.pipe(filter(Boolean))
|
||||
.subscribe(() => this.execute(pkgInfo.id, actionInfo.id))
|
||||
.subscribe(() => this.execute(pkgInfo.id, null, actionInfo.id))
|
||||
} else {
|
||||
this.execute(pkgInfo.id, actionInfo.id)
|
||||
this.execute(pkgInfo.id, null, actionInfo.id)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -96,14 +96,20 @@ export class ActionService {
|
||||
}
|
||||
}
|
||||
|
||||
async execute(packageId: string, actionId: string, input?: object) {
|
||||
async execute(
|
||||
packageId: string,
|
||||
eventId: string | null,
|
||||
actionId: string,
|
||||
input?: object,
|
||||
) {
|
||||
const loader = this.loader.open('Loading').subscribe()
|
||||
|
||||
try {
|
||||
const res = await this.api.runAction({
|
||||
packageId,
|
||||
eventId,
|
||||
actionId,
|
||||
input: input || null,
|
||||
input: input ?? null,
|
||||
})
|
||||
|
||||
if (!res) return
|
||||
|
||||
@@ -110,7 +110,7 @@ export namespace Mock {
|
||||
squashfs: {
|
||||
aarch64: {
|
||||
publishedAt: '2025-04-21T20:58:48.140749883Z',
|
||||
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.9/startos-0.4.0-alpha.9-33ae46f~dev_aarch64.squashfs',
|
||||
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.10/startos-0.4.0-alpha.10-33ae46f~dev_aarch64.squashfs',
|
||||
commitment: {
|
||||
hash: '4elBFVkd/r8hNadKmKtLIs42CoPltMvKe2z3LRqkphk=',
|
||||
size: 1343500288,
|
||||
@@ -122,7 +122,7 @@ export namespace Mock {
|
||||
},
|
||||
'aarch64-nonfree': {
|
||||
publishedAt: '2025-04-21T21:07:00.249285116Z',
|
||||
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.9/startos-0.4.0-alpha.9-33ae46f~dev_aarch64-nonfree.squashfs',
|
||||
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.10/startos-0.4.0-alpha.10-33ae46f~dev_aarch64-nonfree.squashfs',
|
||||
commitment: {
|
||||
hash: 'MrCEi4jxbmPS7zAiGk/JSKlMsiuKqQy6RbYOxlGHOIQ=',
|
||||
size: 1653075968,
|
||||
@@ -134,7 +134,7 @@ export namespace Mock {
|
||||
},
|
||||
raspberrypi: {
|
||||
publishedAt: '2025-04-21T21:16:12.933319237Z',
|
||||
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.9/startos-0.4.0-alpha.9-33ae46f~dev_raspberrypi.squashfs',
|
||||
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.10/startos-0.4.0-alpha.10-33ae46f~dev_raspberrypi.squashfs',
|
||||
commitment: {
|
||||
hash: '/XTVQRCqY3RK544PgitlKu7UplXjkmzWoXUh2E4HCw0=',
|
||||
size: 1490731008,
|
||||
@@ -146,7 +146,7 @@ export namespace Mock {
|
||||
},
|
||||
x86_64: {
|
||||
publishedAt: '2025-04-21T21:14:20.246908903Z',
|
||||
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.9/startos-0.4.0-alpha.9-33ae46f~dev_x86_64.squashfs',
|
||||
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.10/startos-0.4.0-alpha.10-33ae46f~dev_x86_64.squashfs',
|
||||
commitment: {
|
||||
hash: '/6romKTVQGSaOU7FqSZdw0kFyd7P+NBSYNwM3q7Fe44=',
|
||||
size: 1411657728,
|
||||
@@ -158,7 +158,7 @@ export namespace Mock {
|
||||
},
|
||||
'x86_64-nonfree': {
|
||||
publishedAt: '2025-04-21T21:15:17.955265284Z',
|
||||
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.9/startos-0.4.0-alpha.9-33ae46f~dev_x86_64-nonfree.squashfs',
|
||||
url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.10/startos-0.4.0-alpha.10-33ae46f~dev_x86_64-nonfree.squashfs',
|
||||
commitment: {
|
||||
hash: 'HCRq9sr/0t85pMdrEgNBeM4x11zVKHszGnD1GDyZbSE=',
|
||||
size: 1731035136,
|
||||
@@ -354,7 +354,7 @@ export namespace Mock {
|
||||
}
|
||||
|
||||
export const BitcoinDep: T.DependencyMetadata = {
|
||||
title: 'Bitcoin Core',
|
||||
title: 'Bitcoin',
|
||||
icon: BTC_ICON,
|
||||
optional: false,
|
||||
description: 'Needed to run',
|
||||
@@ -385,7 +385,7 @@ export namespace Mock {
|
||||
docsUrl: 'https://bitcoin.org',
|
||||
releaseNotes: 'Even better support for Bitcoin and wallets!',
|
||||
osVersion: '0.3.6',
|
||||
sdkVersion: '0.4.0-beta.36',
|
||||
sdkVersion: '0.4.0-beta.37',
|
||||
gitHash: 'fakehash',
|
||||
icon: BTC_ICON,
|
||||
sourceVersion: null,
|
||||
@@ -420,7 +420,7 @@ export namespace Mock {
|
||||
docsUrl: 'https://bitcoinknots.org',
|
||||
releaseNotes: 'Even better support for Bitcoin and wallets!',
|
||||
osVersion: '0.3.6',
|
||||
sdkVersion: '0.4.0-beta.36',
|
||||
sdkVersion: '0.4.0-beta.37',
|
||||
gitHash: 'fakehash',
|
||||
icon: BTC_ICON,
|
||||
sourceVersion: null,
|
||||
@@ -465,7 +465,7 @@ export namespace Mock {
|
||||
docsUrl: 'https://bitcoin.org',
|
||||
releaseNotes: 'Even better support for Bitcoin and wallets!',
|
||||
osVersion: '0.3.6',
|
||||
sdkVersion: '0.4.0-beta.36',
|
||||
sdkVersion: '0.4.0-beta.37',
|
||||
gitHash: 'fakehash',
|
||||
icon: BTC_ICON,
|
||||
sourceVersion: null,
|
||||
@@ -500,7 +500,7 @@ export namespace Mock {
|
||||
docsUrl: 'https://bitcoinknots.org',
|
||||
releaseNotes: 'Even better support for Bitcoin and wallets!',
|
||||
osVersion: '0.3.6',
|
||||
sdkVersion: '0.4.0-beta.36',
|
||||
sdkVersion: '0.4.0-beta.37',
|
||||
gitHash: 'fakehash',
|
||||
icon: BTC_ICON,
|
||||
sourceVersion: null,
|
||||
@@ -547,23 +547,13 @@ export namespace Mock {
|
||||
docsUrl: 'https://lightning.engineering/',
|
||||
releaseNotes: 'Upstream release to 0.17.5',
|
||||
osVersion: '0.3.6',
|
||||
sdkVersion: '0.4.0-beta.36',
|
||||
sdkVersion: '0.4.0-beta.37',
|
||||
gitHash: 'fakehash',
|
||||
icon: LND_ICON,
|
||||
sourceVersion: null,
|
||||
dependencyMetadata: {
|
||||
bitcoind: {
|
||||
title: 'Bitcoin Core',
|
||||
icon: BTC_ICON,
|
||||
description: 'Used for RPC requests',
|
||||
optional: false,
|
||||
},
|
||||
'btc-rpc-proxy': {
|
||||
title: 'Bitcoin Proxy',
|
||||
icon: PROXY_ICON,
|
||||
description: 'Used for authorized proxying of RPC requests',
|
||||
optional: true,
|
||||
},
|
||||
bitcoind: BitcoinDep,
|
||||
'btc-rpc-proxy': ProxyDep,
|
||||
},
|
||||
donationUrl: null,
|
||||
alerts: {
|
||||
@@ -605,23 +595,13 @@ export namespace Mock {
|
||||
docsUrl: 'https://lightning.engineering/',
|
||||
releaseNotes: 'Upstream release to 0.17.4',
|
||||
osVersion: '0.3.6',
|
||||
sdkVersion: '0.4.0-beta.36',
|
||||
sdkVersion: '0.4.0-beta.37',
|
||||
gitHash: 'fakehash',
|
||||
icon: LND_ICON,
|
||||
sourceVersion: null,
|
||||
dependencyMetadata: {
|
||||
bitcoind: {
|
||||
title: 'Bitcoin Core',
|
||||
icon: BTC_ICON,
|
||||
description: 'Used for RPC requests',
|
||||
optional: false,
|
||||
},
|
||||
'btc-rpc-proxy': {
|
||||
title: 'Bitcoin Proxy',
|
||||
icon: PROXY_ICON,
|
||||
description: 'Used for authorized proxying of RPC requests',
|
||||
optional: true,
|
||||
},
|
||||
bitcoind: BitcoinDep,
|
||||
'btc-rpc-proxy': ProxyDep,
|
||||
},
|
||||
donationUrl: null,
|
||||
alerts: {
|
||||
@@ -667,7 +647,7 @@ export namespace Mock {
|
||||
docsUrl: 'https://bitcoin.org',
|
||||
releaseNotes: 'Even better support for Bitcoin and wallets!',
|
||||
osVersion: '0.3.6',
|
||||
sdkVersion: '0.4.0-beta.36',
|
||||
sdkVersion: '0.4.0-beta.37',
|
||||
gitHash: 'fakehash',
|
||||
icon: BTC_ICON,
|
||||
sourceVersion: null,
|
||||
@@ -702,7 +682,7 @@ export namespace Mock {
|
||||
docsUrl: 'https://bitcoinknots.org',
|
||||
releaseNotes: 'Even better support for Bitcoin and wallets!',
|
||||
osVersion: '0.3.6',
|
||||
sdkVersion: '0.4.0-beta.36',
|
||||
sdkVersion: '0.4.0-beta.37',
|
||||
gitHash: 'fakehash',
|
||||
icon: BTC_ICON,
|
||||
sourceVersion: null,
|
||||
@@ -747,23 +727,13 @@ export namespace Mock {
|
||||
docsUrl: 'https://lightning.engineering/',
|
||||
releaseNotes: 'Upstream release and minor fixes.',
|
||||
osVersion: '0.3.6',
|
||||
sdkVersion: '0.4.0-beta.36',
|
||||
sdkVersion: '0.4.0-beta.37',
|
||||
gitHash: 'fakehash',
|
||||
icon: LND_ICON,
|
||||
sourceVersion: null,
|
||||
dependencyMetadata: {
|
||||
bitcoind: {
|
||||
title: 'Bitcoin Core',
|
||||
icon: BTC_ICON,
|
||||
description: 'Used for RPC requests',
|
||||
optional: false,
|
||||
},
|
||||
'btc-rpc-proxy': {
|
||||
title: 'Bitcoin Proxy',
|
||||
icon: null,
|
||||
description: 'Used for authorized RPC requests',
|
||||
optional: true,
|
||||
},
|
||||
bitcoind: BitcoinDep,
|
||||
'btc-rpc-proxy': ProxyDep,
|
||||
},
|
||||
donationUrl: null,
|
||||
alerts: {
|
||||
@@ -805,17 +775,12 @@ export namespace Mock {
|
||||
marketingSite: '',
|
||||
releaseNotes: 'Upstream release and minor fixes.',
|
||||
osVersion: '0.3.6',
|
||||
sdkVersion: '0.4.0-beta.36',
|
||||
sdkVersion: '0.4.0-beta.37',
|
||||
gitHash: 'fakehash',
|
||||
icon: PROXY_ICON,
|
||||
sourceVersion: null,
|
||||
dependencyMetadata: {
|
||||
bitcoind: {
|
||||
title: 'Bitcoin Core',
|
||||
icon: BTC_ICON,
|
||||
description: 'Used for RPC requests',
|
||||
optional: false,
|
||||
},
|
||||
bitcoind: BitcoinDep,
|
||||
},
|
||||
donationUrl: null,
|
||||
alerts: {
|
||||
@@ -1954,7 +1919,7 @@ export namespace Mock {
|
||||
manifest: MockManifestBitcoind,
|
||||
},
|
||||
s9pk: '/media/startos/data/package-data/archive/installed/asdfasdf.s9pk',
|
||||
icon: '/assets/img/service-icons/bitcoind.svg',
|
||||
icon: '/assets/img/service-icons/bitcoin-core.svg',
|
||||
lastBackup: null,
|
||||
status: {
|
||||
main: 'running',
|
||||
@@ -2059,7 +2024,8 @@ export namespace Mock {
|
||||
net: {
|
||||
assignedPort: 80,
|
||||
assignedSslPort: 443,
|
||||
public: false,
|
||||
publicEnabled: [],
|
||||
privateDisabled: [],
|
||||
},
|
||||
options: {
|
||||
addSsl: null,
|
||||
@@ -2068,13 +2034,14 @@ export namespace Mock {
|
||||
},
|
||||
},
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: [],
|
||||
onions: [],
|
||||
domains: {},
|
||||
hostnameInfo: {
|
||||
80: [
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'local',
|
||||
@@ -2085,7 +2052,7 @@ export namespace Mock {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'wlan0',
|
||||
gatewayId: 'wlan0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'local',
|
||||
@@ -2096,7 +2063,7 @@ export namespace Mock {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv4',
|
||||
@@ -2107,7 +2074,7 @@ export namespace Mock {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'wlan0',
|
||||
gatewayId: 'wlan0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv4',
|
||||
@@ -2118,7 +2085,7 @@ export namespace Mock {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv6',
|
||||
@@ -2130,7 +2097,7 @@ export namespace Mock {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'wlan0',
|
||||
gatewayId: 'wlan0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv6',
|
||||
@@ -2158,7 +2125,8 @@ export namespace Mock {
|
||||
net: {
|
||||
assignedPort: 8332,
|
||||
assignedSslPort: null,
|
||||
public: false,
|
||||
publicEnabled: [],
|
||||
privateDisabled: [],
|
||||
},
|
||||
options: {
|
||||
addSsl: null,
|
||||
@@ -2167,8 +2135,9 @@ export namespace Mock {
|
||||
},
|
||||
},
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: [],
|
||||
onions: [],
|
||||
domains: {},
|
||||
hostnameInfo: {
|
||||
8332: [],
|
||||
},
|
||||
@@ -2180,7 +2149,8 @@ export namespace Mock {
|
||||
net: {
|
||||
assignedPort: 8333,
|
||||
assignedSslPort: null,
|
||||
public: false,
|
||||
publicEnabled: [],
|
||||
privateDisabled: [],
|
||||
},
|
||||
options: {
|
||||
addSsl: null,
|
||||
@@ -2189,8 +2159,9 @@ export namespace Mock {
|
||||
},
|
||||
},
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: [],
|
||||
onions: [],
|
||||
domains: {},
|
||||
hostnameInfo: {
|
||||
8333: [],
|
||||
},
|
||||
@@ -2253,8 +2224,8 @@ export namespace Mock {
|
||||
},
|
||||
currentDependencies: {
|
||||
bitcoind: {
|
||||
title: Mock.MockManifestBitcoind.title,
|
||||
icon: 'assets/img/service-icons/bitcoind.svg',
|
||||
title: BitcoinDep.title,
|
||||
icon: BitcoinDep.icon,
|
||||
kind: 'running',
|
||||
versionRange: '>=26.0.0',
|
||||
healthChecks: [],
|
||||
@@ -2350,8 +2321,8 @@ export namespace Mock {
|
||||
},
|
||||
currentDependencies: {
|
||||
bitcoind: {
|
||||
title: Mock.MockManifestBitcoind.title,
|
||||
icon: 'assets/img/service-icons/bitcoind.svg',
|
||||
title: BitcoinDep.title,
|
||||
icon: BitcoinDep.icon,
|
||||
kind: 'running',
|
||||
versionRange: '>=26.0.0',
|
||||
healthChecks: [],
|
||||
|
||||
@@ -104,6 +104,16 @@ export namespace RR {
|
||||
export type DiskRepairReq = {} // server.disk.repair
|
||||
export type DiskRepairRes = null
|
||||
|
||||
export type SetDnsReq = {
|
||||
servers: string[] | null
|
||||
} // net.dns.set-static
|
||||
export type SetDnsRes = null
|
||||
|
||||
export type QueryDnsReq = {
|
||||
fqdn: string
|
||||
} // net.dns.query
|
||||
export type QueryDnsRes = string | null
|
||||
|
||||
export type ResetTorReq = {
|
||||
wipeState: boolean
|
||||
reason: string
|
||||
@@ -234,10 +244,28 @@ export namespace RR {
|
||||
}
|
||||
export type CreateBackupRes = null
|
||||
|
||||
// package
|
||||
// network
|
||||
|
||||
export type AddTunnelReq = {
|
||||
name: string
|
||||
config: string // file contents
|
||||
public: boolean
|
||||
} // net.tunnel.add
|
||||
export type AddTunnelRes = {
|
||||
id: string
|
||||
}
|
||||
|
||||
export type UpdateTunnelReq = {
|
||||
id: string
|
||||
name: string
|
||||
} // net.gateway.set-name
|
||||
export type UpdateTunnelRes = null
|
||||
|
||||
export type RemoveTunnelReq = { id: string } // net.tunnel.remove
|
||||
export type RemoveTunnelRes = null
|
||||
|
||||
export type InitAcmeReq = {
|
||||
provider: 'letsencrypt' | 'letsencrypt-staging' | string
|
||||
provider: string
|
||||
contact: string[]
|
||||
}
|
||||
export type InitAcmeRes = null
|
||||
@@ -252,14 +280,15 @@ export namespace RR {
|
||||
key: string
|
||||
}
|
||||
export type GenerateTorKeyReq = {} // net.tor.key.generate
|
||||
export type AddTorKeyRes = string // onion address without .onion suffix
|
||||
export type AddTorKeyRes = string // onion address *with* .onion suffix
|
||||
|
||||
export type ServerBindingSetPublicReq = {
|
||||
// server.host.binding.set-public
|
||||
internalPort: number
|
||||
public: boolean | null // default true
|
||||
export type ServerBindingToggleGatewayReq = {
|
||||
// server.host.binding.set-gateway-enabled
|
||||
gateway: T.GatewayId
|
||||
internalPort: 80
|
||||
enabled: boolean
|
||||
}
|
||||
export type BindingSetPublicRes = null
|
||||
export type ServerBindingToggleGatewayRes = null
|
||||
|
||||
export type ServerAddOnionReq = {
|
||||
// server.host.address.onion.add
|
||||
@@ -270,45 +299,73 @@ export namespace RR {
|
||||
export type ServerRemoveOnionReq = ServerAddOnionReq // server.host.address.onion.remove
|
||||
export type RemoveOnionRes = null
|
||||
|
||||
export type ServerAddDomainReq = {
|
||||
// server.host.address.domain.add
|
||||
domain: string // FQDN
|
||||
private: boolean
|
||||
acme: string | null // "letsencrypt" | "letsencrypt-staging" | Url | null
|
||||
export type OsUiAddPublicDomainReq = {
|
||||
// server.host.address.domain.public.add
|
||||
fqdn: string // FQDN
|
||||
gateway: T.GatewayId
|
||||
acme: string | null // URL. null means local Root CA
|
||||
}
|
||||
export type AddDomainRes = null
|
||||
export type OsUiAddPublicDomainRes = QueryDnsRes
|
||||
|
||||
export type ServerRemoveDomainReq = {
|
||||
// server.host.address.domain.remove
|
||||
domain: string // FQDN
|
||||
export type OsUiRemovePublicDomainReq = {
|
||||
// server.host.address.domain.public.remove
|
||||
fqdn: string // FQDN
|
||||
}
|
||||
export type RemoveDomainRes = null
|
||||
export type OsUiRemovePublicDomainRes = null
|
||||
|
||||
export type PkgBindingSetPublicReq = ServerBindingSetPublicReq & {
|
||||
// package.host.binding.set-public
|
||||
export type OsUiAddPrivateDomainReq = {
|
||||
// server.host.address.domain.private.add
|
||||
fqdn: string // FQDN
|
||||
}
|
||||
export type OsUiAddPrivateDomainRes = null
|
||||
|
||||
export type OsUiRemovePrivateDomainReq = {
|
||||
// server.host.address.domain.private.remove
|
||||
fqdn: string // FQDN
|
||||
}
|
||||
export type OsUiRemovePrivateDomainRes = null
|
||||
|
||||
export type PkgBindingToggleGatewayReq = Omit<
|
||||
ServerBindingToggleGatewayReq,
|
||||
'internalPort'
|
||||
> & {
|
||||
// package.host.binding.set-gateway-enabled
|
||||
internalPort: number
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
export type PkgBindingToggleGatewayRes = null
|
||||
|
||||
export type PkgAddOnionReq = ServerAddOnionReq & {
|
||||
// package.host.address.onion.add
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
|
||||
export type PkgRemoveOnionReq = PkgAddOnionReq // package.host.address.onion.remove
|
||||
|
||||
export type PkgAddDomainReq = ServerAddDomainReq & {
|
||||
// package.host.address.domain.add
|
||||
export type PkgAddPublicDomainReq = OsUiAddPublicDomainReq & {
|
||||
// package.host.address.domain.public.add
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
export type PkgAddPublicDomainRes = OsUiAddPublicDomainRes
|
||||
|
||||
export type PkgRemoveDomainReq = ServerRemoveDomainReq & {
|
||||
// package.host.address.domain.remove
|
||||
export type PkgRemovePublicDomainReq = OsUiRemovePublicDomainReq & {
|
||||
// package.host.address.domain.public.remove
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
export type PkgRemovePublicDomainRes = OsUiRemovePublicDomainRes
|
||||
|
||||
export type PkgAddPrivateDomainReq = OsUiAddPrivateDomainReq & {
|
||||
// package.host.address.domain.private.add
|
||||
package: T.PackageId // string
|
||||
host: T.HostId // string
|
||||
}
|
||||
export type PkgAddPrivateDomainRes = OsUiAddPrivateDomainRes
|
||||
|
||||
export type PkgRemovePrivateDomainReq = PkgAddPrivateDomainReq
|
||||
export type PkgRemovePrivateDomainRes = OsUiRemovePrivateDomainRes
|
||||
|
||||
export type GetPackageLogsReq = FetchLogsReq & { id: string } // package.logs
|
||||
export type GetPackageLogsRes = FetchLogsRes
|
||||
@@ -324,12 +381,14 @@ export namespace RR {
|
||||
|
||||
export type GetActionInputReq = { packageId: string; actionId: string } // package.action.get-input
|
||||
export type GetActionInputRes = {
|
||||
eventId: string
|
||||
spec: IST.InputSpec
|
||||
value: object | null
|
||||
}
|
||||
|
||||
export type ActionReq = {
|
||||
packageId: string
|
||||
eventId: string | null
|
||||
actionId: string
|
||||
input: object | null
|
||||
} // package.action.run
|
||||
@@ -374,7 +433,7 @@ export namespace RR {
|
||||
icon: string // base64
|
||||
}
|
||||
export type SideloadPackageRes = {
|
||||
upload: string // guid
|
||||
upload: string
|
||||
progress: string // guid
|
||||
}
|
||||
|
||||
@@ -394,15 +453,6 @@ export namespace RR {
|
||||
export type GetRegistryPackagesRes = GetPackagesRes
|
||||
}
|
||||
|
||||
export type Breakages = {
|
||||
[id: string]: TaggedDependencyError
|
||||
}
|
||||
|
||||
export type TaggedDependencyError = {
|
||||
dependency: string
|
||||
error: DependencyError
|
||||
}
|
||||
|
||||
interface MetricData {
|
||||
value: string
|
||||
unit: string
|
||||
@@ -566,99 +616,9 @@ export type Encrypted = {
|
||||
encrypted: string
|
||||
}
|
||||
|
||||
export type DependencyError =
|
||||
| DependencyErrorNotInstalled
|
||||
| DependencyErrorNotRunning
|
||||
| DependencyErrorIncorrectVersion
|
||||
| DependencyErrorActionRequired
|
||||
| DependencyErrorHealthChecksFailed
|
||||
| DependencyErrorTransitive
|
||||
|
||||
export type DependencyErrorNotInstalled = {
|
||||
type: 'notInstalled'
|
||||
}
|
||||
|
||||
export type DependencyErrorNotRunning = {
|
||||
type: 'notRunning'
|
||||
}
|
||||
|
||||
export type DependencyErrorIncorrectVersion = {
|
||||
type: 'incorrectVersion'
|
||||
expected: string // version range
|
||||
received: string // version
|
||||
}
|
||||
|
||||
export interface DependencyErrorActionRequired {
|
||||
type: 'actionRequired'
|
||||
}
|
||||
|
||||
export type DependencyErrorHealthChecksFailed = {
|
||||
type: 'healthChecksFailed'
|
||||
check: T.NamedHealthCheckResult
|
||||
}
|
||||
|
||||
export type DependencyErrorTransitive = {
|
||||
type: 'transitive'
|
||||
}
|
||||
|
||||
// @TODO 041
|
||||
|
||||
// export namespace RR041 {
|
||||
// // ** domains **
|
||||
|
||||
// export type ClaimStart9ToReq = { networkInterfaceId: string } // net.domain.me.claim
|
||||
// export type ClaimStart9ToRes = null
|
||||
|
||||
// export type DeleteStart9ToReq = {} // net.domain.me.delete
|
||||
// export type DeleteStart9ToRes = null
|
||||
|
||||
// export type AddDomainReq = {
|
||||
// hostname: string
|
||||
// provider: {
|
||||
// name: string
|
||||
// username: string | null
|
||||
// password: string | null
|
||||
// }
|
||||
// networkInterfaceId: string
|
||||
// } // net.domain.add
|
||||
// export type AddDomainRes = null
|
||||
|
||||
// export type DeleteDomainReq = { hostname: string } // net.domain.delete
|
||||
// export type DeleteDomainRes = null
|
||||
|
||||
// // port forwards
|
||||
|
||||
// export type OverridePortReq = { target: number; port: number } // net.port-forwards.override
|
||||
// export type OverridePortRes = null
|
||||
|
||||
// // ** proxies **
|
||||
|
||||
// export type AddProxyReq = {
|
||||
// name: string
|
||||
// config: string
|
||||
// } // net.proxy.add
|
||||
// export type AddProxyRes = null
|
||||
|
||||
// export type UpdateProxyReq = {
|
||||
// name: string
|
||||
// } // net.proxy.update
|
||||
// export type UpdateProxyRes = null
|
||||
|
||||
// export type DeleteProxyReq = { id: string } // net.proxy.delete
|
||||
// export type DeleteProxyRes = null
|
||||
|
||||
// // ** set outbound proxies **
|
||||
|
||||
// export type SetOsOutboundProxyReq = {
|
||||
// proxy: string | null
|
||||
// } // server.proxy.set-outbound
|
||||
// export type SetOsOutboundProxyRes = null
|
||||
|
||||
// export type SetServiceOutboundProxyReq = {
|
||||
// packageId: string
|
||||
// proxy: string | null
|
||||
// } // package.proxy.set-outbound
|
||||
// export type SetServiceOutboundProxyRes = null
|
||||
|
||||
// // ** automated backups **
|
||||
|
||||
@@ -740,20 +700,6 @@ export type DependencyErrorTransitive = {
|
||||
|
||||
// @TODO 041 types
|
||||
|
||||
// export type AppMetrics = {
|
||||
// memory: {
|
||||
// percentageUsed: MetricData
|
||||
// used: MetricData
|
||||
// }
|
||||
// cpu: {
|
||||
// percentageUsed: MetricData
|
||||
// }
|
||||
// disk: {
|
||||
// percentageUsed: MetricData
|
||||
// used: MetricData
|
||||
// }
|
||||
// }
|
||||
|
||||
// export type RemoteBackupTarget = CifsBackupTarget | CloudBackupTarget
|
||||
// export type BackupTarget = RemoteBackupTarget | DiskBackupTarget
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@ import { WebSocketSubject } from 'rxjs/webSocket'
|
||||
export abstract class ApiService {
|
||||
// http
|
||||
|
||||
// for sideloading packages
|
||||
abstract uploadPackage(guid: string, body: Blob): Promise<void>
|
||||
// for uploading files
|
||||
abstract uploadFile(guid: string, body: Blob): Promise<void>
|
||||
|
||||
// for getting static files: ex license
|
||||
abstract getStaticProxy(
|
||||
@@ -90,8 +90,6 @@ export abstract class ApiService {
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes>
|
||||
|
||||
abstract getTorLogs(params: RR.GetServerLogsReq): Promise<RR.GetServerLogsRes>
|
||||
|
||||
abstract followServerLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes>
|
||||
@@ -100,10 +98,6 @@ export abstract class ApiService {
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes>
|
||||
|
||||
abstract followTorLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes>
|
||||
|
||||
abstract followServerMetrics(
|
||||
params: RR.FollowServerMetricsReq,
|
||||
): Promise<RR.FollowServerMetricsRes>
|
||||
@@ -122,16 +116,12 @@ export abstract class ApiService {
|
||||
|
||||
abstract toggleKiosk(enable: boolean): Promise<null>
|
||||
|
||||
abstract setDns(params: RR.SetDnsReq): Promise<RR.SetDnsRes>
|
||||
|
||||
abstract queryDns(params: RR.QueryDnsReq): Promise<RR.QueryDnsRes>
|
||||
|
||||
abstract resetTor(params: RR.ResetTorReq): Promise<RR.ResetTorRes>
|
||||
|
||||
// @TODO 041
|
||||
|
||||
// ** server outbound proxy **
|
||||
|
||||
// abstract setOsOutboundProxy(
|
||||
// params: RR.SetOsOutboundProxyReq,
|
||||
// ): Promise<RR.SetOsOutboundProxyRes>
|
||||
|
||||
// smtp
|
||||
|
||||
abstract setSmtp(params: RR.SetSMTPReq): Promise<RR.SetSMTPRes>
|
||||
@@ -182,38 +172,14 @@ export abstract class ApiService {
|
||||
|
||||
// ** proxies **
|
||||
|
||||
// @TODO 041
|
||||
abstract addTunnel(params: RR.AddTunnelReq): Promise<RR.AddTunnelRes>
|
||||
|
||||
// abstract addProxy(params: RR.AddProxyReq): Promise<RR.AddProxyRes>
|
||||
abstract updateTunnel(params: RR.UpdateTunnelReq): Promise<RR.UpdateTunnelRes>
|
||||
|
||||
// abstract updateProxy(params: RR.UpdateProxyReq): Promise<RR.UpdateProxyRes>
|
||||
|
||||
// abstract deleteProxy(params: RR.DeleteProxyReq): Promise<RR.DeleteProxyRes>
|
||||
abstract removeTunnel(params: RR.RemoveTunnelReq): Promise<RR.RemoveTunnelRes>
|
||||
|
||||
// ** domains **
|
||||
|
||||
// @TODO 041
|
||||
|
||||
// abstract claimStart9ToDomain(
|
||||
// params: RR.ClaimStart9ToReq,
|
||||
// ): Promise<RR.ClaimStart9ToRes>
|
||||
|
||||
// abstract deleteStart9ToDomain(
|
||||
// params: RR.DeleteStart9ToReq,
|
||||
// ): Promise<RR.DeleteStart9ToRes>
|
||||
|
||||
// abstract addDomain(params: RR.AddDomainReq): Promise<RR.AddDomainRes>
|
||||
|
||||
// abstract deleteDomain(params: RR.DeleteDomainReq): Promise<RR.DeleteDomainRes>
|
||||
|
||||
// ** port forwards **
|
||||
|
||||
// @TODO 041
|
||||
|
||||
// abstract overridePortForward(
|
||||
// params: RR.OverridePortReq,
|
||||
// ): Promise<RR.OverridePortRes>
|
||||
|
||||
// wifi
|
||||
|
||||
abstract enableWifi(params: RR.EnabledWifiReq): Promise<RR.EnabledWifiRes>
|
||||
@@ -366,8 +332,8 @@ export abstract class ApiService {
|
||||
// ** service outbound proxy **
|
||||
|
||||
// abstract setServiceOutboundProxy(
|
||||
// params: RR.SetServiceOutboundProxyReq,
|
||||
// ): Promise<RR.SetServiceOutboundProxyRes>
|
||||
// params: RR.SetServiceOutboundTunnelReq,
|
||||
// ): Promise<RR.SetServiceOutboundTunnelRes>
|
||||
|
||||
abstract initAcme(params: RR.InitAcmeReq): Promise<RR.InitAcmeRes>
|
||||
|
||||
@@ -379,9 +345,9 @@ export abstract class ApiService {
|
||||
params: RR.GenerateTorKeyReq,
|
||||
): Promise<RR.AddTorKeyRes>
|
||||
|
||||
abstract serverBindingSetPubic(
|
||||
params: RR.ServerBindingSetPublicReq,
|
||||
): Promise<RR.BindingSetPublicRes>
|
||||
abstract serverBindingToggleGateway(
|
||||
params: RR.ServerBindingToggleGatewayReq,
|
||||
): Promise<RR.ServerBindingToggleGatewayRes>
|
||||
|
||||
abstract serverAddOnion(params: RR.ServerAddOnionReq): Promise<RR.AddOnionRes>
|
||||
|
||||
@@ -389,17 +355,25 @@ export abstract class ApiService {
|
||||
params: RR.ServerRemoveOnionReq,
|
||||
): Promise<RR.RemoveOnionRes>
|
||||
|
||||
abstract serverAddDomain(
|
||||
params: RR.ServerAddDomainReq,
|
||||
): Promise<RR.AddDomainRes>
|
||||
abstract osUiAddPublicDomain(
|
||||
params: RR.OsUiAddPublicDomainReq,
|
||||
): Promise<RR.OsUiAddPublicDomainRes>
|
||||
|
||||
abstract serverRemoveDomain(
|
||||
params: RR.ServerRemoveDomainReq,
|
||||
): Promise<RR.RemoveDomainRes>
|
||||
abstract osUiRemovePublicDomain(
|
||||
params: RR.OsUiRemovePublicDomainReq,
|
||||
): Promise<RR.OsUiRemovePublicDomainRes>
|
||||
|
||||
abstract pkgBindingSetPubic(
|
||||
params: RR.PkgBindingSetPublicReq,
|
||||
): Promise<RR.BindingSetPublicRes>
|
||||
abstract osUiAddPrivateDomain(
|
||||
params: RR.OsUiAddPrivateDomainReq,
|
||||
): Promise<RR.OsUiAddPrivateDomainRes>
|
||||
|
||||
abstract osUiRemovePrivateDomain(
|
||||
params: RR.OsUiRemovePrivateDomainReq,
|
||||
): Promise<RR.OsUiRemovePrivateDomainRes>
|
||||
|
||||
abstract pkgBindingToggleGateway(
|
||||
params: RR.PkgBindingToggleGatewayReq,
|
||||
): Promise<RR.PkgBindingToggleGatewayRes>
|
||||
|
||||
abstract pkgAddOnion(params: RR.PkgAddOnionReq): Promise<RR.AddOnionRes>
|
||||
|
||||
@@ -407,9 +381,19 @@ export abstract class ApiService {
|
||||
params: RR.PkgRemoveOnionReq,
|
||||
): Promise<RR.RemoveOnionRes>
|
||||
|
||||
abstract pkgAddDomain(params: RR.PkgAddDomainReq): Promise<RR.AddDomainRes>
|
||||
abstract pkgAddPublicDomain(
|
||||
params: RR.PkgAddPublicDomainReq,
|
||||
): Promise<RR.PkgAddPublicDomainRes>
|
||||
|
||||
abstract pkgRemoveDomain(
|
||||
params: RR.PkgRemoveDomainReq,
|
||||
): Promise<RR.RemoveDomainRes>
|
||||
abstract pkgRemovePublicDomain(
|
||||
params: RR.PkgRemovePublicDomainReq,
|
||||
): Promise<RR.PkgRemovePublicDomainRes>
|
||||
|
||||
abstract pkgAddPrivateDomain(
|
||||
params: RR.PkgAddPrivateDomainReq,
|
||||
): Promise<RR.PkgAddPrivateDomainRes>
|
||||
|
||||
abstract pkgRemovePrivateDomain(
|
||||
params: RR.PkgRemovePrivateDomainReq,
|
||||
): Promise<RR.PkgRemovePrivateDomainRes>
|
||||
}
|
||||
|
||||
@@ -33,9 +33,9 @@ export class LiveApiService extends ApiService {
|
||||
this.document.defaultView.rpcClient = this
|
||||
}
|
||||
|
||||
// for sideloading packages
|
||||
// for uploading files
|
||||
|
||||
async uploadPackage(guid: string, body: Blob): Promise<void> {
|
||||
async uploadFile(guid: string, body: Blob): Promise<void> {
|
||||
await this.httpRequest({
|
||||
method: Method.POST,
|
||||
body,
|
||||
@@ -97,7 +97,7 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
async getState(): Promise<RR.ServerState> {
|
||||
return this.rpcRequest({ method: 'state', params: {} })
|
||||
return this.rpcRequest({ method: 'state', params: {}, timeout: 10000 })
|
||||
}
|
||||
|
||||
// db
|
||||
@@ -212,10 +212,6 @@ export class LiveApiService extends ApiService {
|
||||
return this.rpcRequest({ method: 'server.kernel-logs', params })
|
||||
}
|
||||
|
||||
async getTorLogs(params: RR.GetServerLogsReq): Promise<RR.GetServerLogsRes> {
|
||||
return this.rpcRequest({ method: 'net.tor.logs', params })
|
||||
}
|
||||
|
||||
async followServerLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes> {
|
||||
@@ -228,12 +224,6 @@ export class LiveApiService extends ApiService {
|
||||
return this.rpcRequest({ method: 'server.kernel-logs.follow', params })
|
||||
}
|
||||
|
||||
async followTorLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes> {
|
||||
return this.rpcRequest({ method: 'net.tor.logs.follow', params })
|
||||
}
|
||||
|
||||
async followServerMetrics(
|
||||
params: RR.FollowServerMetricsReq,
|
||||
): Promise<RR.FollowServerMetricsRes> {
|
||||
@@ -267,16 +257,24 @@ export class LiveApiService extends ApiService {
|
||||
})
|
||||
}
|
||||
|
||||
async setDns(params: RR.SetDnsReq): Promise<RR.SetDnsRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'net.dns.set-static',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async queryDns(params: RR.QueryDnsReq): Promise<RR.QueryDnsRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'net.dns.query',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async resetTor(params: RR.ResetTorReq): Promise<RR.ResetTorRes> {
|
||||
return this.rpcRequest({ method: 'net.tor.reset', params })
|
||||
}
|
||||
|
||||
// async setOsOutboundProxy(
|
||||
// params: RR.SetOsOutboundProxyReq,
|
||||
// ): Promise<RR.SetOsOutboundProxyRes> {
|
||||
// return this.rpcRequest({ method: 'server.proxy.set-outbound', params })
|
||||
// }
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
async checkOSUpdate(
|
||||
@@ -352,47 +350,17 @@ export class LiveApiService extends ApiService {
|
||||
|
||||
// proxies
|
||||
|
||||
// async addProxy(params: RR.AddProxyReq): Promise<RR.AddProxyRes> {
|
||||
// return this.rpcRequest({ method: 'net.proxy.add', params })
|
||||
// }
|
||||
async addTunnel(params: RR.AddTunnelReq): Promise<RR.AddTunnelRes> {
|
||||
return this.rpcRequest({ method: 'net.tunnel.add', params })
|
||||
}
|
||||
|
||||
// async updateProxy(params: RR.UpdateProxyReq): Promise<RR.UpdateProxyRes> {
|
||||
// return this.rpcRequest({ method: 'net.proxy.update', params })
|
||||
// }
|
||||
async updateTunnel(params: RR.UpdateTunnelReq): Promise<RR.UpdateTunnelRes> {
|
||||
return this.rpcRequest({ method: 'net.gateway.set-name', params })
|
||||
}
|
||||
|
||||
// async deleteProxy(params: RR.DeleteProxyReq): Promise<RR.DeleteProxyRes> {
|
||||
// return this.rpcRequest({ method: 'net.proxy.delete', params })
|
||||
// }
|
||||
|
||||
// domains
|
||||
|
||||
// async claimStart9ToDomain(
|
||||
// params: RR.ClaimStart9ToReq,
|
||||
// ): Promise<RR.ClaimStart9ToRes> {
|
||||
// return this.rpcRequest({ method: 'net.domain.me.claim', params })
|
||||
// }
|
||||
|
||||
// async deleteStart9ToDomain(
|
||||
// params: RR.DeleteStart9ToReq,
|
||||
// ): Promise<RR.DeleteStart9ToRes> {
|
||||
// return this.rpcRequest({ method: 'net.domain.me.delete', params })
|
||||
// }
|
||||
|
||||
// async addDomain(params: RR.AddDomainReq): Promise<RR.AddDomainRes> {
|
||||
// return this.rpcRequest({ method: 'net.domain.add', params })
|
||||
// }
|
||||
|
||||
// async deleteDomain(params: RR.DeleteDomainReq): Promise<RR.DeleteDomainRes> {
|
||||
// return this.rpcRequest({ method: 'net.domain.delete', params })
|
||||
// }
|
||||
|
||||
// port forwards
|
||||
|
||||
// async overridePortForward(
|
||||
// params: RR.OverridePortReq,
|
||||
// ): Promise<RR.OverridePortRes> {
|
||||
// return this.rpcRequest({ method: 'net.port-forwards.override', params })
|
||||
// }
|
||||
async removeTunnel(params: RR.RemoveTunnelReq): Promise<RR.RemoveTunnelRes> {
|
||||
return this.rpcRequest({ method: 'net.tunnel.remove', params })
|
||||
}
|
||||
|
||||
// wifi
|
||||
|
||||
@@ -627,8 +595,8 @@ export class LiveApiService extends ApiService {
|
||||
}
|
||||
|
||||
// async setServiceOutboundProxy(
|
||||
// params: RR.SetServiceOutboundProxyReq,
|
||||
// ): Promise<RR.SetServiceOutboundProxyRes> {
|
||||
// params: RR.SetServiceOutboundTunnelReq,
|
||||
// ): Promise<RR.SetServiceOutboundTunnelRes> {
|
||||
// return this.rpcRequest({ method: 'package.proxy.set-outbound', params })
|
||||
// }
|
||||
|
||||
@@ -660,11 +628,11 @@ export class LiveApiService extends ApiService {
|
||||
})
|
||||
}
|
||||
|
||||
async serverBindingSetPubic(
|
||||
params: RR.ServerBindingSetPublicReq,
|
||||
): Promise<RR.BindingSetPublicRes> {
|
||||
async serverBindingToggleGateway(
|
||||
params: RR.ServerBindingToggleGatewayReq,
|
||||
): Promise<RR.ServerBindingToggleGatewayRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'server.host.binding.set-public',
|
||||
method: 'server.host.binding.set-gateway-enabled',
|
||||
params,
|
||||
})
|
||||
}
|
||||
@@ -685,29 +653,47 @@ export class LiveApiService extends ApiService {
|
||||
})
|
||||
}
|
||||
|
||||
async serverAddDomain(
|
||||
params: RR.ServerAddDomainReq,
|
||||
): Promise<RR.AddDomainRes> {
|
||||
async osUiAddPublicDomain(
|
||||
params: RR.OsUiAddPublicDomainReq,
|
||||
): Promise<RR.OsUiAddPublicDomainRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'server.host.address.domain.add',
|
||||
method: 'server.host.address.domain.public.add',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async serverRemoveDomain(
|
||||
params: RR.ServerRemoveDomainReq,
|
||||
): Promise<RR.RemoveDomainRes> {
|
||||
async osUiRemovePublicDomain(
|
||||
params: RR.OsUiRemovePublicDomainReq,
|
||||
): Promise<RR.OsUiRemovePublicDomainRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'server.host.address.domain.remove',
|
||||
method: 'server.host.address.domain.public.remove',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async pkgBindingSetPubic(
|
||||
params: RR.PkgBindingSetPublicReq,
|
||||
): Promise<RR.BindingSetPublicRes> {
|
||||
async osUiAddPrivateDomain(
|
||||
params: RR.OsUiAddPrivateDomainReq,
|
||||
): Promise<RR.OsUiAddPrivateDomainRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.binding.set-public',
|
||||
method: 'server.host.address.domain.private.add',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async osUiRemovePrivateDomain(
|
||||
params: RR.OsUiRemovePrivateDomainReq,
|
||||
): Promise<RR.OsUiRemovePrivateDomainRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'server.host.address.domain.private.remove',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async pkgBindingToggleGateway(
|
||||
params: RR.PkgBindingToggleGatewayReq,
|
||||
): Promise<RR.PkgBindingToggleGatewayRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.binding.set-gateway-enabled',
|
||||
params,
|
||||
})
|
||||
}
|
||||
@@ -728,18 +714,38 @@ export class LiveApiService extends ApiService {
|
||||
})
|
||||
}
|
||||
|
||||
async pkgAddDomain(params: RR.PkgAddDomainReq): Promise<RR.AddDomainRes> {
|
||||
async pkgAddPublicDomain(
|
||||
params: RR.PkgAddPublicDomainReq,
|
||||
): Promise<RR.PkgAddPublicDomainRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.address.domain.add',
|
||||
method: 'package.host.address.domain.public.add',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async pkgRemoveDomain(
|
||||
params: RR.PkgRemoveDomainReq,
|
||||
): Promise<RR.RemoveDomainRes> {
|
||||
async pkgRemovePublicDomain(
|
||||
params: RR.PkgRemovePublicDomainReq,
|
||||
): Promise<RR.PkgRemovePublicDomainRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.address.domain.remove',
|
||||
method: 'package.host.address.domain.public.remove',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async pkgAddPrivateDomain(
|
||||
params: RR.PkgAddPrivateDomainReq,
|
||||
): Promise<RR.PkgAddPrivateDomainRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.address.domain.private.add',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
async pkgRemovePrivateDomain(
|
||||
params: RR.PkgRemovePrivateDomainReq,
|
||||
): Promise<RR.PkgRemovePrivateDomainRes> {
|
||||
return this.rpcRequest({
|
||||
method: 'package.host.address.domain.private.remove',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { pauseFor, Log, RPCErrorDetails, RPCOptions } from '@start9labs/shared'
|
||||
import { pauseFor, Log, RPCErrorDetails } from '@start9labs/shared'
|
||||
import { ApiService } from './embassy-api.service'
|
||||
import {
|
||||
AddOperation,
|
||||
@@ -24,7 +24,7 @@ import { AuthService } from '../auth.service'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { MarketplacePkg } from '@start9labs/marketplace'
|
||||
import { WebSocketSubject } from 'rxjs/webSocket'
|
||||
import { toAcmeUrl } from 'src/app/utils/acme'
|
||||
import { toAuthorityUrl } from 'src/app/utils/acme'
|
||||
|
||||
import markdown from './md-sample.md'
|
||||
|
||||
@@ -71,7 +71,7 @@ export class MockApiService extends ApiService {
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
async uploadPackage(guid: string, body: Blob): Promise<void> {
|
||||
async uploadFile(guid: string, body: Blob): Promise<void> {
|
||||
await pauseFor(2000)
|
||||
}
|
||||
|
||||
@@ -303,17 +303,6 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async getTorLogs(params: RR.GetServerLogsReq): Promise<RR.GetServerLogsRes> {
|
||||
await pauseFor(2000)
|
||||
const entries = this.randomLogs(params.limit)
|
||||
|
||||
return {
|
||||
entries,
|
||||
startCursor: 'startCursor',
|
||||
endCursor: 'end-cursor',
|
||||
}
|
||||
}
|
||||
|
||||
async followServerLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes> {
|
||||
@@ -334,16 +323,6 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async followTorLogs(
|
||||
params: RR.FollowServerLogsReq,
|
||||
): Promise<RR.FollowServerLogsRes> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
startCursor: 'start-cursor',
|
||||
guid: 'logs-guid',
|
||||
}
|
||||
}
|
||||
|
||||
private randomLogs(limit = 1): Log[] {
|
||||
const arrLength = Math.ceil(limit / Mock.ServerLogs.length)
|
||||
const logs = new Array(arrLength)
|
||||
@@ -462,28 +441,32 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async setDns(params: RR.SetDnsReq): Promise<RR.SetDnsRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: ReplaceOperation<T.DnsSettings['staticServers']>[] = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: '/serverInfo/network/dns/staticServers',
|
||||
value: params.servers,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async queryDns(params: RR.QueryDnsReq): Promise<RR.QueryDnsRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async resetTor(params: RR.ResetTorReq): Promise<RR.ResetTorRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// async setOsOutboundProxy(
|
||||
// params: RR.SetOsOutboundProxyReq,
|
||||
// ): Promise<RR.SetOsOutboundProxyRes> {
|
||||
// await pauseFor(2000)
|
||||
|
||||
// const patch = [
|
||||
// {
|
||||
// op: PatchOp.REPLACE,
|
||||
// path: '/serverInfo/network/outboundProxy',
|
||||
// value: params.proxy,
|
||||
// },
|
||||
// ]
|
||||
// this.mockRevision(patch)
|
||||
|
||||
// return null
|
||||
// }
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
async checkOSUpdate(
|
||||
@@ -559,153 +542,67 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
// network
|
||||
// proxies
|
||||
|
||||
// async addProxy(params: RR.AddProxyReq): Promise<RR.AddProxyRes> {
|
||||
// await pauseFor(2000)
|
||||
private proxyId = 0
|
||||
async addTunnel(params: RR.AddTunnelReq): Promise<RR.AddTunnelRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
// const patch = [
|
||||
// {
|
||||
// op: PatchOp.ADD,
|
||||
// path: `/serverInfo/network/networkInterfaces/wga1`,
|
||||
// value: {
|
||||
// inbound: true,
|
||||
// outbound: true,
|
||||
// ipInfo: {
|
||||
// name: params.name,
|
||||
// scopeId: 3,
|
||||
// deviceType: 'wireguard',
|
||||
// subnets: [],
|
||||
// wanIp: '1.1.1.1',
|
||||
// ntpServers: [],
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// this.mockRevision(patch)
|
||||
const id = `wg${this.proxyId++}`
|
||||
|
||||
// return null
|
||||
// }
|
||||
const patch: AddOperation<T.NetworkInterfaceInfo>[] = [
|
||||
{
|
||||
op: PatchOp.ADD,
|
||||
path: `/serverInfo/network/gateways/${id}`,
|
||||
value: {
|
||||
name: params.name,
|
||||
public: params.public,
|
||||
secure: false,
|
||||
ipInfo: {
|
||||
name: id,
|
||||
scopeId: 3,
|
||||
deviceType: 'wireguard',
|
||||
subnets: ['192.168.1.10/24'],
|
||||
wanIp: '203.0.113.45',
|
||||
ntpServers: [],
|
||||
lanIp: ['192.168.1.10'],
|
||||
dnsServers: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
// async updateProxy(params: RR.UpdateProxyReq): Promise<RR.UpdateProxyRes> {
|
||||
// await pauseFor(2000)
|
||||
return { id }
|
||||
}
|
||||
|
||||
// const patch = [
|
||||
// {
|
||||
// op: PatchOp.REPLACE,
|
||||
// path: `/serverInfo/network/proxies/0/name`,
|
||||
// value: params.name,
|
||||
// },
|
||||
// ]
|
||||
// this.mockRevision(patch)
|
||||
async updateTunnel(params: RR.UpdateTunnelReq): Promise<RR.UpdateTunnelRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
// return null
|
||||
// }
|
||||
const patch: ReplaceOperation<string>[] = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/serverInfo/network/gateways/${params.id}/label`,
|
||||
value: params.name,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
// async deleteProxy(params: RR.DeleteProxyReq): Promise<RR.DeleteProxyRes> {
|
||||
// await pauseFor(2000)
|
||||
// const patch = [
|
||||
// {
|
||||
// op: PatchOp.REPLACE,
|
||||
// path: '/serverInfo/network/proxies',
|
||||
// value: [],
|
||||
// },
|
||||
// ]
|
||||
// this.mockRevision(patch)
|
||||
return null
|
||||
}
|
||||
|
||||
// return null
|
||||
// }
|
||||
async removeTunnel(params: RR.RemoveTunnelReq): Promise<RR.RemoveTunnelRes> {
|
||||
await pauseFor(2000)
|
||||
const patch: RemoveOperation[] = [
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/serverInfo/network/gateways/${params.id}`,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
// domains
|
||||
|
||||
// async claimStart9ToDomain(
|
||||
// params: RR.ClaimStart9ToReq,
|
||||
// ): Promise<RR.ClaimStart9ToRes> {
|
||||
// await pauseFor(2000)
|
||||
|
||||
// const patch = [
|
||||
// {
|
||||
// op: PatchOp.REPLACE,
|
||||
// path: '/serverInfo/network/start9To',
|
||||
// value: {
|
||||
// subdomain: 'xyz',
|
||||
// networkInterfaceId: params.networkInterfaceId,
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// this.mockRevision(patch)
|
||||
|
||||
// return null
|
||||
// }
|
||||
|
||||
// async deleteStart9ToDomain(
|
||||
// params: RR.DeleteStart9ToReq,
|
||||
// ): Promise<RR.DeleteStart9ToRes> {
|
||||
// await pauseFor(2000)
|
||||
// const patch = [
|
||||
// {
|
||||
// op: PatchOp.REPLACE,
|
||||
// path: '/serverInfo/network/start9To',
|
||||
// value: null,
|
||||
// },
|
||||
// ]
|
||||
// this.mockRevision(patch)
|
||||
|
||||
// return null
|
||||
// }
|
||||
|
||||
// async addDomain(params: RR.AddDomainReq): Promise<RR.AddDomainRes> {
|
||||
// await pauseFor(2000)
|
||||
|
||||
// const patch = [
|
||||
// {
|
||||
// op: PatchOp.REPLACE,
|
||||
// path: `/serverInfo/network/domains`,
|
||||
// value: {
|
||||
// [params.hostname]: {
|
||||
// networkInterfaceId: params.networkInterfaceId,
|
||||
// provider: params.provider.name,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// this.mockRevision(patch)
|
||||
|
||||
// return null
|
||||
// }
|
||||
|
||||
// async deleteDomain(params: RR.DeleteDomainReq): Promise<RR.DeleteDomainRes> {
|
||||
// await pauseFor(2000)
|
||||
// const patch = [
|
||||
// {
|
||||
// op: PatchOp.REPLACE,
|
||||
// path: '/serverInfo/network/domains',
|
||||
// value: {},
|
||||
// },
|
||||
// ]
|
||||
// this.mockRevision(patch)
|
||||
|
||||
// return null
|
||||
// }
|
||||
|
||||
// port forwards
|
||||
|
||||
// async overridePortForward(
|
||||
// params: RR.OverridePortReq,
|
||||
// ): Promise<RR.OverridePortRes> {
|
||||
// await pauseFor(2000)
|
||||
|
||||
// const patch = [
|
||||
// {
|
||||
// op: PatchOp.REPLACE,
|
||||
// path: '/serverInfo/network/wanConfig/forwards/0/override',
|
||||
// value: params.port,
|
||||
// },
|
||||
// ]
|
||||
// this.mockRevision(patch)
|
||||
|
||||
// return null
|
||||
// }
|
||||
return null
|
||||
}
|
||||
|
||||
// wifi
|
||||
|
||||
@@ -1108,6 +1005,7 @@ export class MockApiService extends ApiService {
|
||||
): Promise<RR.GetActionInputRes> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
eventId: 'ANZXNWIFRTTBZ6T52KQPZILIQQODDHXQ',
|
||||
value: Mock.MockConfig,
|
||||
spec: await Mock.getActionInputSpec(),
|
||||
}
|
||||
@@ -1371,8 +1269,8 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
|
||||
// async setServiceOutboundProxy(
|
||||
// params: RR.SetServiceOutboundProxyReq,
|
||||
// ): Promise<RR.SetServiceOutboundProxyRes> {
|
||||
// params: RR.SetServiceOutboundTunnelReq,
|
||||
// ): Promise<RR.SetServiceOutboundTunnelRes> {
|
||||
// await pauseFor(2000)
|
||||
// const patch = [
|
||||
// {
|
||||
@@ -1394,7 +1292,7 @@ export class MockApiService extends ApiService {
|
||||
op: PatchOp.ADD,
|
||||
path: `/serverInfo/acme`,
|
||||
value: {
|
||||
[toAcmeUrl(params.provider)]: { contact: params.contact },
|
||||
[toAuthorityUrl(params.provider)]: { contact: params.contact },
|
||||
},
|
||||
},
|
||||
]
|
||||
@@ -1421,24 +1319,24 @@ export class MockApiService extends ApiService {
|
||||
|
||||
async addTorKey(params: RR.AddTorKeyReq): Promise<RR.AddTorKeyRes> {
|
||||
await pauseFor(2000)
|
||||
return 'vanityabcdefghijklmnop'
|
||||
return 'vanityabcdefghijklmnop.onion'
|
||||
}
|
||||
|
||||
async generateTorKey(params: RR.GenerateTorKeyReq): Promise<RR.AddTorKeyRes> {
|
||||
await pauseFor(2000)
|
||||
return 'abcdefghijklmnopqrstuv'
|
||||
return 'abcdefghijklmnopqrstuv.onion'
|
||||
}
|
||||
|
||||
async serverBindingSetPubic(
|
||||
params: RR.PkgBindingSetPublicReq,
|
||||
): Promise<RR.BindingSetPublicRes> {
|
||||
async serverBindingToggleGateway(
|
||||
params: RR.ServerBindingToggleGatewayReq,
|
||||
): Promise<RR.ServerBindingToggleGatewayRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/serverInfo/host/bindings/${params.internalPort}/net/public`,
|
||||
value: params.public,
|
||||
path: `/serverInfo/network/host/bindings/${params.internalPort}/net/publicEnabled`,
|
||||
value: params.enabled ? [params.gateway] : [],
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
@@ -1493,15 +1391,17 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async serverAddDomain(params: RR.PkgAddDomainReq): Promise<RR.AddDomainRes> {
|
||||
async osUiAddPublicDomain(
|
||||
params: RR.OsUiAddPublicDomainReq,
|
||||
): Promise<RR.OsUiAddPublicDomainRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: Operation<any>[] = [
|
||||
{
|
||||
op: PatchOp.ADD,
|
||||
path: `/serverInfo/host/domains`,
|
||||
path: `/serverInfo/host/publicDomains`,
|
||||
value: {
|
||||
[params.domain]: { public: !params.private, acme: params.acme },
|
||||
[params.fqdn]: { gateway: params.gateway, acme: params.acme },
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1509,11 +1409,11 @@ export class MockApiService extends ApiService {
|
||||
path: `/serverInfo/host/hostnameInfo/80/0`,
|
||||
value: {
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
public: false,
|
||||
gatewayId: 'eth0',
|
||||
public: true,
|
||||
hostname: {
|
||||
kind: 'domain',
|
||||
domain: params.domain,
|
||||
domain: params.fqdn,
|
||||
subdomain: null,
|
||||
port: null,
|
||||
sslPort: 443,
|
||||
@@ -1526,15 +1426,15 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async serverRemoveDomain(
|
||||
params: RR.PkgRemoveDomainReq,
|
||||
): Promise<RR.RemoveDomainRes> {
|
||||
async osUiRemovePublicDomain(
|
||||
params: RR.OsUiRemovePublicDomainReq,
|
||||
): Promise<RR.OsUiRemovePublicDomainRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/serverInfo/host/domains/${params.domain}`,
|
||||
path: `/serverInfo/host/publicDomains/${params.fqdn}`,
|
||||
},
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
@@ -1546,16 +1446,70 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async pkgBindingSetPubic(
|
||||
params: RR.PkgBindingSetPublicReq,
|
||||
): Promise<RR.BindingSetPublicRes> {
|
||||
async osUiAddPrivateDomain(
|
||||
params: RR.OsUiAddPrivateDomainReq,
|
||||
): Promise<RR.OsUiAddPrivateDomainRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: Operation<any>[] = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/serverInfo/host/privateDomains`,
|
||||
value: [params.fqdn],
|
||||
},
|
||||
{
|
||||
op: PatchOp.ADD,
|
||||
path: `/serverInfo/host/hostnameInfo/80/0`,
|
||||
value: {
|
||||
kind: 'ip',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'domain',
|
||||
domain: params.fqdn,
|
||||
subdomain: null,
|
||||
port: null,
|
||||
sslPort: 443,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async osUiRemovePrivateDomain(
|
||||
params: RR.OsUiRemovePrivateDomainReq,
|
||||
): Promise<RR.OsUiRemovePrivateDomainRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: Operation<any>[] = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/serverInfo/host/privateDomains`,
|
||||
value: [],
|
||||
},
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/serverInfo/host/hostnameInfo/80/0`,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async pkgBindingToggleGateway(
|
||||
params: RR.PkgBindingToggleGatewayReq,
|
||||
): Promise<RR.PkgBindingToggleGatewayRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/bindings/${params.internalPort}/net/public`,
|
||||
value: params.public,
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/bindings/${params.internalPort}/net/privateDisabled`,
|
||||
value: params.enabled ? [] : [params.gateway],
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
@@ -1610,15 +1564,17 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async pkgAddDomain(params: RR.PkgAddDomainReq): Promise<RR.AddDomainRes> {
|
||||
async pkgAddPublicDomain(
|
||||
params: RR.PkgAddPublicDomainReq,
|
||||
): Promise<RR.PkgAddPublicDomainRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: Operation<any>[] = [
|
||||
{
|
||||
op: PatchOp.ADD,
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/domains`,
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/publicDomains`,
|
||||
value: {
|
||||
[params.domain]: { public: !params.private, acme: params.acme },
|
||||
[params.fqdn]: { gateway: params.gateway, acme: params.acme },
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1626,11 +1582,11 @@ export class MockApiService extends ApiService {
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/hostnameInfo/80/0`,
|
||||
value: {
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
public: false,
|
||||
gatewayId: 'eth0',
|
||||
public: true,
|
||||
hostname: {
|
||||
kind: 'domain',
|
||||
domain: params.domain,
|
||||
domain: params.fqdn,
|
||||
subdomain: null,
|
||||
port: null,
|
||||
sslPort: 443,
|
||||
@@ -1643,15 +1599,69 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async pkgRemoveDomain(
|
||||
params: RR.PkgRemoveDomainReq,
|
||||
): Promise<RR.RemoveDomainRes> {
|
||||
async pkgRemovePublicDomain(
|
||||
params: RR.PkgRemovePublicDomainReq,
|
||||
): Promise<RR.PkgRemovePublicDomainRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: RemoveOperation[] = [
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/domains/${params.domain}`,
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/publicDomains/${params.fqdn}`,
|
||||
},
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/hostnameInfo/80/0`,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async pkgAddPrivateDomain(
|
||||
params: RR.PkgAddPrivateDomainReq,
|
||||
): Promise<RR.PkgAddPrivateDomainRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: Operation<any>[] = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/privateDomains`,
|
||||
value: [params.fqdn],
|
||||
},
|
||||
{
|
||||
op: PatchOp.ADD,
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/hostnameInfo/80/0`,
|
||||
value: {
|
||||
kind: 'ip',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'domain',
|
||||
domain: params.fqdn,
|
||||
subdomain: null,
|
||||
port: null,
|
||||
sslPort: 443,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
async pkgRemovePrivateDomain(
|
||||
params: RR.PkgRemovePrivateDomainReq,
|
||||
): Promise<RR.PkgRemovePrivateDomainRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
const patch: Operation<any>[] = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/packageData/${params.package}/hosts/${params.host}/privateDomains`,
|
||||
value: [],
|
||||
},
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { Mock } from './api.fixures'
|
||||
import { knownACME } from 'src/app/utils/acme'
|
||||
import { knownAuthorities } from 'src/app/utils/acme'
|
||||
const version = require('../../../../../../package.json').version
|
||||
|
||||
export const mockPatchData: DataModel = {
|
||||
@@ -28,7 +28,7 @@ export const mockPatchData: DataModel = {
|
||||
lastRegion: null,
|
||||
},
|
||||
acme: {
|
||||
[knownACME[0].url]: {
|
||||
[knownAuthorities[0].url]: {
|
||||
contact: ['mailto:support@start9.com'],
|
||||
},
|
||||
},
|
||||
@@ -39,7 +39,8 @@ export const mockPatchData: DataModel = {
|
||||
net: {
|
||||
assignedPort: null,
|
||||
assignedSslPort: 443,
|
||||
public: false,
|
||||
publicEnabled: [],
|
||||
privateDisabled: [],
|
||||
},
|
||||
options: {
|
||||
preferredExternalPort: 80,
|
||||
@@ -51,13 +52,14 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
},
|
||||
},
|
||||
domains: {},
|
||||
publicDomains: {},
|
||||
privateDomains: [],
|
||||
onions: ['myveryownspecialtoraddress'],
|
||||
hostnameInfo: {
|
||||
80: [
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'local',
|
||||
@@ -68,7 +70,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'wlan0',
|
||||
gatewayId: 'wlan0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'local',
|
||||
@@ -79,7 +81,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv4',
|
||||
@@ -90,7 +92,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'wlan0',
|
||||
gatewayId: 'wlan0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv4',
|
||||
@@ -101,7 +103,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv6',
|
||||
@@ -113,7 +115,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'wlan0',
|
||||
gatewayId: 'wlan0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv6',
|
||||
@@ -134,22 +136,26 @@ export const mockPatchData: DataModel = {
|
||||
],
|
||||
},
|
||||
},
|
||||
networkInterfaces: {
|
||||
gateways: {
|
||||
eth0: {
|
||||
inbound: false,
|
||||
outbound: true,
|
||||
name: null,
|
||||
public: null,
|
||||
secure: null,
|
||||
ipInfo: {
|
||||
name: 'Wired Connection 1',
|
||||
scopeId: 1,
|
||||
deviceType: 'ethernet',
|
||||
subnets: ['10.0.0.2/24'],
|
||||
wanIp: null,
|
||||
wanIp: '203.0.113.45',
|
||||
ntpServers: [],
|
||||
lanIp: ['10.0.2.12'],
|
||||
dnsServers: [],
|
||||
},
|
||||
},
|
||||
wlan0: {
|
||||
inbound: false,
|
||||
outbound: true,
|
||||
name: null,
|
||||
public: null,
|
||||
secure: null,
|
||||
ipInfo: {
|
||||
name: 'Wireless Connection 1',
|
||||
scopeId: 2,
|
||||
@@ -158,10 +164,34 @@ export const mockPatchData: DataModel = {
|
||||
'10.0.90.12/24',
|
||||
'fe80::cd00:0000:0cde:1257:0000:211e:72cd/64',
|
||||
],
|
||||
wanIp: null,
|
||||
wanIp: '203.0.113.45',
|
||||
ntpServers: [],
|
||||
lanIp: ['10.0.90.12'],
|
||||
dnsServers: ['8.8.8.8'],
|
||||
},
|
||||
},
|
||||
wireguard1: {
|
||||
name: 'StartTunnel',
|
||||
public: null,
|
||||
secure: null,
|
||||
ipInfo: {
|
||||
name: 'wireguard1',
|
||||
scopeId: 2,
|
||||
deviceType: 'wireguard',
|
||||
subnets: [
|
||||
'10.0.90.12/24',
|
||||
'fe80::cd00:0000:0cde:1257:0000:211e:72cd/64',
|
||||
],
|
||||
wanIp: '203.0.113.45',
|
||||
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,
|
||||
@@ -200,7 +230,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
},
|
||||
s9pk: '/media/startos/data/package-data/archive/installed/asdfasdf.s9pk',
|
||||
icon: '/assets/img/service-icons/bitcoind.svg',
|
||||
icon: '/assets/img/service-icons/bitcoin-core.svg',
|
||||
lastBackup: new Date(new Date().valueOf() - 604800001).toISOString(),
|
||||
status: {
|
||||
main: 'stopped',
|
||||
@@ -309,7 +339,8 @@ export const mockPatchData: DataModel = {
|
||||
net: {
|
||||
assignedPort: 80,
|
||||
assignedSslPort: 443,
|
||||
public: false,
|
||||
publicEnabled: [],
|
||||
privateDisabled: [],
|
||||
},
|
||||
options: {
|
||||
addSsl: null,
|
||||
@@ -318,13 +349,14 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
},
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: [],
|
||||
onions: [],
|
||||
domains: {},
|
||||
hostnameInfo: {
|
||||
80: [
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'local',
|
||||
@@ -335,7 +367,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'wlan0',
|
||||
gatewayId: 'wlan0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'local',
|
||||
@@ -346,7 +378,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv4',
|
||||
@@ -357,7 +389,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'wlan0',
|
||||
gatewayId: 'wlan0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv4',
|
||||
@@ -368,7 +400,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'eth0',
|
||||
gatewayId: 'eth0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv6',
|
||||
@@ -380,7 +412,7 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
{
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'wlan0',
|
||||
gatewayId: 'wlan0',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'ipv6',
|
||||
@@ -408,7 +440,8 @@ export const mockPatchData: DataModel = {
|
||||
net: {
|
||||
assignedPort: 8332,
|
||||
assignedSslPort: null,
|
||||
public: false,
|
||||
publicEnabled: [],
|
||||
privateDisabled: [],
|
||||
},
|
||||
options: {
|
||||
addSsl: null,
|
||||
@@ -417,8 +450,9 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
},
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: [],
|
||||
onions: [],
|
||||
domains: {},
|
||||
hostnameInfo: {
|
||||
8332: [],
|
||||
},
|
||||
@@ -430,7 +464,8 @@ export const mockPatchData: DataModel = {
|
||||
net: {
|
||||
assignedPort: 8333,
|
||||
assignedSslPort: null,
|
||||
public: false,
|
||||
publicEnabled: [],
|
||||
privateDisabled: [],
|
||||
},
|
||||
options: {
|
||||
addSsl: null,
|
||||
@@ -439,8 +474,9 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
},
|
||||
},
|
||||
publicDomains: {},
|
||||
privateDomains: [],
|
||||
onions: [],
|
||||
domains: {},
|
||||
hostnameInfo: {
|
||||
8333: [],
|
||||
},
|
||||
@@ -557,15 +593,15 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
currentDependencies: {
|
||||
bitcoind: {
|
||||
title: 'Bitcoin Core',
|
||||
icon: 'assets/img/service-icons/bitcoind.svg',
|
||||
title: Mock.BitcoinDep.title,
|
||||
icon: Mock.BitcoinDep.icon,
|
||||
kind: 'running',
|
||||
versionRange: '>=26.0.0',
|
||||
healthChecks: [],
|
||||
},
|
||||
'btc-rpc-proxy': {
|
||||
title: 'Bitcoin Proxy',
|
||||
icon: 'assets/img/service-icons/btc-rpc-proxy.png',
|
||||
title: Mock.ProxyDep.title,
|
||||
icon: Mock.ProxyDep.icon,
|
||||
kind: 'running',
|
||||
versionRange: '>2.0.0',
|
||||
healthChecks: [],
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Inject, Injectable, DOCUMENT } from '@angular/core'
|
||||
import { WorkspaceConfig } from '@start9labs/shared'
|
||||
import { T, utils } from '@start9labs/start-sdk'
|
||||
import { PackageDataEntry } from './patch-db/data-model'
|
||||
|
||||
const {
|
||||
gitHash,
|
||||
@@ -32,25 +31,23 @@ export class ConfigService {
|
||||
return useMocks ? mocks.maskAs === 'tor' : this.hostname.endsWith('.onion')
|
||||
}
|
||||
|
||||
isLocal(): boolean {
|
||||
return useMocks
|
||||
? mocks.maskAs === 'local'
|
||||
: this.hostname.endsWith('.local')
|
||||
}
|
||||
|
||||
isLocalhost(): boolean {
|
||||
return useMocks
|
||||
? mocks.maskAs === 'localhost'
|
||||
: this.hostname === 'localhost' || this.hostname === '127.0.0.1'
|
||||
}
|
||||
|
||||
isIpv4(): boolean {
|
||||
return useMocks
|
||||
? mocks.maskAs === 'ipv4'
|
||||
: new RegExp(utils.Patterns.ipv4.regex).test(this.hostname)
|
||||
isLanHttp(): boolean {
|
||||
return !this.isTor() && !this.isLocalhost() && !this.isHttps()
|
||||
}
|
||||
|
||||
isLanIpv4(): boolean {
|
||||
private isLocal(): boolean {
|
||||
return useMocks
|
||||
? mocks.maskAs === 'local'
|
||||
: this.hostname.endsWith('.local')
|
||||
}
|
||||
|
||||
private isLanIpv4(): boolean {
|
||||
return useMocks
|
||||
? mocks.maskAs === 'ipv4'
|
||||
: new RegExp(utils.Patterns.ipv4.regex).test(this.hostname) &&
|
||||
@@ -79,177 +76,7 @@ export class ConfigService {
|
||||
!this.isIpv6()
|
||||
}
|
||||
|
||||
isLanHttp(): boolean {
|
||||
return !this.isTor() && !this.isLocalhost() && !this.isHttps()
|
||||
}
|
||||
|
||||
isHttps(): boolean {
|
||||
return useMocks ? mocks.maskAsHttps : this.protocol === 'https:'
|
||||
}
|
||||
|
||||
isSecure(): boolean {
|
||||
return window.isSecureContext || this.isTor()
|
||||
}
|
||||
|
||||
isLaunchable(
|
||||
state: T.PackageState['state'],
|
||||
status: T.MainStatus['main'],
|
||||
): boolean {
|
||||
return state === 'installed' && status === 'running'
|
||||
}
|
||||
|
||||
/** ${scheme}://${username}@${host}:${externalPort}${suffix} */
|
||||
launchableAddress(ui: T.ServiceInterface, hosts: T.Hosts): string {
|
||||
const host = hosts[ui.addressInfo.hostId]
|
||||
|
||||
if (!host) return ''
|
||||
|
||||
let hostnameInfo = host.hostnameInfo[ui.addressInfo.internalPort]
|
||||
hostnameInfo =
|
||||
hostnameInfo?.filter(
|
||||
h =>
|
||||
this.isLocalhost() ||
|
||||
h.kind !== 'ip' ||
|
||||
h.hostname.kind !== 'ipv6' ||
|
||||
!h.hostname.value.startsWith('fe80::'),
|
||||
) || []
|
||||
if (this.isLocalhost()) {
|
||||
const local = hostnameInfo.find(
|
||||
h => h.kind === 'ip' && h.hostname.kind === 'local',
|
||||
)
|
||||
if (local) {
|
||||
hostnameInfo.unshift({
|
||||
kind: 'ip',
|
||||
networkInterfaceId: 'lo',
|
||||
public: false,
|
||||
hostname: {
|
||||
kind: 'local',
|
||||
port: local.hostname.port,
|
||||
sslPort: local.hostname.sslPort,
|
||||
value: 'localhost',
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (!hostnameInfo) return ''
|
||||
|
||||
const addressInfo = ui.addressInfo
|
||||
const username = addressInfo.username ? addressInfo.username + '@' : ''
|
||||
const suffix = addressInfo.suffix || ''
|
||||
const url = new URL(`https://${username}placeholder${suffix}`)
|
||||
const use = (hostname: {
|
||||
value: string
|
||||
port: number | null
|
||||
sslPort: number | null
|
||||
}) => {
|
||||
url.hostname = hostname.value
|
||||
const useSsl =
|
||||
hostname.port && hostname.sslPort ? this.isHttps() : !!hostname.sslPort
|
||||
url.protocol = useSsl
|
||||
? `${addressInfo.sslScheme || 'https'}:`
|
||||
: `${addressInfo.scheme || 'http'}:`
|
||||
const port = useSsl ? hostname.sslPort : hostname.port
|
||||
const omitPort = useSsl
|
||||
? ui.addressInfo.sslScheme === 'https' && port === 443
|
||||
: ui.addressInfo.scheme === 'http' && port === 80
|
||||
if (!omitPort && port) url.port = String(port)
|
||||
}
|
||||
const useFirst = (
|
||||
hostnames: (
|
||||
| {
|
||||
value: string
|
||||
port: number | null
|
||||
sslPort: number | null
|
||||
}
|
||||
| undefined
|
||||
)[],
|
||||
) => {
|
||||
const first = hostnames.find(h => h)
|
||||
if (first) {
|
||||
use(first)
|
||||
}
|
||||
return !!first
|
||||
}
|
||||
|
||||
const ipHostnames = hostnameInfo
|
||||
.filter(h => h.kind === 'ip')
|
||||
.map(h => h.hostname) as T.IpHostname[]
|
||||
const domainHostname = ipHostnames
|
||||
.filter(h => h.kind === 'domain')
|
||||
.map(h => h as T.IpHostname & { kind: 'domain' })
|
||||
.map(h => ({
|
||||
value: h.domain,
|
||||
sslPort: h.sslPort,
|
||||
port: h.port,
|
||||
}))[0]
|
||||
const wanIpHostname = hostnameInfo
|
||||
.filter(h => h.kind === 'ip' && h.public && h.hostname.kind !== 'domain')
|
||||
.map(h => h.hostname as Exclude<T.IpHostname, { kind: 'domain' }>)
|
||||
.map(h => ({
|
||||
value: h.value,
|
||||
sslPort: h.sslPort,
|
||||
port: h.port,
|
||||
}))[0]
|
||||
const onionHostname = hostnameInfo
|
||||
.filter(h => h.kind === 'onion')
|
||||
.map(h => h as T.HostnameInfo & { kind: 'onion' })
|
||||
.map(h => ({
|
||||
value: h.hostname.value,
|
||||
sslPort: h.hostname.sslPort,
|
||||
port: h.hostname.port,
|
||||
}))[0]
|
||||
const localHostname = ipHostnames
|
||||
.filter(h => h.kind === 'local')
|
||||
.map(h => h as T.IpHostname & { kind: 'local' })
|
||||
.map(h => ({ value: h.value, sslPort: h.sslPort, port: h.port }))[0]
|
||||
|
||||
if (this.isClearnet()) {
|
||||
if (
|
||||
!useFirst([domainHostname, wanIpHostname, onionHostname, localHostname])
|
||||
) {
|
||||
return ''
|
||||
}
|
||||
} else if (this.isTor()) {
|
||||
if (
|
||||
!useFirst([onionHostname, domainHostname, wanIpHostname, localHostname])
|
||||
) {
|
||||
return ''
|
||||
}
|
||||
} else if (this.isIpv6()) {
|
||||
const ipv6Hostname = ipHostnames.find(h => h.kind === 'ipv6') as {
|
||||
kind: 'ipv6'
|
||||
value: string
|
||||
scopeId: number
|
||||
port: number | null
|
||||
sslPort: number | null
|
||||
}
|
||||
|
||||
if (!useFirst([ipv6Hostname, localHostname])) {
|
||||
return ''
|
||||
}
|
||||
} else {
|
||||
// ipv4 or .local or localhost
|
||||
|
||||
if (!localHostname) return ''
|
||||
|
||||
use({
|
||||
value: this.hostname,
|
||||
port: localHostname.port,
|
||||
sslPort: localHostname.sslPort,
|
||||
})
|
||||
}
|
||||
|
||||
return url.href
|
||||
}
|
||||
|
||||
getHost(): string {
|
||||
return this.host
|
||||
}
|
||||
}
|
||||
|
||||
export function hasUi(
|
||||
interfaces: PackageDataEntry['serviceInterfaces'],
|
||||
): boolean {
|
||||
return Object.values(interfaces).some(iface => iface.type === 'ui')
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ export class ControlsService {
|
||||
private alert(content: i18nKey): Promise<boolean> {
|
||||
return firstValueFrom(
|
||||
this.dialog
|
||||
.openConfirm<boolean>({
|
||||
.openConfirm({
|
||||
label: 'Warning',
|
||||
size: 's',
|
||||
data: {
|
||||
|
||||
@@ -10,11 +10,46 @@ import {
|
||||
import deepEqual from 'fast-deep-equal'
|
||||
import { Observable } from 'rxjs'
|
||||
import { isInstalled } from 'src/app/utils/get-package-data'
|
||||
import { DependencyError } from './api/api.types'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
|
||||
export type AllDependencyErrors = Record<string, PkgDependencyErrors>
|
||||
export type PkgDependencyErrors = Record<string, DependencyError | null>
|
||||
|
||||
export type DependencyError =
|
||||
| DependencyErrorNotInstalled
|
||||
| DependencyErrorNotRunning
|
||||
| DependencyErrorIncorrectVersion
|
||||
| DependencyErrorTaskRequired
|
||||
| DependencyErrorHealthChecksFailed
|
||||
| DependencyErrorTransitive
|
||||
|
||||
export type DependencyErrorNotInstalled = {
|
||||
type: 'notInstalled'
|
||||
}
|
||||
|
||||
export type DependencyErrorNotRunning = {
|
||||
type: 'notRunning'
|
||||
}
|
||||
|
||||
export type DependencyErrorIncorrectVersion = {
|
||||
type: 'incorrectVersion'
|
||||
expected: string // version range
|
||||
received: string // version
|
||||
}
|
||||
|
||||
export interface DependencyErrorTaskRequired {
|
||||
type: 'taskRequired'
|
||||
}
|
||||
|
||||
export type DependencyErrorHealthChecksFailed = {
|
||||
type: 'healthChecksFailed'
|
||||
check: T.NamedHealthCheckResult
|
||||
}
|
||||
|
||||
export type DependencyErrorTransitive = {
|
||||
type: 'transitive'
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
@@ -103,15 +138,17 @@ export class DepErrorService {
|
||||
|
||||
// action required
|
||||
if (
|
||||
Object.values(pkg.tasks).some(
|
||||
t =>
|
||||
t.active &&
|
||||
t.task.packageId === depId &&
|
||||
t.task.severity === 'critical',
|
||||
)
|
||||
Object.values(pkg.tasks)
|
||||
.filter(t => !!t)
|
||||
.some(
|
||||
t =>
|
||||
t.active &&
|
||||
t.task.packageId === depId &&
|
||||
t.task.severity === 'critical',
|
||||
)
|
||||
) {
|
||||
return {
|
||||
type: 'actionRequired',
|
||||
type: 'taskRequired',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
Validators,
|
||||
} from '@angular/forms'
|
||||
import { IST, utils } from '@start9labs/start-sdk'
|
||||
import { tuiCreateFileFormatValidator } from '@taiga-ui/kit'
|
||||
import Mustache from 'mustache'
|
||||
|
||||
@Injectable({
|
||||
@@ -138,6 +139,10 @@ export class FormService {
|
||||
case 'multiselect':
|
||||
value = currentValue === undefined ? spec.default : currentValue
|
||||
return this.formBuilder.control(value, multiselectValidators(spec))
|
||||
case 'hidden':
|
||||
return this.formBuilder.control(currentValue || null)
|
||||
case 'file':
|
||||
return this.formBuilder.control(null, fileValidators(spec))
|
||||
default:
|
||||
return this.formBuilder.control(null)
|
||||
}
|
||||
@@ -236,6 +241,18 @@ function multiselectValidators(spec: IST.ValueSpecMultiselect): ValidatorFn[] {
|
||||
return validators
|
||||
}
|
||||
|
||||
function fileValidators(spec: IST.ValueSpecFile): ValidatorFn[] {
|
||||
const validators: ValidatorFn[] = [
|
||||
tuiCreateFileFormatValidator(spec.extensions.join(',')),
|
||||
]
|
||||
|
||||
if (spec.required) {
|
||||
validators.push(Validators.required)
|
||||
}
|
||||
|
||||
return validators
|
||||
}
|
||||
|
||||
function listValidators(spec: IST.ValueSpecList): ValidatorFn[] {
|
||||
const validators: ValidatorFn[] = []
|
||||
validators.push(listInRange(spec.minLength, spec.maxLength))
|
||||
|
||||
45
web/projects/ui/src/app/services/gateway.service.ts
Normal file
45
web/projects/ui/src/app/services/gateway.service.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { inject, Injectable } from '@angular/core'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { T, utils } from '@start9labs/start-sdk'
|
||||
import { map } from 'rxjs/operators'
|
||||
import { DataModel } from './patch-db/data-model'
|
||||
import { toSignal } from '@angular/core/rxjs-interop'
|
||||
|
||||
export type GatewayPlus = T.NetworkInterfaceInfo & {
|
||||
id: string
|
||||
name: string
|
||||
ipInfo: T.IpInfo
|
||||
subnets: utils.IpNet[]
|
||||
lanIpv4: string[]
|
||||
wanIp?: utils.IpAddress
|
||||
public: boolean
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class GatewayService {
|
||||
readonly gateways = toSignal(
|
||||
inject<PatchDB<DataModel>>(PatchDB)
|
||||
.watch$('serverInfo', 'network', 'gateways')
|
||||
.pipe(
|
||||
map(gateways =>
|
||||
Object.entries(gateways)
|
||||
.filter(([_, val]) => !!val?.ipInfo)
|
||||
.map(([id, val]) => {
|
||||
const subnets =
|
||||
val.ipInfo?.subnets.map(s => utils.IpNet.parse(s)) ?? []
|
||||
const name = val.name ?? val.ipInfo!.name
|
||||
return {
|
||||
...val,
|
||||
id,
|
||||
name,
|
||||
subnets,
|
||||
lanIpv4: subnets.filter(s => s.isIpv4()).map(s => s.address),
|
||||
public: val.public ?? subnets.some(s => s.isPublic()),
|
||||
wanIp:
|
||||
val.ipInfo?.wanIp && utils.IpAddress.parse(val.ipInfo?.wanIp),
|
||||
} as GatewayPlus
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -115,7 +115,6 @@ export class MarketplaceService {
|
||||
flavor: string | null,
|
||||
registryUrl?: string,
|
||||
): Observable<MarketplacePkg> {
|
||||
console.log('HERE')
|
||||
return this.currentRegistry$.pipe(
|
||||
switchMap(registry => {
|
||||
const url = registryUrl || registry.url
|
||||
@@ -147,7 +146,7 @@ export class MarketplaceService {
|
||||
}
|
||||
|
||||
private fetchRegistry$(url: string): Observable<StoreDataWithUrl | null> {
|
||||
console.warn('FETCHING REGISTRY: ', url)
|
||||
console.log('FETCHING REGISTRY: ', url)
|
||||
return combineLatest([this.fetchInfo$(url), this.fetchPackages$(url)]).pipe(
|
||||
map(([info, packages]) => ({ info, packages, url })),
|
||||
catchError(e => {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { Languages } from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
|
||||
export type DataModel = T.Public & { ui: UIData; packageData: AllPackageData }
|
||||
export type DataModel = T.Public & {
|
||||
ui: UIData
|
||||
packageData: AllPackageData
|
||||
}
|
||||
|
||||
export type UIData = {
|
||||
name: string | null
|
||||
@@ -11,22 +14,6 @@ export type UIData = {
|
||||
language: Languages
|
||||
}
|
||||
|
||||
export type NetworkInfo = T.NetworkInfo & {
|
||||
// @TODO 041
|
||||
// start9To: {
|
||||
// subdomain: string
|
||||
// networkInterfaceId: string
|
||||
// } | null
|
||||
// domains: {
|
||||
// [key: string]: Domain
|
||||
// }
|
||||
// wanConfig: {
|
||||
// upnp: boolean
|
||||
// forwards: PortForward[]
|
||||
// }
|
||||
// outboundProxy: string | null
|
||||
}
|
||||
|
||||
export type PackageDataEntry<T extends StateInfo = StateInfo> =
|
||||
T.PackageDataEntry & {
|
||||
stateInfo: T
|
||||
|
||||
@@ -28,7 +28,7 @@ export function getInstalledPrimaryStatus({
|
||||
return Object.values(tasks).some(
|
||||
t => t.active && t.task.severity === 'critical',
|
||||
)
|
||||
? 'actionRequired'
|
||||
? 'taskRequired'
|
||||
: status.main
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ function getHealthStatus(status: T.MainStatus): T.HealthStatus | null {
|
||||
return null
|
||||
}
|
||||
|
||||
const values = Object.values(status.health)
|
||||
const values = Object.values(status.health).filter(h => !!h)
|
||||
|
||||
if (values.some(h => h.result === 'failure')) {
|
||||
return 'failure'
|
||||
@@ -71,7 +71,7 @@ export type PrimaryStatus =
|
||||
| 'restarting'
|
||||
| 'stopped'
|
||||
| 'backingUp'
|
||||
| 'actionRequired'
|
||||
| 'taskRequired'
|
||||
| 'error'
|
||||
|
||||
export type DependencyStatus = 'warning' | 'satisfied'
|
||||
@@ -127,7 +127,7 @@ export const PrimaryRendering: Record<PrimaryStatus, StatusRendering> = {
|
||||
color: 'success',
|
||||
showDots: false,
|
||||
},
|
||||
actionRequired: {
|
||||
taskRequired: {
|
||||
display: 'Task Required',
|
||||
color: 'warning',
|
||||
showDots: false,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @TODO 041
|
||||
|
||||
// import { Injectable } from '@angular/core'
|
||||
// import { ErrorService, LoadingService } from '@start9labs/shared'
|
||||
// import { TuiDialogOptions } from '@taiga-ui/core'
|
||||
@@ -28,14 +26,14 @@
|
||||
// ) {}
|
||||
|
||||
// async presentModalSetOutboundProxy(current: string | null, pkgId?: string) {
|
||||
// const networkInterfaces = await firstValueFrom(
|
||||
// this.patch.watch$('serverInfo', 'network', 'networkInterfaces'),
|
||||
// const gateways = await firstValueFrom(
|
||||
// this.patch.watch$('serverInfo', 'network', 'gateways'),
|
||||
// )
|
||||
// const config = ISB.InputSpec.of({
|
||||
// proxyId: ISB.Value.select({
|
||||
// name: 'Select Proxy',
|
||||
// default: current || '',
|
||||
// values: Object.entries(networkInterfaces)
|
||||
// values: Object.entries(gateways)
|
||||
// .filter(
|
||||
// ([_, n]) => n.outbound && n.ipInfo?.deviceType === 'wireguard',
|
||||
// )
|
||||
@@ -52,7 +50,7 @@
|
||||
// const options: Partial<
|
||||
// TuiDialogOptions<FormContext<typeof config.validator._TYPE>>
|
||||
// > = {
|
||||
// label: 'Outbound Proxy',
|
||||
// label: 'Outbound proxy',
|
||||
// data: {
|
||||
// spec: await configBuilderToSpec(config),
|
||||
// buttons: [
|
||||
|
||||
Reference in New Issue
Block a user