mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Feature/network (#2622)
* Feature: Add in the clear bindings * wip: Working on network * fix: Make it so the config gives the url * chore: Remove the repeated types * chore: Add in the todo's here * chore: UPdate and remove some poorly name var * chore: Remove the clear-bindings impl * chore: Remove the wrapper * handle HostnameInfo for Host bindings Co-authored-by: Jade <Blu-J@users.noreply.github.com> * ?? * chore: Make the install work * Fix: Url's not being created * chore: Fix the local onion in url * include port in hostname * Chore of adding a comment just to modify. --------- Co-authored-by: Aiden McClelland <me@drbonez.dev> Co-authored-by: Jade <Blu-J@users.noreply.github.com>
This commit is contained in:
25
sdk/lib/util/Hostname.ts
Normal file
25
sdk/lib/util/Hostname.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { HostnameInfo } from "../types"
|
||||
|
||||
export function hostnameInfoToAddress(hostInfo: HostnameInfo): string {
|
||||
if (hostInfo.kind === "onion") {
|
||||
return `${hostInfo.hostname.value}`
|
||||
}
|
||||
if (hostInfo.kind !== "ip") {
|
||||
throw Error("Expecting that the kind is ip.")
|
||||
}
|
||||
const hostname = hostInfo.hostname
|
||||
if (hostname.kind === "domain") {
|
||||
return `${hostname.subdomain ? `${hostname.subdomain}.` : ""}${hostname.domain}`
|
||||
}
|
||||
const port = hostname.sslPort || hostname.port
|
||||
const portString = port ? `:${port}` : ""
|
||||
if ("ipv4" === hostname.kind || "ipv6" === hostname.kind) {
|
||||
return `${hostname.value}${portString}`
|
||||
}
|
||||
if ("local" === hostname.kind) {
|
||||
return `${hostname.value}${portString}`
|
||||
}
|
||||
throw Error(
|
||||
"Expecting to have a valid hostname kind." + JSON.stringify(hostname),
|
||||
)
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
import { ServiceInterfaceType } from "../StartSdk"
|
||||
import { knownProtocols } from "../interfaces/Host"
|
||||
import {
|
||||
AddressInfo,
|
||||
Effects,
|
||||
HostInfo,
|
||||
Host,
|
||||
HostAddress,
|
||||
Hostname,
|
||||
HostnameInfo,
|
||||
HostnameInfoIp,
|
||||
HostnameInfoOnion,
|
||||
IpInfo,
|
||||
} from "../types"
|
||||
|
||||
export type UrlString = string
|
||||
@@ -20,13 +25,13 @@ export const getHostname = (url: string): Hostname | null => {
|
||||
}
|
||||
|
||||
export type Filled = {
|
||||
hostnames: Hostname[]
|
||||
onionHostnames: Hostname[]
|
||||
localHostnames: Hostname[]
|
||||
ipHostnames: Hostname[]
|
||||
ipv4Hostnames: Hostname[]
|
||||
ipv6Hostnames: Hostname[]
|
||||
nonIpHostnames: Hostname[]
|
||||
hostnames: HostnameInfo[]
|
||||
onionHostnames: HostnameInfo[]
|
||||
localHostnames: HostnameInfo[]
|
||||
ipHostnames: HostnameInfo[]
|
||||
ipv4Hostnames: HostnameInfo[]
|
||||
ipv6Hostnames: HostnameInfo[]
|
||||
nonIpHostnames: HostnameInfo[]
|
||||
|
||||
urls: UrlString[]
|
||||
onionUrls: UrlString[]
|
||||
@@ -50,7 +55,7 @@ export type ServiceInterfaceFilled = {
|
||||
/** Whether or not to mask the URIs for this interface. Useful if the URIs contain sensitive information, such as a password, macaroon, or API key */
|
||||
masked: boolean
|
||||
/** Information about the host for this binding */
|
||||
hostInfo: HostInfo
|
||||
host: Host
|
||||
/** URI information */
|
||||
addressInfo: FilledAddressInfo
|
||||
/** Indicates if we are a ui/p2p/api for the kind of interface that this is representing */
|
||||
@@ -69,110 +74,103 @@ const negate =
|
||||
(a: A) =>
|
||||
!fn(a)
|
||||
const unique = <A>(values: A[]) => Array.from(new Set(values))
|
||||
function stringifyHostname(info: HostnameInfo): Hostname {
|
||||
let base: string
|
||||
if ("kind" in info.hostname && info.hostname.kind === "domain") {
|
||||
base = info.hostname.subdomain
|
||||
? `${info.hostname.subdomain}.${info.hostname.domain}`
|
||||
: info.hostname.domain
|
||||
} else {
|
||||
base = info.hostname.value
|
||||
export const addressHostToUrl = (
|
||||
{ scheme, sslScheme, username, suffix }: AddressInfo,
|
||||
host: HostnameInfo,
|
||||
): UrlString[] => {
|
||||
const res = []
|
||||
const fmt = (scheme: string | null, host: HostnameInfo, port: number) => {
|
||||
const includePort =
|
||||
scheme &&
|
||||
scheme in knownProtocols &&
|
||||
port === knownProtocols[scheme as keyof typeof knownProtocols].defaultPort
|
||||
let hostname
|
||||
if (host.kind === "onion") {
|
||||
hostname = host.hostname.value
|
||||
} else if (host.kind === "ip") {
|
||||
if (host.hostname.kind === "domain") {
|
||||
hostname = `${host.hostname.subdomain ? `${host.hostname.subdomain}.` : ""}${host.hostname.domain}`
|
||||
} else {
|
||||
hostname = host.hostname.value
|
||||
}
|
||||
}
|
||||
return `${scheme ? `${scheme}://` : ""}${
|
||||
username ? `${username}@` : ""
|
||||
}${hostname}${includePort ? `:${port}` : ""}${suffix}`
|
||||
}
|
||||
if (info.hostname.port && info.hostname.sslPort) {
|
||||
return `${base}:${info.hostname.port}` as Hostname
|
||||
} else if (info.hostname.sslPort) {
|
||||
return `${base}:${info.hostname.sslPort}` as Hostname
|
||||
} else if (info.hostname.port) {
|
||||
return `${base}:${info.hostname.port}` as Hostname
|
||||
if (host.hostname.sslPort !== null) {
|
||||
res.push(fmt(sslScheme, host, host.hostname.sslPort))
|
||||
}
|
||||
return base as Hostname
|
||||
}
|
||||
const addressHostToUrl = (
|
||||
{ bindOptions, username, suffix }: AddressInfo,
|
||||
host: Hostname,
|
||||
): UrlString => {
|
||||
const scheme = host.endsWith(".onion")
|
||||
? bindOptions.scheme
|
||||
: bindOptions.addSsl
|
||||
? bindOptions.addSsl.scheme
|
||||
: bindOptions.scheme // TODO: encode whether hostname transport is "secure"?
|
||||
return `${scheme ? `${scheme}//` : ""}${
|
||||
username ? `${username}@` : ""
|
||||
}${host}${suffix}`
|
||||
if (host.hostname.port !== null) {
|
||||
res.push(fmt(scheme, host, host.hostname.port))
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
export const filledAddress = (
|
||||
hostInfo: HostInfo,
|
||||
host: Host,
|
||||
addressInfo: AddressInfo,
|
||||
): FilledAddressInfo => {
|
||||
const toUrl = addressHostToUrl.bind(null, addressInfo)
|
||||
const hostnameInfo =
|
||||
hostInfo.kind == "multi"
|
||||
? hostInfo.hostnames
|
||||
: hostInfo.hostname
|
||||
? [hostInfo.hostname]
|
||||
: []
|
||||
const hostnames = host.hostnameInfo[addressInfo.internalPort]
|
||||
|
||||
return {
|
||||
...addressInfo,
|
||||
hostnames: hostnameInfo.flatMap((h) => stringifyHostname(h)),
|
||||
hostnames,
|
||||
get onionHostnames() {
|
||||
return hostnameInfo
|
||||
.filter((h) => h.kind === "onion")
|
||||
.map((h) => stringifyHostname(h))
|
||||
return hostnames.filter((h) => h.kind === "onion")
|
||||
},
|
||||
get localHostnames() {
|
||||
return hostnameInfo
|
||||
.filter((h) => h.kind === "ip" && h.hostname.kind === "local")
|
||||
.map((h) => stringifyHostname(h))
|
||||
return hostnames.filter(
|
||||
(h) => h.kind === "ip" && h.hostname.kind === "local",
|
||||
)
|
||||
},
|
||||
get ipHostnames() {
|
||||
return hostnameInfo
|
||||
.filter(
|
||||
(h) =>
|
||||
h.kind === "ip" &&
|
||||
(h.hostname.kind === "ipv4" || h.hostname.kind === "ipv6"),
|
||||
)
|
||||
.map((h) => stringifyHostname(h))
|
||||
return hostnames.filter(
|
||||
(h) =>
|
||||
h.kind === "ip" &&
|
||||
(h.hostname.kind === "ipv4" || h.hostname.kind === "ipv6"),
|
||||
)
|
||||
},
|
||||
get ipv4Hostnames() {
|
||||
return hostnameInfo
|
||||
.filter((h) => h.kind === "ip" && h.hostname.kind === "ipv4")
|
||||
.map((h) => stringifyHostname(h))
|
||||
return hostnames.filter(
|
||||
(h) => h.kind === "ip" && h.hostname.kind === "ipv4",
|
||||
)
|
||||
},
|
||||
get ipv6Hostnames() {
|
||||
return hostnameInfo
|
||||
.filter((h) => h.kind === "ip" && h.hostname.kind === "ipv6")
|
||||
.map((h) => stringifyHostname(h))
|
||||
return hostnames.filter(
|
||||
(h) => h.kind === "ip" && h.hostname.kind === "ipv6",
|
||||
)
|
||||
},
|
||||
get nonIpHostnames() {
|
||||
return hostnameInfo
|
||||
.filter(
|
||||
(h) =>
|
||||
h.kind === "ip" &&
|
||||
h.hostname.kind !== "ipv4" &&
|
||||
h.hostname.kind !== "ipv6",
|
||||
)
|
||||
.map((h) => stringifyHostname(h))
|
||||
return hostnames.filter(
|
||||
(h) =>
|
||||
h.kind === "ip" &&
|
||||
h.hostname.kind !== "ipv4" &&
|
||||
h.hostname.kind !== "ipv6",
|
||||
)
|
||||
},
|
||||
get urls() {
|
||||
return this.hostnames.map(toUrl)
|
||||
return this.hostnames.flatMap(toUrl)
|
||||
},
|
||||
get onionUrls() {
|
||||
return this.onionHostnames.map(toUrl)
|
||||
return this.onionHostnames.flatMap(toUrl)
|
||||
},
|
||||
get localUrls() {
|
||||
return this.localHostnames.map(toUrl)
|
||||
return this.localHostnames.flatMap(toUrl)
|
||||
},
|
||||
get ipUrls() {
|
||||
return this.ipHostnames.map(toUrl)
|
||||
return this.ipHostnames.flatMap(toUrl)
|
||||
},
|
||||
get ipv4Urls() {
|
||||
return this.ipv4Hostnames.map(toUrl)
|
||||
return this.ipv4Hostnames.flatMap(toUrl)
|
||||
},
|
||||
get ipv6Urls() {
|
||||
return this.ipv6Hostnames.map(toUrl)
|
||||
return this.ipv6Hostnames.flatMap(toUrl)
|
||||
},
|
||||
get nonIpUrls() {
|
||||
return this.nonIpHostnames.map(toUrl)
|
||||
return this.nonIpHostnames.flatMap(toUrl)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -193,23 +191,25 @@ const makeInterfaceFilled = async ({
|
||||
packageId,
|
||||
callback,
|
||||
})
|
||||
const hostInfo = await effects.getHostInfo({
|
||||
packageId,
|
||||
kind: null,
|
||||
serviceInterfaceId: serviceInterfaceValue.id,
|
||||
callback,
|
||||
})
|
||||
const primaryUrl = await effects.getPrimaryUrl({
|
||||
serviceInterfaceId: id,
|
||||
const hostId = serviceInterfaceValue.addressInfo.hostId
|
||||
const host = await effects.getHostInfo({
|
||||
packageId,
|
||||
hostId,
|
||||
callback,
|
||||
})
|
||||
const primaryUrl = await effects
|
||||
.getPrimaryUrl({
|
||||
serviceInterfaceId: id,
|
||||
packageId,
|
||||
callback,
|
||||
})
|
||||
.catch((e) => null)
|
||||
|
||||
const interfaceFilled: ServiceInterfaceFilled = {
|
||||
...serviceInterfaceValue,
|
||||
primaryUrl: primaryUrl,
|
||||
hostInfo,
|
||||
addressInfo: filledAddress(hostInfo, serviceInterfaceValue.addressInfo),
|
||||
host,
|
||||
addressInfo: filledAddress(host, serviceInterfaceValue.addressInfo),
|
||||
get primaryHostname() {
|
||||
if (primaryUrl == null) return null
|
||||
return getHostname(primaryUrl)
|
||||
|
||||
@@ -18,41 +18,27 @@ const makeManyInterfaceFilled = async ({
|
||||
packageId,
|
||||
callback,
|
||||
})
|
||||
const hostIdsRecord = Object.fromEntries(
|
||||
await Promise.all(
|
||||
Array.from(new Set(serviceInterfaceValues.map((x) => x.id))).map(
|
||||
async (id) =>
|
||||
[
|
||||
id,
|
||||
await effects.getHostInfo({
|
||||
kind: null,
|
||||
packageId,
|
||||
serviceInterfaceId: id,
|
||||
callback,
|
||||
}),
|
||||
] as const,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
const serviceInterfacesFilled: ServiceInterfaceFilled[] = await Promise.all(
|
||||
serviceInterfaceValues.map(async (serviceInterfaceValue) => {
|
||||
const hostInfo = await effects.getHostInfo({
|
||||
kind: null,
|
||||
packageId,
|
||||
serviceInterfaceId: serviceInterfaceValue.id,
|
||||
callback,
|
||||
})
|
||||
const primaryUrl = await effects.getPrimaryUrl({
|
||||
serviceInterfaceId: serviceInterfaceValue.id,
|
||||
Object.values(serviceInterfaceValues).map(async (serviceInterfaceValue) => {
|
||||
const hostId = serviceInterfaceValue.addressInfo.hostId
|
||||
const host = await effects.getHostInfo({
|
||||
packageId,
|
||||
hostId,
|
||||
callback,
|
||||
})
|
||||
const primaryUrl = await effects
|
||||
.getPrimaryUrl({
|
||||
serviceInterfaceId: serviceInterfaceValue.id,
|
||||
packageId,
|
||||
callback,
|
||||
})
|
||||
.catch(() => null)
|
||||
return {
|
||||
...serviceInterfaceValue,
|
||||
primaryUrl: primaryUrl,
|
||||
hostInfo,
|
||||
addressInfo: filledAddress(hostInfo, serviceInterfaceValue.addressInfo),
|
||||
host,
|
||||
addressInfo: filledAddress(host, serviceInterfaceValue.addressInfo),
|
||||
get primaryHostname() {
|
||||
if (primaryUrl == null) return null
|
||||
return getHostname(primaryUrl)
|
||||
|
||||
@@ -10,6 +10,8 @@ import "./once"
|
||||
|
||||
export { GetServiceInterface, getServiceInterface } from "./getServiceInterface"
|
||||
export { getServiceInterfaces } from "./getServiceInterfaces"
|
||||
export { addressHostToUrl } from "./getServiceInterface"
|
||||
export { hostnameInfoToAddress } from "./Hostname"
|
||||
// prettier-ignore
|
||||
export type FlattenIntersection<T> =
|
||||
T extends ArrayLike<any> ? T :
|
||||
|
||||
Reference in New Issue
Block a user