Compare commits

..

7 Commits

Author SHA1 Message Date
dependabot[bot]
635137226e Bump fast-xml-parser, @aws-sdk/client-s3 and @aws-sdk/client-sesv2
Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) to 5.3.4 and updates ancestor dependencies [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser), [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-s3) and [@aws-sdk/client-sesv2](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-sesv2). These dependencies need to be updated together.


Updates `fast-xml-parser` from 5.2.5 to 5.3.4
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v5.2.5...v5.3.4)

Updates `@aws-sdk/client-s3` from 3.971.0 to 3.983.0
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.983.0/clients/client-s3)

Updates `@aws-sdk/client-sesv2` from 3.946.0 to 3.983.0
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-sesv2/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.983.0/clients/client-sesv2)

---
updated-dependencies:
- dependency-name: fast-xml-parser
  dependency-version: 5.3.4
  dependency-type: indirect
- dependency-name: "@aws-sdk/client-s3"
  dependency-version: 3.983.0
  dependency-type: direct:production
- dependency-name: "@aws-sdk/client-sesv2"
  dependency-version: 3.983.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-05 05:46:03 +00:00
Owen
b4c01349d1 Merge branch 'dev' 2026-02-04 21:44:07 -08:00
Owen
e4d4c62833 Dont create newt sites with exit node or subnet 2026-02-02 18:19:13 -08:00
Owen
20ae903d7f Subscribed limits for domains is higher 2026-02-02 16:46:48 -08:00
MoweME
b0566d3c6f fix(i18n): correct German site terminology
Updates the German translation to use "Standort" (site) instead of "Seite" (page) for consistency with the site context.
2026-01-29 10:01:30 -08:00
MoweME
5dda8c384f fix(i18n): correct German translation strings
Corrects mistranslation of device timestamp labels and fixes product name reference in site tunnel settings.
2026-01-29 10:01:30 -08:00
Owen
cb569ff14d Properly insert PANGOLIN_SETUP_TOKEN into db
Fixes #2361
2026-01-28 15:03:31 -08:00
10 changed files with 523 additions and 1178 deletions

View File

@@ -97,7 +97,7 @@
"siteGeneralDescription": "Allgemeine Einstellungen für diesen Standort konfigurieren",
"siteSettingDescription": "Standorteinstellungen konfigurieren",
"siteSetting": "{siteName} Einstellungen",
"siteNewtTunnel": "Neuer Standort (empfohlen)",
"siteNewtTunnel": "Newt Standort (empfohlen)",
"siteNewtTunnelDescription": "Einfachster Weg, einen Einstiegspunkt in jedes Netzwerk zu erstellen. Keine zusätzliche Einrichtung.",
"siteWg": "Einfacher WireGuard Tunnel",
"siteWgDescription": "Verwende jeden WireGuard-Client, um einen Tunnel einzurichten. Manuelles NAT-Setup erforderlich.",
@@ -107,7 +107,7 @@
"siteSeeAll": "Alle Standorte anzeigen",
"siteTunnelDescription": "Legen Sie fest, wie Sie sich mit dem Standort verbinden möchten",
"siteNewtCredentials": "Zugangsdaten",
"siteNewtCredentialsDescription": "So wird sich die Seite mit dem Server authentifizieren",
"siteNewtCredentialsDescription": "So wird sich der Standort mit dem Server authentifizieren",
"remoteNodeCredentialsDescription": "So wird sich der entfernte Node mit dem Server authentifizieren",
"siteCredentialsSave": "Anmeldedaten speichern",
"siteCredentialsSaveDescription": "Du kannst das nur einmal sehen. Stelle sicher, dass du es an einen sicheren Ort kopierst.",
@@ -2503,7 +2503,7 @@
"deviceModel": "Gerätemodell",
"serialNumber": "Seriennummer",
"hostname": "Hostname",
"firstSeen": "Erster Blick",
"firstSeen": "Zuerst gesehen",
"lastSeen": "Zuletzt gesehen",
"biometricsEnabled": "Biometrie aktiviert",
"diskEncrypted": "Festplatte verschlüsselt",

