From f9f38fb3f0f1ddac74383b35001adfa8b6223a96 Mon Sep 17 00:00:00 2001 From: Owen Date: Mon, 14 Sep 2026 14:07:26 -0400 Subject: [PATCH] Handle the agent and agent version --- messages/en-US.json | 1 + server/db/pg/schema/schema.ts | 2 +- server/db/sqlite/schema/schema.ts | 2 +- .../routers/newt/handleNewtRegisterMessage.ts | 6 +- .../clients/user/[niceId]/general/page.tsx | 65 +------------------ src/components/ClientInfoCard.tsx | 62 +++++++++++++++++- src/components/SiteInfoCard.tsx | 11 ++-- src/components/SitesTable.tsx | 13 +++- src/components/newt-install-commands.tsx | 10 +-- 9 files changed, 91 insertions(+), 81 deletions(-) diff --git a/messages/en-US.json b/messages/en-US.json index 80e2fa8ed..c6ac24e6d 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -153,6 +153,7 @@ "siteResourcesTargetsOnSite": "Targets on this site", "siteSetting": "{siteName} Settings", "siteNewtTunnel": "Pangolin Site (Recommended)", + "pangolinSite": "Pangolin Site", "siteNewtTunnelDescription": "Easiest way to create an entrypoint into any network. No extra setup.", "siteWg": "Basic WireGuard", "siteWgDescription": "Use any WireGuard client to establish a tunnel. Manual NAT setup required.", diff --git a/server/db/pg/schema/schema.ts b/server/db/pg/schema/schema.ts index 15bbd1992..744e88b98 100644 --- a/server/db/pg/schema/schema.ts +++ b/server/db/pg/schema/schema.ts @@ -682,7 +682,7 @@ export const newts = pgTable( secretHash: varchar("secretHash").notNull(), dateCreated: varchar("dateCreated").notNull(), version: varchar("version"), - agent: varchar("agent").default("newt"), // either newt or cli + agent: varchar("agent"), // either newt or cli agentVersion: varchar("agentVersion"), siteId: integer("siteId").references(() => sites.siteId, { onDelete: "cascade" diff --git a/server/db/sqlite/schema/schema.ts b/server/db/sqlite/schema/schema.ts index 51c1e76d2..e30bc678e 100644 --- a/server/db/sqlite/schema/schema.ts +++ b/server/db/sqlite/schema/schema.ts @@ -703,7 +703,7 @@ export const newts = sqliteTable( secretHash: text("secretHash").notNull(), dateCreated: text("dateCreated").notNull(), version: text("version"), - agent: text("agent").default("newt"), // either newt or cli + agent: text("agent"), // either newt or cli agentVersion: text("agentVersion"), siteId: integer("siteId").references(() => sites.siteId, { onDelete: "cascade" diff --git a/server/routers/newt/handleNewtRegisterMessage.ts b/server/routers/newt/handleNewtRegisterMessage.ts index 1d0d1aef8..7adc74a1b 100644 --- a/server/routers/newt/handleNewtRegisterMessage.ts +++ b/server/routers/newt/handleNewtRegisterMessage.ts @@ -171,7 +171,11 @@ export const handleNewtRegisterMessage: MessageHandler = async (context) => { logger.error(`Failed to add peer to exit node: ${error}`); } - if (newtVersion && newtVersion !== newt.version) { + if ( + newtVersion !== newt.version || + agent !== newt.agent || + agentVersion !== newt.agentVersion + ) { // update the newt version in the database await db .update(newts) diff --git a/src/app/[orgId]/settings/clients/user/[niceId]/general/page.tsx b/src/app/[orgId]/settings/clients/user/[niceId]/general/page.tsx index 0ed7c7b16..a5a1a4a31 100644 --- a/src/app/[orgId]/settings/clients/user/[niceId]/general/page.tsx +++ b/src/app/[orgId]/settings/clients/user/[niceId]/general/page.tsx @@ -19,7 +19,6 @@ import { InfoSections, InfoSectionTitle } from "@app/components/InfoSection"; -import { Badge } from "@app/components/ui/badge"; import { Button } from "@app/components/ui/button"; import ActionBanner from "@app/components/ActionBanner"; import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert"; @@ -41,13 +40,6 @@ import { useParams } from "next/navigation"; import { FaApple, FaWindows, FaLinux } from "react-icons/fa"; import { SiAndroid } from "react-icons/si"; import { tierMatrix } from "@server/lib/billing/tierMatrix"; -import { - productUpdatesQueries, - type LatestVersionResponse -} from "@app/lib/queries"; -import { useQuery } from "@tanstack/react-query"; -import semver from "semver"; -import { InfoPopup } from "@app/components/ui/info-popup"; function formatTimestamp(timestamp: number | null | undefined): string { if (!timestamp) return "-"; @@ -173,34 +165,6 @@ export default function GeneralPage() { }>(null); const [isCheckingCache, setIsCheckingCache] = useState(false); const [isRebuildingCache, setIsRebuildingCache] = useState(false); - const data = useQuery(productUpdatesQueries.latestVersion(true)); - const latestPlatformVersions = data.data?.data; - - const agentVersionMap: Record = { - "Pangolin Windows": "windows", - "Pangolin Android": "android", - "Pangolin iOS": "ios", - "Pangolin iPadOS": "ios", - "Pangolin macOS": "mac", - "Pangolin CLI": "cli", - "Olm CLI": "olm" - }; - - let updateAvailable = false; - if (client.agent && client.olmVersion && latestPlatformVersions) { - const agent = agentVersionMap[ - client.agent - ] as keyof LatestVersionResponse; - - if (agent in latestPlatformVersions) { - const agentVersion = latestPlatformVersions[agent]; - - updateAvailable = Boolean( - semver.valid(client.olmVersion) && - semver.lt(client.olmVersion, agentVersion.latestVersion) - ); - } - } // get "imp" from local storage to determine if we should show the verify button (imp = "1" means show) const showVerifyButton = @@ -467,7 +431,7 @@ export default function GeneralPage() { )} {/* Device Information Section */} - {(client.fingerprint || (client.agent && client.olmVersion)) && ( + {client.fingerprint && ( @@ -479,33 +443,6 @@ export default function GeneralPage() { - {client.agent && client.olmVersion && ( -
- - - {t("agent")} - - -
- - {client.agent + - " v" + - client.olmVersion} - - - {updateAvailable && ( - - )} -
-
-
-
- )} - {client.fingerprint && (() => { const platform = client.fingerprint.platform; diff --git a/src/components/ClientInfoCard.tsx b/src/components/ClientInfoCard.tsx index 428f65f6b..cfd004e62 100644 --- a/src/components/ClientInfoCard.tsx +++ b/src/components/ClientInfoCard.tsx @@ -11,9 +11,26 @@ import { import IdpTypeBadge from "@app/components/IdpTypeBadge"; import { getUserDisplayName } from "@app/lib/getUserDisplayName"; import { useTranslations } from "next-intl"; +import { + productUpdatesQueries, + type LatestVersionResponse +} from "@app/lib/queries"; +import { useQuery } from "@tanstack/react-query"; +import semver from "semver"; +import { InfoPopup } from "@app/components/ui/info-popup"; type ClientInfoCardProps = {}; +const agentVersionMap: Record = { + "Pangolin Windows": "windows", + "Pangolin Android": "android", + "Pangolin iOS": "ios", + "Pangolin iPadOS": "ios", + "Pangolin macOS": "mac", + "Pangolin CLI": "cli", + "Olm CLI": "olm" +}; + export default function SiteInfoCard({}: ClientInfoCardProps) { const { client, updateClient } = useClientContext(); const t = useTranslations(); @@ -24,14 +41,57 @@ export default function SiteInfoCard({}: ClientInfoCardProps) { username: client.userUsername }); + const data = useQuery(productUpdatesQueries.latestVersion(true)); + const latestPlatformVersions = data.data?.data; + + let updateAvailable = false; + if (client.agent && client.olmVersion && latestPlatformVersions) { + const agent = agentVersionMap[ + client.agent + ] as keyof LatestVersionResponse; + + if (agent in latestPlatformVersions) { + const agentVersion = latestPlatformVersions[agent]; + + updateAvailable = Boolean( + semver.valid(client.olmVersion) && + semver.lt(client.olmVersion, agentVersion.latestVersion) + ); + } + } + + const cols = + 2 + + (userDisplayName ? 1 : 0) + + (client.agent && client.olmVersion ? 1 : 0); + return ( - + {t("name")} {client.name} + {client.agent && client.olmVersion ? ( + + {t("agent")} + +
+ + {client.agent + + " v" + + client.olmVersion} + + {updateAvailable && ( + + )} +
+
+
+ ) : null} {userDisplayName ? ( {t("user")} diff --git a/src/components/SiteInfoCard.tsx b/src/components/SiteInfoCard.tsx index 59743c82c..f8a1b1fbb 100644 --- a/src/components/SiteInfoCard.tsx +++ b/src/components/SiteInfoCard.tsx @@ -63,7 +63,6 @@ export default function SiteInfoCard({}: SiteInfoCardProps) { ) : null; if (site.type === "newt") { - const isCli = site.agent === "cli"; return ( @@ -74,14 +73,16 @@ export default function SiteInfoCard({}: SiteInfoCardProps) { {t("connectionType")} - {isCli ? "CLI" : "Newt"} + {t("pangolinSite")} - - {t("newtVersion")} - + {t("agent")} + {site.agent == "newt" ? "Newt" : null} + {site.agent == "cli" + ? "Pangolin CLI" + : null}{" "} {site.agentVersion ? `v${site.agentVersion}` : "-"} diff --git a/src/components/SitesTable.tsx b/src/components/SitesTable.tsx index baf43fd24..31d2fae3b 100644 --- a/src/components/SitesTable.tsx +++ b/src/components/SitesTable.tsx @@ -371,7 +371,7 @@ export default function SitesTable({ }, { accessorKey: "type", - friendlyName: t("type"), + friendlyName: t("agent"), header: () => { return {t("type")}; }, @@ -386,13 +386,20 @@ export default function SitesTable({ ); if (originalRow.type === "newt") { - const isCli = originalRow.agent === "cli"; + if (!originalRow.agent) { + return -; + } return (
- {isCli ? "CLI" : "Newt"} + {originalRow.agent == "newt" + ? "Newt" + : null} + {originalRow.agent == "cli" + ? "Pangolin CLI" + : null} {originalRow.agentVersion && ( diff --git a/src/components/newt-install-commands.tsx b/src/components/newt-install-commands.tsx index f0496382e..ad5c29f5e 100644 --- a/src/components/newt-install-commands.tsx +++ b/src/components/newt-install-commands.tsx @@ -97,7 +97,7 @@ export function NewtSiteInstallCommands({ command: `${runAsRootPrefix}pangolin up site --id ${id} --secret ${secret} --endpoint ${endpoint}${acceptClientsFlag}${disableSshFlag}` } ], - "Auto Systemd Service": [ + "Systemd Service": [ { title: t("install"), command: `curl -fsSL https://static.pangolin.net/get-cli.sh | bash` @@ -141,7 +141,7 @@ sudo chmod 600 /etc/pangolin/pangolin-site.env` title: t("serviceFile"), command: `sudo tee /etc/systemd/system/pangolin-site.service > /dev/null << 'EOF' [Unit] -Description=Newt +Description=Pangolin Site Wants=network-online.target After=network-online.target @@ -223,9 +223,9 @@ sudo systemctl enable --now pangolin-site` docker: { "Docker Compose": [ `services: - newt: + pangolin-site: image: fosrl/pangolin-cli - container_name: newt + container_name: pangolin-site restart: unless-stopped environment: - PANGOLIN_ENDPOINT=${endpoint} @@ -521,7 +521,7 @@ function getPlatformName(platformName: Platform) { function getArchitectures(platform: Platform) { switch (platform) { case "linux": - return ["Run", "Auto Systemd Service", "Manual Systemd Service"]; + return ["Run", "Systemd Service", "Manual Systemd Service"]; case "macos": return ["Run", "Service"]; case "windows":