diff --git a/lib/config/configConstants.ts b/lib/config/configConstants.ts index 8220ef2..13cfe32 100644 --- a/lib/config/configConstants.ts +++ b/lib/config/configConstants.ts @@ -41,12 +41,6 @@ export const customSmtp = Config.of, never>({ required: false, masked: true, }), - tls: Value.toggle({ - name: "Require Transport Security", - default: true, - description: - "Require TLS transport security. If disabled, email will use plaintext by default and TLS via STARTTLS if the SMTP server supports it. If enabled, email will refuse to connect unless the server supports STARTTLS.", - }), }) /** diff --git a/lib/interfaces/NetworkInterfaceBuilder.ts b/lib/interfaces/NetworkInterfaceBuilder.ts index dc1124f..ff9e430 100644 --- a/lib/interfaces/NetworkInterfaceBuilder.ts +++ b/lib/interfaces/NetworkInterfaceBuilder.ts @@ -21,6 +21,8 @@ export class NetworkInterfaceBuilder { name: string id: string description: string + hasPrimary: boolean + disabled: boolean ui: boolean username: null | string path: string @@ -39,7 +41,17 @@ export class NetworkInterfaceBuilder { async export[]>( origins: Origins, ): Promise { - const { name, description, id, ui, username, path, search } = this.options + const { + name, + description, + hasPrimary, + disabled, + id, + ui, + username, + path, + search, + } = this.options const addresses = Array.from(origins).map((o) => o.build({ username, path, search, scheme: null }), @@ -49,6 +61,8 @@ export class NetworkInterfaceBuilder { interfaceId: id, name, description, + hasPrimary, + disabled, addresses, ui, }) diff --git a/lib/test/host.test.ts b/lib/test/host.test.ts index 1d2fcf0..559c4cc 100644 --- a/lib/test/host.test.ts +++ b/lib/test/host.test.ts @@ -1,8 +1,6 @@ -import { MultiHost } from "../interfaces/Host" import { NetworkInterfaceBuilder } from "../interfaces/NetworkInterfaceBuilder" import { Effects } from "../types" import { createUtils } from "../util" -import { sdk } from "./output.sdk" describe("host", () => { test("Testing that the types work", () => { @@ -15,6 +13,8 @@ describe("host", () => { name: "Foo", id: "foo", description: "A Foo", + hasPrimary: false, + disabled: false, ui: true, username: "bar", path: "/baz", diff --git a/lib/test/util.getNetworkInterface.test.ts b/lib/test/util.getNetworkInterface.test.ts new file mode 100644 index 0000000..bfddb4e --- /dev/null +++ b/lib/test/util.getNetworkInterface.test.ts @@ -0,0 +1,20 @@ +import { getHostname } from "../util/getNetworkInterface" + +describe("getHostname ", () => { + const inputToExpected = [ + ["http://localhost:3000", "localhost"], + ["http://localhost", "localhost"], + ["localhost", "localhost"], + ["http://127.0.0.1/", "127.0.0.1"], + ["http://127.0.0.1/testing/1234?314345", "127.0.0.1"], + ["127.0.0.1/", "127.0.0.1"], + ["http://mail.google.com/", "mail.google.com"], + ["mail.google.com/", "mail.google.com"], + ] + + for (const [input, expectValue] of inputToExpected) { + test(`should return ${expectValue} for ${input}`, () => { + expect(getHostname(input)).toEqual(expectValue) + }) + } +}) diff --git a/lib/types.ts b/lib/types.ts index c10d47f..dfec7b3 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -2,6 +2,7 @@ export * as configTypes from "./config/configTypes" import { InputSpec } from "./config/configTypes" import { DependenciesReceipt } from "./config/setupConfig" import { PortOptions } from "./interfaces/Host" +import { UrlString } from "./util/getNetworkInterface" export type ExportedAction = (options: { effects: Effects @@ -143,7 +144,6 @@ export type SmtpValue = { from: string login: string password: string | null | undefined - tls: boolean } export type CommandType = @@ -185,12 +185,16 @@ export type NetworkInterface = { name: string /** Human readable description, used as tooltip usually */ description: string + /** Whether or not one address must be the primary address */ + hasPrimary: boolean + /** Disabled interfaces do not serve, but they retain their metadata and addresses */ + disabled: boolean /** All URIs */ addresses: Address[] /** Defaults to false, but describes if this address can be opened in a browser as an * ui interface */ - ui?: boolean + ui: boolean } // prettier-ignore export type ExposeAllServicePaths = @@ -370,6 +374,16 @@ export type Effects = { callback: () => void }): Promise + /** + * The user sets the primary url for a interface + * @param options + */ + getPrimaryUrl(options: { + packageId?: PackageId + interfaceId: InterfaceId + callback: () => void + }): Promise + /** * There are times that we want to see the addresses that where exported * @param options.addressId If we want to filter the address id diff --git a/lib/util/getNetworkInterface.ts b/lib/util/getNetworkInterface.ts index f3d3e7b..51e83fb 100644 --- a/lib/util/getNetworkInterface.ts +++ b/lib/util/getNetworkInterface.ts @@ -4,6 +4,16 @@ import * as regexes from "./regexes" export type UrlString = string export type HostId = string +const getHostnameRegex = /^(\w+:\/\/)?([^\/\:]+)(:\d{1,3})?(\/)?/ +export const getHostname = (url: string): HostName | null => { + const founds = url.match(getHostnameRegex)?.[2] + if (!founds) return null + const parts = founds.split("@") + const last = parts[parts.length - 1] as HostName | null + console.log({ url, parts, founds, last }) + return last +} + export type Filled = { hostnames: HostName[] onionHostnames: HostName[] @@ -30,12 +40,19 @@ export type NetworkInterfaceFilled = { name: string /** Human readable description, used as tooltip usually */ description: string + /** Whether or not the interface has a primary URL */ + hasPrimary: boolean + /** Whether or not the interface disabled */ + disabled: boolean /** All URIs */ addresses: FilledAddress[] /** Defaults to false, but describes if this address can be opened in a browser as an * ui interface */ - ui?: boolean + ui: boolean + + primaryHostname: HostName | null + primaryUrl: UrlString | null } & Filled const either = (...args: ((a: A) => boolean)[]) => @@ -118,6 +135,7 @@ export const filledAddress = ( export const networkInterfaceFilled = ( interfaceValue: NetworkInterface, + primaryUrl: UrlString | null, addresses: FilledAddress[], ): NetworkInterfaceFilled => { return { @@ -147,6 +165,10 @@ export const networkInterfaceFilled = ( get allHostnames() { return unique(addresses.flatMap((x) => x.allHostnames)) }, + get primaryHostname() { + if (primaryUrl == null) return null + return getHostname(primaryUrl) + }, get urls() { return unique(addresses.flatMap((x) => x.urls)) }, @@ -171,6 +193,7 @@ export const networkInterfaceFilled = ( get allUrls() { return unique(addresses.flatMap((x) => x.allUrls)) }, + primaryUrl, } } const makeInterfaceFilled = async ({ @@ -189,24 +212,32 @@ const makeInterfaceFilled = async ({ packageId, callback, }) - const hostIdsRecord: { [hostId: HostId]: HostName[] } = Object.fromEntries( - await Promise.all( - unique(interfaceValue.addresses.map((x) => x.hostId)).map( - async (hostId) => [ + const hostIdsRecord = Promise.all( + unique(interfaceValue.addresses.map((x) => x.hostId)).map( + async (hostId) => + [ hostId, - effects.getHostnames({ + await effects.getHostnames({ packageId, hostId, callback, }), - ], - ), + ] as const, ), ) + const primaryUrl = effects.getPrimaryUrl({ + interfaceId, + packageId, + callback, + }) - const fillAddress = filledAddress.bind(null, hostIdsRecord) + const fillAddress = filledAddress.bind( + null, + Object.fromEntries(await hostIdsRecord), + ) const interfaceFilled: NetworkInterfaceFilled = networkInterfaceFilled( interfaceValue, + await primaryUrl, interfaceValue.addresses.map(fillAddress), ) return interfaceFilled diff --git a/lib/util/getNetworkInterfaces.ts b/lib/util/getNetworkInterfaces.ts index f56321a..625b761 100644 --- a/lib/util/getNetworkInterfaces.ts +++ b/lib/util/getNetworkInterfaces.ts @@ -19,30 +19,39 @@ const makeManyInterfaceFilled = async ({ packageId, callback, }) - const hostIdsRecord: { [hostId: HostId]: HostName[] } = Object.fromEntries( + const hostIdsRecord = Object.fromEntries( await Promise.all( Array.from( new Set( interfaceValues.flatMap((x) => x.addresses).map((x) => x.hostId), ), - ).map(async (hostId) => [ - hostId, - effects.getHostnames({ - packageId, - hostId, - callback, - }), - ]), + ).map( + async (hostId) => + [ + hostId, + await effects.getHostnames({ + packageId, + hostId, + callback, + }), + ] as const, + ), ), ) const fillAddress = filledAddress.bind(null, hostIdsRecord) - const interfacesFilled: NetworkInterfaceFilled[] = interfaceValues.map( - (interfaceValue) => + const interfacesFilled: NetworkInterfaceFilled[] = await Promise.all( + interfaceValues.map(async (interfaceValue) => networkInterfaceFilled( interfaceValue, + await effects.getPrimaryUrl({ + interfaceId: interfaceValue.interfaceId, + packageId, + callback, + }), interfaceValue.addresses.map(fillAddress), ), + ), ) return interfacesFilled } diff --git a/lib/util/utils.ts b/lib/util/utils.ts index c0f1cfd..b238fab 100644 --- a/lib/util/utils.ts +++ b/lib/util/utils.ts @@ -56,6 +56,8 @@ export type Utils = { name: string id: string description: string + hasPrimary: boolean + disabled: boolean ui: boolean username: null | string path: string @@ -114,6 +116,8 @@ export const utils = ( name: string id: string description: string + hasPrimary: boolean + disabled: boolean ui: boolean username: null | string path: string diff --git a/package-lock.json b/package-lock.json index ed5492c..efc6b45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@start9labs/start-sdk", - "version": "0.4.0-rev0.lib0.rc4", + "version": "0.4.0-rev0.lib0.rc5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@start9labs/start-sdk", - "version": "0.4.0-rev0.lib0.rc4", + "version": "0.4.0-rev0.lib0.rc5", "license": "MIT", "dependencies": { "@iarna/toml": "^2.2.5", diff --git a/package.json b/package.json index 6e9d54e..761818f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@start9labs/start-sdk", - "version": "0.4.0-rev0.lib0.rc4", + "version": "0.4.0-rev0.lib0.rc5", "description": "Software development kit to facilitate packaging services for StartOS", "main": "./lib/index.js", "types": "./lib/index.d.ts",