1602
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -34,7 +34,7 @@
},
"dependencies": {
"@asteasolutions/zod-to-openapi": "8.4.0",
"@aws-sdk/client-s3": "3.971.0",
"@aws-sdk/client-s3": "3.983.0",
"@faker-js/faker": "10.2.0",
"@headlessui/react": "2.2.9",
"@hookform/resolvers": "5.2.2",

View File

@@ -17,7 +17,6 @@ import { hashPassword } from "@server/auth/password";
import { isValidIP } from "@server/lib/validators";
import { isIpInCidr } from "@server/lib/ip";
import { verifyExitNodeOrgAccess } from "#dynamic/lib/exitNodes";
import { build } from "@server/build";
const createSiteParamsSchema = z.strictObject({
orgId: z.string()
@@ -259,7 +258,19 @@ export async function createSite(
let newSite: Site;
await db.transaction(async (trx) => {
if (type == "wireguard" || type == "newt") {
if (type == "newt") {
[newSite] = await trx
.insert(sites)
.values({
orgId,
name,
niceId,
address: updatedAddress || null,
type,
dockerSocketEnabled: true
})
.returning();
} else if (type == "wireguard") {
// we are creating a site with an exit node (tunneled)
if (!subnet) {
return next(
@@ -311,11 +322,9 @@ export async function createSite(
exitNodeId,
name,
niceId,
address: updatedAddress || null,
subnet,
type,
dockerSocketEnabled: type == "newt",
...(pubKey && type == "wireguard" && { pubKey })
pubKey: pubKey || null
})
.returning();
} else if (type == "local") {

View File

@@ -7,35 +7,22 @@ import { cache } from "react";
export const dynamic = "force-dynamic";
type Props = {
searchParams: Promise<{ code?: string; user?: string }>;
searchParams: Promise<{ code?: string }>;
};
function deviceRedirectSearchParams(params: {
code?: string;
user?: string;
}): string {
const search = new URLSearchParams();
if (params.code) search.set("code", params.code);
if (params.user) search.set("user", params.user);
const q = search.toString();
return q ? `?${q}` : "";
}
export default async function DeviceLoginPage({ searchParams }: Props) {
const user = await verifySession({ forceLogin: true });
const params = await searchParams;
const code = params.code || "";
const defaultUser = params.user;
if (!user) {
const redirectDestination = `/auth/login/device${deviceRedirectSearchParams({ code, user: params.user })}`;
const loginUrl = new URL("/auth/login", "http://x");
loginUrl.searchParams.set("forceLogin", "true");
loginUrl.searchParams.set("redirect", redirectDestination);
if (defaultUser) loginUrl.searchParams.set("user", defaultUser);
console.log("loginUrl", loginUrl.pathname + loginUrl.search);
redirect(loginUrl.pathname + loginUrl.search);
const redirectDestination = code
? `/auth/login/device?code=${encodeURIComponent(code)}`
: "/auth/login/device";
redirect(
`/auth/login?forceLogin=true&redirect=${encodeURIComponent(redirectDestination)}`
);
}
const userName = user
@@ -50,7 +37,6 @@ export default async function DeviceLoginPage({ searchParams }: Props) {
userEmail={user?.email || ""}
userName={userName}
initialCode={code}
userQueryParam={defaultUser}
/>
);
}

View File

@@ -72,8 +72,6 @@ export default async function Page(props: {
searchParams.redirect = redirectUrl;
}
const defaultUser = searchParams.user as string | undefined;
// Only use SmartLoginForm if NOT (OSS build OR org-only IdP enabled)
const useSmartLogin =
build === "saas" || (build === "enterprise" && env.flags.useOrgOnlyIdp);
@@ -153,7 +151,6 @@ export default async function Page(props: {
<SmartLoginForm
redirect={redirectUrl}
forceLogin={forceLogin}
defaultUser={defaultUser}
/>
</CardContent>
</Card>
@@ -168,7 +165,6 @@ export default async function Page(props: {
(build === "saas" || env.flags.useOrgOnlyIdp)
}
searchParams={searchParams}
defaultUser={defaultUser}
/>
)}

View File

@@ -29,7 +29,6 @@ type DashboardLoginFormProps = {
searchParams?: {
[key: string]: string | string[] | undefined;
};
defaultUser?: string;
};
export default function DashboardLoginForm({
@@ -37,8 +36,7 @@ export default function DashboardLoginForm({
idps,
forceLogin,
showOrgLogin,
searchParams,
defaultUser
searchParams
}: DashboardLoginFormProps) {
const router = useRouter();
const { env } = useEnvContext();
@@ -77,7 +75,6 @@ export default function DashboardLoginForm({
redirect={redirect}
idps={idps}
forceLogin={forceLogin}
defaultEmail={defaultUser}
onLogin={(redirectUrl) => {
if (redirectUrl) {
const safe = cleanRedirect(redirectUrl);

View File

@@ -55,14 +55,12 @@ type DeviceLoginFormProps = {
userEmail: string;
userName?: string;
initialCode?: string;
userQueryParam?: string;
};
export default function DeviceLoginForm({
userEmail,
userName,
initialCode = "",
userQueryParam
initialCode = ""
}: DeviceLoginFormProps) {
const router = useRouter();
const { env } = useEnvContext();
@@ -221,12 +219,9 @@ export default function DeviceLoginForm({
const currentSearch =
typeof window !== "undefined" ? window.location.search : "";
const redirectTarget = `/auth/login/device${currentSearch || ""}`;
const loginUrl = new URL("/auth/login", "http://x");
loginUrl.searchParams.set("forceLogin", "true");
loginUrl.searchParams.set("redirect", redirectTarget);
if (userQueryParam)
loginUrl.searchParams.set("user", userQueryParam);
router.push(loginUrl.pathname + loginUrl.search);
router.push(
`/auth/login?forceLogin=true&redirect=${encodeURIComponent(redirectTarget)}`
);
router.refresh();
}
}

View File

@@ -54,7 +54,6 @@ type LoginFormProps = {
idps?: LoginFormIDP[];
orgId?: string;
forceLogin?: boolean;
defaultEmail?: string;
};
export default function LoginForm({
@@ -62,8 +61,7 @@ export default function LoginForm({
onLogin,
idps,
orgId,
forceLogin,
defaultEmail
forceLogin
}: LoginFormProps) {
const router = useRouter();
@@ -118,7 +116,7 @@ export default function LoginForm({
const form = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
email: defaultEmail ?? "",
email: "",
password: ""
}
});

View File

@@ -1,6 +1,6 @@
"use client";
import { useEffect, useRef, useState } from "react";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
@@ -42,7 +42,6 @@ const isValidEmail = (str: string): boolean => {
type SmartLoginFormProps = {
redirect?: string;
forceLogin?: boolean;
defaultUser?: string;
};
type ViewState =
@@ -60,8 +59,7 @@ type ViewState =
export default function SmartLoginForm({
redirect,
forceLogin,
defaultUser
forceLogin
}: SmartLoginFormProps) {
const router = useRouter();
const { lookup, loading, error } = useUserLookup();
@@ -74,18 +72,10 @@ export default function SmartLoginForm({
const form = useForm<z.infer<typeof identifierSchema>>({
resolver: zodResolver(identifierSchema),
defaultValues: {
identifier: defaultUser ?? ""
identifier: ""
}
});
const hasAutoLookedUp = useRef(false);
useEffect(() => {
if (defaultUser?.trim() && !hasAutoLookedUp.current) {
hasAutoLookedUp.current = true;
void handleLookup({ identifier: defaultUser.trim() });
}
}, [defaultUser]);
const handleLookup = async (values: z.infer<typeof identifierSchema>) => {
const identifier = values.identifier.trim();
const isEmail = isValidEmail(identifier);