+
- Your password has been successfully reset
+ Password Reset Confirmation
Hi {email || "there"},
@@ -46,12 +56,10 @@ export const ConfirmPasswordReset = ({ email }: Props) => {
reset. If you made this change, no further action is
required.
-
-
- If you did not request this change, please
- contact our support team immediately.
-
-
+
+ If you did not request this change, please contact
+ our support team immediately.
+
Thank you for keeping your account secure.
diff --git a/server/emails/templates/ResetPasswordCode.tsx b/server/emails/templates/ResetPasswordCode.tsx
index eb2ec7fb..e0171189 100644
--- a/server/emails/templates/ResetPasswordCode.tsx
+++ b/server/emails/templates/ResetPasswordCode.tsx
@@ -37,8 +37,18 @@ export const ResetPasswordCode = ({ email, code, link }: Props) => {
>
+
+
+ Pangolin
+
+
+
+ {new Date().toLocaleDateString()}
+
+
+
- You've requested to reset your password
+ Password Reset Request
Hi {email || "there"},
@@ -51,7 +61,7 @@ export const ResetPasswordCode = ({ email, code, link }: Props) => {
and follow the instructions to reset your password,
or manually enter the following code:
-
+
{code}
diff --git a/server/emails/templates/ResourceOTPCode.tsx b/server/emails/templates/ResourceOTPCode.tsx
index 7744400c..32a1fd5d 100644
--- a/server/emails/templates/ResourceOTPCode.tsx
+++ b/server/emails/templates/ResourceOTPCode.tsx
@@ -43,6 +43,16 @@ export const ResourceOTPCode = ({
>
+
+
+ Pangolin
+
+
+
+ {new Date().toLocaleDateString()}
+
+
+
Your One-Time Password
@@ -56,12 +66,11 @@ export const ResourceOTPCode = ({
{organizationName}. Use the OTP
below to complete your authentication:
-
+
{otp}
-
Best regards,
diff --git a/server/emails/templates/SendInviteLink.tsx b/server/emails/templates/SendInviteLink.tsx
index 85ec5ec0..ba454386 100644
--- a/server/emails/templates/SendInviteLink.tsx
+++ b/server/emails/templates/SendInviteLink.tsx
@@ -46,8 +46,18 @@ export const SendInviteLink = ({
>
+
+
Two-Factor Authentication{" "}
{enabled ? "Enabled" : "Disabled"}
@@ -48,22 +58,19 @@ export const TwoFactorAuthNotification = ({ email, enabled }: Props) => {
has been successfully{" "}
{enabled ? "enabled" : "disabled"} on your account.
-
- {enabled ? (
-
- With Two-Factor Authentication enabled, your
- account is now more secure. Please ensure
- you keep your authentication method safe.
-
- ) : (
-
- With Two-Factor Authentication disabled,
- your account may be less secure. We
- recommend enabling it to protect your
- account.
-
- )}
-
+ {enabled ? (
+
+ With Two-Factor Authentication enabled, your
+ account is now more secure. Please ensure you
+ keep your authentication method safe.
+
+ ) : (
+
+ With Two-Factor Authentication disabled, your
+ account may be less secure. We recommend
+ enabling it to protect your account.
+
+ )}
If you did not make this change, please contact our
support team immediately.
diff --git a/server/emails/templates/VerifyEmailCode.tsx b/server/emails/templates/VerifyEmailCode.tsx
index 9adab19b..efd5acfb 100644
--- a/server/emails/templates/VerifyEmailCode.tsx
+++ b/server/emails/templates/VerifyEmailCode.tsx
@@ -41,17 +41,28 @@ export const VerifyEmail = ({
>
+
+
+ Pangolin
+
+
+
+ {new Date().toLocaleDateString()}
+
+
+
- Please verify your email
+ Please Verify Your Email
Hi {username || "there"},
You’ve requested to verify your email. Please use
- the code below to complete the verification process upon logging in.
+ the code below to complete the verification process
+ upon logging in.
-
+
{verificationCode}
diff --git a/server/routers/site/createSite.ts b/server/routers/site/createSite.ts
index 73ecb490..417dcf26 100644
--- a/server/routers/site/createSite.ts
+++ b/server/routers/site/createSite.ts
@@ -25,7 +25,12 @@ const createSiteSchema = z
.object({
name: z.string().min(1).max(255),
exitNodeId: z.number().int().positive(),
- subdomain: z.string().min(1).max(255).optional(),
+ // subdomain: z
+ // .string()
+ // .min(1)
+ // .max(255)
+ // .transform((val) => val.toLowerCase())
+ // .optional(),
pubKey: z.string().optional(),
subnet: z.string(),
newtId: z.string().optional(),
diff --git a/server/routers/site/getSite.ts b/server/routers/site/getSite.ts
index 5bc25e09..fd19b30b 100644
--- a/server/routers/site/getSite.ts
+++ b/server/routers/site/getSite.ts
@@ -23,13 +23,25 @@ const getSiteSchema = z
})
.strict();
-export type GetSiteResponse = {
- siteId: number;
- name: string;
- subdomain: string;
- subnet: string;
- type: string;
-};
+async function query(siteId?: number, niceId?: string, orgId?: string) {
+ if (siteId) {
+ const [res] = await db
+ .select()
+ .from(sites)
+ .where(eq(sites.siteId, siteId))
+ .limit(1);
+ return res;
+ } else if (niceId && orgId) {
+ const [res] = await db
+ .select()
+ .from(sites)
+ .where(and(eq(sites.niceId, niceId), eq(sites.orgId, orgId)))
+ .limit(1);
+ return res;
+ }
+}
+
+export type GetSiteResponse = NonNullable>>;
export async function getSite(
req: Request,
@@ -49,42 +61,14 @@ export async function getSite(
const { siteId, niceId, orgId } = parsedParams.data;
- let site;
- if (siteId) {
- site = await db
- .select()
- .from(sites)
- .where(eq(sites.siteId, siteId))
- .limit(1);
- } else if (niceId && orgId) {
- site = await db
- .select()
- .from(sites)
- .where(and(eq(sites.niceId, niceId), eq(sites.orgId, orgId)))
- .limit(1);
- }
+ const site = await query(siteId, niceId, orgId);
if (!site) {
return next(createHttpError(HttpCode.NOT_FOUND, "Site not found"));
}
- if (site.length === 0) {
- return next(
- createHttpError(
- HttpCode.NOT_FOUND,
- `Site with ID ${siteId} not found`
- )
- );
- }
-
- return response(res, {
- data: {
- siteId: site[0].siteId,
- niceId: site[0].niceId,
- name: site[0].name,
- subnet: site[0].subnet,
- type: site[0].type
- },
+ return response(res, {
+ data: site,
success: true,
error: false,
message: "Site retrieved successfully",
diff --git a/server/routers/site/updateSite.ts b/server/routers/site/updateSite.ts
index 41e764a5..5fc39e69 100644
--- a/server/routers/site/updateSite.ts
+++ b/server/routers/site/updateSite.ts
@@ -18,7 +18,12 @@ const updateSiteParamsSchema = z
const updateSiteBodySchema = z
.object({
name: z.string().min(1).max(255).optional(),
- subdomain: z.string().min(1).max(255).optional()
+ // subdomain: z
+ // .string()
+ // .min(1)
+ // .max(255)
+ // .transform((val) => val.toLowerCase())
+ // .optional()
// pubKey: z.string().optional(),
// subnet: z.string().optional(),
// exitNode: z.number().int().positive().optional(),
diff --git a/server/schemas/subdomainSchema.ts b/server/schemas/subdomainSchema.ts
index 4f761f4a..30ba2ddd 100644
--- a/server/schemas/subdomainSchema.ts
+++ b/server/schemas/subdomainSchema.ts
@@ -6,4 +6,5 @@ export const subdomainSchema = z
/^(?!:\/\/)([a-zA-Z0-9-_]+\.)*[a-zA-Z0-9-_]+$/,
"Invalid subdomain format"
)
- .min(1, "Subdomain must be at least 1 character long");
+ .min(1, "Subdomain must be at least 1 character long")
+ .transform((val) => val.toLowerCase());
diff --git a/src/app/[orgId]/settings/access/roles/page.tsx b/src/app/[orgId]/settings/access/roles/page.tsx
index 6e0b6783..1555a5d0 100644
--- a/src/app/[orgId]/settings/access/roles/page.tsx
+++ b/src/app/[orgId]/settings/access/roles/page.tsx
@@ -13,6 +13,8 @@ type RolesPageProps = {
params: Promise<{ orgId: string }>;
};
+export const dynamic = "force-dynamic";
+
export default async function RolesPage(props: RolesPageProps) {
const params = await props.params;
diff --git a/src/app/[orgId]/settings/access/users/[userId]/layout.tsx b/src/app/[orgId]/settings/access/users/[userId]/layout.tsx
index 5568abd3..d7f792f4 100644
--- a/src/app/[orgId]/settings/access/users/[userId]/layout.tsx
+++ b/src/app/[orgId]/settings/access/users/[userId]/layout.tsx
@@ -11,9 +11,10 @@ import {
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
- BreadcrumbSeparator,
+ BreadcrumbSeparator
} from "@/components/ui/breadcrumb";
import Link from "next/link";
+import { cache } from "react";
interface UserLayoutProps {
children: React.ReactNode;
@@ -27,10 +28,13 @@ export default async function UserLayoutProps(props: UserLayoutProps) {
let user = null;
try {
- const res = await internal.get>(
- `/org/${params.orgId}/user/${params.userId}`,
- await authCookieHeader(),
+ const getOrgUser = cache(async () =>
+ internal.get>(
+ `/org/${params.orgId}/user/${params.userId}`,
+ await authCookieHeader()
+ )
);
+ const res = await getOrgUser();
user = res.data.data;
} catch {
redirect(`/${params.orgId}/settings/sites`);
@@ -39,8 +43,8 @@ export default async function UserLayoutProps(props: UserLayoutProps) {
const sidebarNavItems = [
{
title: "Access Controls",
- href: "/{orgId}/settings/access/users/{userId}/access-controls",
- },
+ href: "/{orgId}/settings/access/users/{userId}/access-controls"
+ }
];
return (
diff --git a/src/app/[orgId]/settings/access/users/page.tsx b/src/app/[orgId]/settings/access/users/page.tsx
index 37354c91..d6f3d993 100644
--- a/src/app/[orgId]/settings/access/users/page.tsx
+++ b/src/app/[orgId]/settings/access/users/page.tsx
@@ -15,6 +15,8 @@ type UsersPageProps = {
params: Promise<{ orgId: string }>;
};
+export const dynamic = "force-dynamic";
+
export default async function UsersPage(props: UsersPageProps) {
const params = await props.params;
diff --git a/src/app/[orgId]/settings/resources/[resourceId]/authentication/page.tsx b/src/app/[orgId]/settings/resources/[resourceId]/authentication/page.tsx
index a3310a46..a1d2c5bc 100644
--- a/src/app/[orgId]/settings/resources/[resourceId]/authentication/page.tsx
+++ b/src/app/[orgId]/settings/resources/[resourceId]/authentication/page.tsx
@@ -382,8 +382,8 @@ export default function ResourceAuthenticationPage() {
/>
)}
-