diff --git a/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx b/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx index a29480e0..8f750bf2 100644 --- a/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx +++ b/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx @@ -39,6 +39,7 @@ import { } from "@app/lib/wireguard"; import { QRCodeCanvas } from "qrcode.react"; import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert"; +import { NewtSiteInstallCommands } from "@app/components/newt-install-commands"; export default function CredentialsPage() { const { env } = useEnvContext(); @@ -186,107 +187,120 @@ export default function CredentialsPage() { return site?.name || site?.niceId || "My site"; }; - const displayNewtId = currentNewtId || siteDefaults?.newtId || null; - const displaySecret = regeneratedSecret || null; + const displayNewtId = currentNewtId ?? siteDefaults?.newtId ?? null; + const displaySecret = regeneratedSecret ?? null; return ( <> {site?.type === "newt" && ( - - - - {t("siteNewtCredentials")} - - - {t("siteNewtCredentialsDescription")} - - + <> + + + + {t("siteNewtCredentials")} + + + {t("siteNewtCredentialsDescription")} + + - + - - - - - {t("newtEndpoint")} - - - - - - - - {t("newtId")} - - - {displayNewtId ? ( + + + + + {t("newtEndpoint")} + + - ) : ( - {"••••••••••••••••"} - )} - - - - - {t("newtSecretKey")} - - - {displaySecret ? ( - - ) : ( - - { - "••••••••••••••••••••••••••••••••" - } - - )} - - - + + + + + {t("newtId")} + + + {displayNewtId ? ( + + ) : ( + + {"••••••••••••••••"} + + )} + + + + + {t("newtSecretKey")} + + + {displaySecret ? ( + + ) : ( + + { + "••••••••••••••••••••••••••••••••" + } + + )} + + + - {showCredentialsAlert && displaySecret && ( - - - - {t("siteCredentialsSave")} - - - {t("siteCredentialsSaveDescription")} - - + {showCredentialsAlert && displaySecret && ( + + + + {t("siteCredentialsSave")} + + + {t( + "siteCredentialsSaveDescription" + )} + + + )} + + {build !== "oss" && ( + + + + )} - - {build !== "oss" && ( - - - - - )} - + + + + )} {site?.type === "wireguard" && ( diff --git a/src/app/[orgId]/settings/sites/create/page.tsx b/src/app/[orgId]/settings/sites/create/page.tsx index 133a94f2..a873cbe2 100644 --- a/src/app/[orgId]/settings/sites/create/page.tsx +++ b/src/app/[orgId]/settings/sites/create/page.tsx @@ -62,6 +62,8 @@ import { QRCodeCanvas } from "qrcode.react"; import { useTranslations } from "next-intl"; import { build } from "@server/build"; +import { NewtSiteInstallCommands } from "@app/components/newt-install-commands"; +import { id } from "date-fns/locale"; type SiteType = "newt" | "wireguard" | "local"; @@ -189,10 +191,6 @@ export default function Page() { const [loadingPage, setLoadingPage] = useState(true); - const [platform, setPlatform] = useState("unix"); - const [architecture, setArchitecture] = useState("amd64"); - const [commands, setCommands] = useState(null); - const [newtId, setNewtId] = useState(""); const [newtSecret, setNewtSecret] = useState(""); const [newtEndpoint, setNewtEndpoint] = useState(""); @@ -202,7 +200,6 @@ export default function Page() { const [wgConfig, setWgConfig] = useState(""); const [createLoading, setCreateLoading] = useState(false); - const [acceptClients, setAcceptClients] = useState(true); const [newtVersion, setNewtVersion] = useState("latest"); const [showAdvancedSettings, setShowAdvancedSettings] = useState(false); @@ -216,187 +213,6 @@ export default function Page() { string | undefined >(); - const hydrateCommands = ( - id: string, - secret: string, - endpoint: string, - version: string, - acceptClients: boolean = true - ) => { - const acceptClientsFlag = !acceptClients ? " --disable-clients" : ""; - const acceptClientsEnv = !acceptClients - ? "\n - DISABLE_CLIENTS=true" - : ""; - - const commands = { - unix: { - All: [ - { - title: t("install"), - command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash` - }, - { - title: t("run"), - command: `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` - } - ] - }, - windows: { - x64: [ - { - title: t("install"), - command: `curl -o newt.exe -L "https://github.com/fosrl/newt/releases/download/${version}/newt_windows_amd64.exe"` - }, - { - title: t("run"), - command: `newt.exe --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` - } - ] - }, - docker: { - "Docker Compose": [ - `services: - newt: - image: fosrl/newt - container_name: newt - restart: unless-stopped - environment: - - PANGOLIN_ENDPOINT=${endpoint} - - NEWT_ID=${id} - - NEWT_SECRET=${secret}${acceptClientsEnv}` - ], - "Docker Run": [ - `docker run -dit fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` - ] - }, - kubernetes: { - "Helm Chart": [ - `helm repo add fossorial https://charts.fossorial.io`, - `helm repo update fossorial`, - `helm install newt fossorial/newt \\ - --create-namespace \\ - --set newtInstances[0].name="main-tunnel" \\ - --set-string newtInstances[0].auth.keys.endpointKey="${endpoint}" \\ - --set-string newtInstances[0].auth.keys.idKey="${id}" \\ - --set-string newtInstances[0].auth.keys.secretKey="${secret}"` - ] - }, - podman: { - "Podman Quadlet": [ - `[Unit] -Description=Newt container - -[Container] -ContainerName=newt -Image=docker.io/fosrl/newt -Environment=PANGOLIN_ENDPOINT=${endpoint} -Environment=NEWT_ID=${id} -Environment=NEWT_SECRET=${secret}${!acceptClients ? "\nEnvironment=DISABLE_CLIENTS=true" : ""} -# Secret=newt-secret,type=env,target=NEWT_SECRET - -[Service] -Restart=always - -[Install] -WantedBy=default.target` - ], - "Podman Run": [ - `podman run -dit docker.io/fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` - ] - }, - nixos: { - All: [ - `nix run 'nixpkgs#fosrl-newt' -- --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` - ] - } - }; - setCommands(commands); - }; - - const getArchitectures = () => { - switch (platform) { - case "unix": - return ["All"]; - case "windows": - return ["x64"]; - case "docker": - return ["Docker Compose", "Docker Run"]; - case "kubernetes": - return ["Helm Chart"]; - case "podman": - return ["Podman Quadlet", "Podman Run"]; - case "nixos": - return ["All"]; - default: - return ["x64"]; - } - }; - - const getPlatformName = (platformName: string) => { - switch (platformName) { - case "windows": - return "Windows"; - case "unix": - return "Unix & macOS"; - case "docker": - return "Docker"; - case "kubernetes": - return "Kubernetes"; - case "podman": - return "Podman"; - case "nixos": - return "NixOS"; - default: - return "Unix / macOS"; - } - }; - - const getCommand = (): CommandItem[] => { - const placeholder: CommandItem[] = [t("unknownCommand")]; - if (!commands) { - return placeholder; - } - let platformCommands = commands[platform as keyof Commands]; - - if (!platformCommands) { - // get first key - const firstPlatform = Object.keys(commands)[0] as Platform; - platformCommands = commands[firstPlatform as keyof Commands]; - - setPlatform(firstPlatform); - } - - let architectureCommands = platformCommands[architecture]; - if (!architectureCommands) { - // get first key - const firstArchitecture = Object.keys(platformCommands)[0]; - architectureCommands = platformCommands[firstArchitecture]; - - setArchitecture(firstArchitecture); - } - - return architectureCommands || placeholder; - }; - - const getPlatformIcon = (platformName: string) => { - switch (platformName) { - case "windows": - return ; - case "unix": - return ; - case "docker": - return ; - case "kubernetes": - return ; - case "podman": - return ; - case "nixos": - return ; - default: - return ; - } - }; - const form = useForm({ resolver: zodResolver(createSiteFormSchema), defaultValues: { @@ -414,7 +230,7 @@ WantedBy=default.target` let payload: CreateSiteBody = { name: data.name, - type: data.method as "newt" | "wireguard" | "local" + type: data.method }; if (data.method == "wireguard") { @@ -568,14 +384,6 @@ WantedBy=default.target` setNewtEndpoint(newtEndpoint); setClientAddress(clientAddress); - hydrateCommands( - newtId, - newtSecret, - env.app.dashboardUrl, - currentNewtVersion, - acceptClients - ); - const wgConfig = generateWireGuardConfig( privateKey, data.publicKey, @@ -631,11 +439,6 @@ WantedBy=default.target` load(); }, []); - // Sync form acceptClients value with local state - useEffect(() => { - form.setValue("acceptClients", acceptClients); - }, [acceptClients, form]); - // Sync form exitNodeId value with local state useEffect(() => { if (build !== "saas") { @@ -847,214 +650,15 @@ WantedBy=default.target` - - {/*
*/} - {/* */} - {/* ( */} - {/* */} - {/*
*/} - {/* { */} - {/* form.setValue( */} - {/* "copied", */} - {/* e as boolean */} - {/* ); */} - {/* }} */} - {/* /> */} - {/* */} - {/*
*/} - {/* */} - {/*
*/} - {/* )} */} - {/* /> */} - {/* */} - {/* */} - - - - {t("siteInstallNewt")} - - - {t("siteInstallNewtDescription")} - - - -
-

- {t("operatingSystem")} -

-
- {platforms.map((os) => ( - - ))} -
-
-
-

- {["docker", "podman"].includes( - platform - ) - ? t("method") - : t("architecture")} -

-
- {getArchitectures().map( - (arch) => ( - - ) - )} -
- -
-

- {t("siteConfiguration")} -

-
- { - const value = - checked as boolean; - setAcceptClients( - value - ); - form.setValue( - "acceptClients", - value - ); - // Re-hydrate commands with new acceptClients value - if ( - newtId && - newtSecret && - newtVersion - ) { - hydrateCommands( - newtId, - newtSecret, - env.app - .dashboardUrl, - newtVersion, - value - ); - } - }} - label={t( - "siteAcceptClientConnections" - )} - /> -
-

- {t( - "siteAcceptClientConnectionsDescription" - )} -

-
- -
-

- {t("commands")} -

-
- {getCommand().map( - (item, index) => { - const commandText = - typeof item === - "string" - ? item - : item.command; - const title = - typeof item === - "string" - ? undefined - : item.title; - - return ( -
- {title && ( -

- { - title - } -

- )} - -
- ); - } - )} -
-
-
-
-
+ )} diff --git a/src/components/commands.tsx b/src/components/commands.tsx deleted file mode 100644 index daee185c..00000000 --- a/src/components/commands.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import { useTranslations } from "next-intl"; -import CopyTextBox from "./CopyTextBox"; - -import type { id } from "date-fns/locale"; - -// function getCommand(): CommandItem[] { -// const placeholder: CommandItem[] = [t("unknownCommand")]; -// if (!commands) { -// return placeholder; -// } -// let platformCommands = commands[platform as keyof Commands]; - -// if (!platformCommands) { -// // get first key -// const firstPlatform = Object.keys(commands)[0] as Platform; -// platformCommands = commands[firstPlatform as keyof Commands]; - -// setPlatform(firstPlatform); -// } - -// let architectureCommands = platformCommands[architecture]; -// if (!architectureCommands) { -// // get first key -// const firstArchitecture = Object.keys(platformCommands)[0]; -// architectureCommands = platformCommands[firstArchitecture]; - -// setArchitecture(firstArchitecture); -// } - -// return architectureCommands || placeholder; -// }; - -export type CommandItem = string | { title: string; command: string }; - -type CommandByPlatform = { - unix: Record; - windows: Record; - docker: Record; - kubernetes: Record; - podman: Record; - nixos: Record; -}; -type Platform = keyof CommandByPlatform; - -export type SiteCommandsProps = { - id: string; - secret: string; - endpoint: string; - version: string; - acceptClients: boolean; - platform: Platform; -}; - -export function SiteCommands({ - acceptClients, - id, - secret, - endpoint, - version, - platform -}: SiteCommandsProps) { - const t = useTranslations(); - - const acceptClientsFlag = !acceptClients ? " --disable-clients" : ""; - const acceptClientsEnv = !acceptClients - ? "\n - DISABLE_CLIENTS=true" - : ""; - - const commandList: Record> = { - unix: { - All: [ - { - title: t("install"), - command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash` - }, - { - title: t("run"), - command: `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` - } - ] - }, - windows: { - x64: [ - { - title: t("install"), - command: `curl -o newt.exe -L "https://github.com/fosrl/newt/releases/download/${version}/newt_windows_amd64.exe"` - }, - { - title: t("run"), - command: `newt.exe --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` - } - ] - }, - docker: { - "Docker Compose": [ - `services: - newt: - image: fosrl/newt - container_name: newt - restart: unless-stopped - environment: - - PANGOLIN_ENDPOINT=${endpoint} - - NEWT_ID=${id} - - NEWT_SECRET=${secret}${acceptClientsEnv}` - ], - "Docker Run": [ - `docker run -dit fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` - ] - }, - kubernetes: { - "Helm Chart": [ - `helm repo add fossorial https://charts.fossorial.io`, - `helm repo update fossorial`, - `helm install newt fossorial/newt \\ - --create-namespace \\ - --set newtInstances[0].name="main-tunnel" \\ - --set-string newtInstances[0].auth.keys.endpointKey="${endpoint}" \\ - --set-string newtInstances[0].auth.keys.idKey="${id}" \\ - --set-string newtInstances[0].auth.keys.secretKey="${secret}"` - ] - }, - podman: { - "Podman Quadlet": [ - `[Unit] -Description=Newt container - -[Container] -ContainerName=newt -Image=docker.io/fosrl/newt -Environment=PANGOLIN_ENDPOINT=${endpoint} -Environment=NEWT_ID=${id} -Environment=NEWT_SECRET=${secret}${!acceptClients ? "\nEnvironment=DISABLE_CLIENTS=true" : ""} -# Secret=newt-secret,type=env,target=NEWT_SECRET - -[Service] -Restart=always - -[Install] -WantedBy=default.target` - ], - "Podman Run": [ - `podman run -dit docker.io/fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` - ] - }, - nixos: { - All: [ - `nix run 'nixpkgs#fosrl-newt' -- --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` - ] - } - }; - - const commands = commandList[platform]; - - return ( -
- {[].map((item, index) => { - const commandText = - typeof item === "string" ? item : item.command; - const title = typeof item === "string" ? undefined : item.title; - - return ( -
- {title && ( -

- {title} -

- )} - -
- ); - })} -
- ); -} diff --git a/src/components/newt-install-commands.tsx b/src/components/newt-install-commands.tsx new file mode 100644 index 00000000..c1be0f51 --- /dev/null +++ b/src/components/newt-install-commands.tsx @@ -0,0 +1,315 @@ +import { useTranslations } from "next-intl"; +import CopyTextBox from "./CopyTextBox"; +import { + SettingsSection, + SettingsSectionBody, + SettingsSectionDescription, + SettingsSectionHeader, + SettingsSectionTitle +} from "./Settings"; +import { CheckboxWithLabel } from "./ui/checkbox"; +import { Button } from "./ui/button"; +import { useState } from "react"; +import { FaCubes, FaDocker, FaWindows } from "react-icons/fa"; +import { Terminal } from "lucide-react"; +import { SiKubernetes, SiNixos } from "react-icons/si"; + +export type CommandItem = string | { title: string; command: string }; + +const PLATFORMS = [ + "unix", + "windows", + "docker", + "kubernetes", + "podman", + "nixos" +] as const; + +type Platform = (typeof PLATFORMS)[number]; + +export type NewtSiteInstallCommandsProps = { + id: string; + secret: string; + endpoint: string; + version: string; +}; + +export function NewtSiteInstallCommands({ + id, + secret, + endpoint, + version +}: NewtSiteInstallCommandsProps) { + const t = useTranslations(); + + const [platform, setPlatform] = useState("unix"); + const [acceptClients, setAcceptClients] = useState(true); + + const acceptClientsFlag = !acceptClients ? " --disable-clients" : ""; + const acceptClientsEnv = !acceptClients + ? "\n - DISABLE_CLIENTS=true" + : ""; + + const commandList: Record> = { + unix: { + All: [ + { + title: t("install"), + command: `curl -fsSL https://static.pangolin.net/get-newt.sh | bash` + }, + { + title: t("run"), + command: `newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` + } + ] + }, + windows: { + x64: [ + { + title: t("install"), + command: `curl -o newt.exe -L "https://github.com/fosrl/newt/releases/download/${version}/newt_windows_amd64.exe"` + }, + { + title: t("run"), + command: `newt.exe --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` + } + ] + }, + docker: { + "Docker Compose": [ + `services: + newt: + image: fosrl/newt + container_name: newt + restart: unless-stopped + environment: + - PANGOLIN_ENDPOINT=${endpoint} + - NEWT_ID=${id} + - NEWT_SECRET=${secret}${acceptClientsEnv}` + ], + "Docker Run": [ + `docker run -dit fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` + ] + }, + kubernetes: { + "Helm Chart": [ + `helm repo add fossorial https://charts.fossorial.io`, + `helm repo update fossorial`, + `helm install newt fossorial/newt \\ + --create-namespace \\ + --set newtInstances[0].name="main-tunnel" \\ + --set-string newtInstances[0].auth.keys.endpointKey="${endpoint}" \\ + --set-string newtInstances[0].auth.keys.idKey="${id}" \\ + --set-string newtInstances[0].auth.keys.secretKey="${secret}"` + ] + }, + podman: { + "Podman Quadlet": [ + `[Unit] +Description=Newt container + +[Container] +ContainerName=newt +Image=docker.io/fosrl/newt +Environment=PANGOLIN_ENDPOINT=${endpoint} +Environment=NEWT_ID=${id} +Environment=NEWT_SECRET=${secret}${!acceptClients ? "\nEnvironment=DISABLE_CLIENTS=true" : ""} +# Secret=newt-secret,type=env,target=NEWT_SECRET + +[Service] +Restart=always + +[Install] +WantedBy=default.target` + ], + "Podman Run": [ + `podman run -dit docker.io/fosrl/newt --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` + ] + }, + nixos: { + All: [ + `nix run 'nixpkgs#fosrl-newt' -- --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}` + ] + } + }; + + const [architecture, setArchitecture] = useState( + () => getArchitectures(platform)[0] + ); + + const commands = commandList[platform][architecture]; + + return ( + + + + {t("siteInstallNewt")} + + + {t("siteInstallNewtDescription")} + + + +
+

{t("operatingSystem")}

+
+ {PLATFORMS.map((os) => ( + + ))} +
+
+ +
+

+ {["docker", "podman"].includes(platform) + ? t("method") + : t("architecture")} +

+
+ {getArchitectures(platform).map((arch) => ( + + ))} +
+ +
+

+ {t("siteConfiguration")} +

+
+ { + const value = checked as boolean; + setAcceptClients(value); + }} + label={t("siteAcceptClientConnections")} + /> +
+

+ {t("siteAcceptClientConnectionsDescription")} +

+
+ +
+

{t("commands")}

+
+ {commands.map((item, index) => { + const commandText = + typeof item === "string" + ? item + : item.command; + const title = + typeof item === "string" + ? undefined + : item.title; + + return ( +
+ {title && ( +

+ {title} +

+ )} + +
+ ); + })} +
+
+
+
+
+ ); +} + +function getPlatformIcon(platformName: Platform) { + switch (platformName) { + case "windows": + return ; + case "unix": + return ; + case "docker": + return ; + case "kubernetes": + return ; + case "podman": + return ; + case "nixos": + return ; + default: + return ; + } +} + +function getPlatformName(platformName: Platform) { + switch (platformName) { + case "windows": + return "Windows"; + case "unix": + return "Unix & macOS"; + case "docker": + return "Docker"; + case "kubernetes": + return "Kubernetes"; + case "podman": + return "Podman"; + case "nixos": + return "NixOS"; + default: + return "Unix / macOS"; + } +} + +function getArchitectures(platform: Platform) { + switch (platform) { + case "unix": + return ["All"]; + case "windows": + return ["x64"]; + case "docker": + return ["Docker Compose", "Docker Run"]; + case "kubernetes": + return ["Helm Chart"]; + case "podman": + return ["Podman Quadlet", "Podman Run"]; + case "nixos": + return ["All"]; + default: + return ["x64"]; + } +}