mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-19 08:48:34 +02:00
Update libraries to resolve critical security findings
This commit is contained in:
parent
787a172a7c
commit
7fd1652a71
5 changed files with 1061 additions and 1513 deletions
2472
package-lock.json
generated
2472
package-lock.json
generated
File diff suppressed because it is too large
Load diff
19
package.json
19
package.json
|
@ -40,12 +40,13 @@
|
||||||
"@radix-ui/react-switch": "1.1.2",
|
"@radix-ui/react-switch": "1.1.2",
|
||||||
"@radix-ui/react-tabs": "1.1.2",
|
"@radix-ui/react-tabs": "1.1.2",
|
||||||
"@radix-ui/react-toast": "1.2.4",
|
"@radix-ui/react-toast": "1.2.4",
|
||||||
"@react-email/components": "0.0.31",
|
"@react-email/components": "0.0.36",
|
||||||
|
"@react-email/render": "^1.0.6",
|
||||||
"@react-email/tailwind": "1.0.4",
|
"@react-email/tailwind": "1.0.4",
|
||||||
"@tanstack/react-table": "8.20.6",
|
"@tanstack/react-table": "8.20.6",
|
||||||
"axios": "1.7.9",
|
"axios": "1.8.4",
|
||||||
"better-sqlite3": "11.7.0",
|
"better-sqlite3": "11.7.0",
|
||||||
"canvas-confetti": "^1.9.3",
|
"canvas-confetti": "1.9.3",
|
||||||
"class-variance-authority": "0.7.1",
|
"class-variance-authority": "0.7.1",
|
||||||
"clsx": "2.1.1",
|
"clsx": "2.1.1",
|
||||||
"cmdk": "1.0.4",
|
"cmdk": "1.0.4",
|
||||||
|
@ -64,7 +65,7 @@
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"lucide-react": "0.469.0",
|
"lucide-react": "0.469.0",
|
||||||
"moment": "2.30.1",
|
"moment": "2.30.1",
|
||||||
"next": "15.1.3",
|
"next": "15.2.4",
|
||||||
"next-themes": "0.4.4",
|
"next-themes": "0.4.4",
|
||||||
"node-cache": "5.1.2",
|
"node-cache": "5.1.2",
|
||||||
"node-fetch": "3.3.2",
|
"node-fetch": "3.3.2",
|
||||||
|
@ -105,14 +106,14 @@
|
||||||
"@types/swagger-ui-express": "^4.1.8",
|
"@types/swagger-ui-express": "^4.1.8",
|
||||||
"@types/ws": "8.5.13",
|
"@types/ws": "8.5.13",
|
||||||
"@types/yargs": "17.0.33",
|
"@types/yargs": "17.0.33",
|
||||||
"drizzle-kit": "0.30.1",
|
"drizzle-kit": "0.30.6",
|
||||||
"esbuild": "0.24.2",
|
"esbuild": "0.25.2",
|
||||||
"esbuild-node-externals": "1.16.0",
|
"esbuild-node-externals": "1.18.0",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"react-email": "3.0.4",
|
"react-email": "4.0.5",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"tsc-alias": "1.8.10",
|
"tsc-alias": "1.8.10",
|
||||||
"tsx": "4.19.2",
|
"tsx": "4.19.3",
|
||||||
"typescript": "^5",
|
"typescript": "^5",
|
||||||
"yargs": "17.7.2"
|
"yargs": "17.7.2"
|
||||||
},
|
},
|
||||||
|
|
|
@ -62,13 +62,11 @@ const createSiteFormSchema = z
|
||||||
.object({
|
.object({
|
||||||
name: z
|
name: z
|
||||||
.string()
|
.string()
|
||||||
.min(2, {
|
.min(2, { message: "Name must be at least 2 characters." })
|
||||||
message: "Name must be at least 2 characters."
|
|
||||||
})
|
|
||||||
.max(30, {
|
.max(30, {
|
||||||
message: "Name must not be longer than 30 characters."
|
message: "Name must not be longer than 30 characters."
|
||||||
}),
|
}),
|
||||||
method: z.string(),
|
method: z.enum(["newt", "wireguard", "local"]),
|
||||||
copied: z.boolean()
|
copied: z.boolean()
|
||||||
})
|
})
|
||||||
.refine(
|
.refine(
|
||||||
|
@ -86,6 +84,15 @@ const createSiteFormSchema = z
|
||||||
|
|
||||||
type CreateSiteFormValues = z.infer<typeof createSiteFormSchema>;
|
type CreateSiteFormValues = z.infer<typeof createSiteFormSchema>;
|
||||||
|
|
||||||
|
type SiteType = "newt" | "wireguard" | "local";
|
||||||
|
|
||||||
|
interface TunnelTypeOption {
|
||||||
|
id: SiteType;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
type Commands = {
|
type Commands = {
|
||||||
mac: Record<string, string[]>;
|
mac: Record<string, string[]>;
|
||||||
linux: Record<string, string[]>;
|
linux: Record<string, string[]>;
|
||||||
|
@ -99,7 +106,9 @@ export default function Page() {
|
||||||
const { orgId } = useParams();
|
const { orgId } = useParams();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const [tunnelTypes, setTunnelTypes] = useState<any>([
|
const [tunnelTypes, setTunnelTypes] = useState<
|
||||||
|
ReadonlyArray<TunnelTypeOption>
|
||||||
|
>([
|
||||||
{
|
{
|
||||||
id: "newt",
|
id: "newt",
|
||||||
title: "Newt Tunnel (Recommended)",
|
title: "Newt Tunnel (Recommended)",
|
||||||
|
@ -310,22 +319,15 @@ PersistentKeepalive = 5`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm<CreateSiteFormValues>({
|
||||||
resolver: zodResolver(createSiteFormSchema),
|
resolver: zodResolver(createSiteFormSchema),
|
||||||
defaultValues: {
|
defaultValues: { name: "", copied: false, method: "newt" }
|
||||||
name: "",
|
|
||||||
copied: false,
|
|
||||||
method: "newt"
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function onSubmit(data: CreateSiteFormValues) {
|
async function onSubmit(data: CreateSiteFormValues) {
|
||||||
setCreateLoading(true);
|
setCreateLoading(true);
|
||||||
|
|
||||||
let payload: CreateSiteBody = {
|
let payload: CreateSiteBody = { name: data.name, type: data.method };
|
||||||
name: data.name,
|
|
||||||
type: data.method
|
|
||||||
};
|
|
||||||
|
|
||||||
if (data.method == "wireguard") {
|
if (data.method == "wireguard") {
|
||||||
if (!siteDefaults || !wgConfig) {
|
if (!siteDefaults || !wgConfig) {
|
||||||
|
@ -454,10 +456,7 @@ PersistentKeepalive = 5`;
|
||||||
|
|
||||||
setTunnelTypes((prev: any) => {
|
setTunnelTypes((prev: any) => {
|
||||||
return prev.map((item: any) => {
|
return prev.map((item: any) => {
|
||||||
return {
|
return { ...item, disabled: false };
|
||||||
...item,
|
|
||||||
disabled: false
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -532,9 +531,8 @@ PersistentKeepalive = 5`;
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
This is the
|
This is the display
|
||||||
display name for the
|
name for the site.
|
||||||
site.
|
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
|
@ -558,12 +556,10 @@ PersistentKeepalive = 5`;
|
||||||
<SettingsSectionBody>
|
<SettingsSectionBody>
|
||||||
<StrategySelect
|
<StrategySelect
|
||||||
options={tunnelTypes}
|
options={tunnelTypes}
|
||||||
defaultValue={
|
defaultValue={form.getValues("method")}
|
||||||
form.getValues("method") as string
|
onChange={(value) => {
|
||||||
}
|
form.setValue("method", value);
|
||||||
onChange={(value) =>
|
}}
|
||||||
form.setValue("method", value)
|
|
||||||
}
|
|
||||||
cols={3}
|
cols={3}
|
||||||
/>
|
/>
|
||||||
</SettingsSectionBody>
|
</SettingsSectionBody>
|
||||||
|
|
|
@ -38,7 +38,7 @@ export default function SupporterMessage({ tier }: { tier: string }) {
|
||||||
<path d="M12 .587l3.668 7.431 8.2 1.192-5.934 5.782 1.4 8.168L12 18.896l-7.334 3.864 1.4-8.168L.132 9.21l8.2-1.192z" />
|
<path d="M12 .587l3.668 7.431 8.2 1.192-5.934 5.782 1.4 8.168L12 18.896l-7.334 3.864 1.4-8.168L.132 9.21l8.2-1.192z" />
|
||||||
</svg>
|
</svg>
|
||||||
{/* Popover */}
|
{/* Popover */}
|
||||||
<div className="absolute left-1/2 transform -translate-x-1/2 -top-10 hidden group-hover:block bg-white/10 backdrop-blur-md text-primary text-sm rounded-md shadow-lg px-4 py-2">
|
<div className="absolute left-1/2 transform -translate-x-1/2 -top-10 hidden group-hover:block bg-white/10 text-primary text-sm rounded-md shadow-lg px-4 py-2 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity">
|
||||||
Thank you for supporting Pangolin as a {tier}!
|
Thank you for supporting Pangolin as a {tier}!
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,38 +4,39 @@ import { cn } from "@app/lib/cn";
|
||||||
import { RadioGroup, RadioGroupItem } from "./ui/radio-group";
|
import { RadioGroup, RadioGroupItem } from "./ui/radio-group";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
interface StrategyOption {
|
interface StrategyOption<TValue extends string> {
|
||||||
id: string;
|
id: TValue;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
disabled?: boolean; // New optional property
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StrategySelectProps {
|
interface StrategySelectProps<TValue extends string> {
|
||||||
options: StrategyOption[];
|
options: ReadonlyArray<StrategyOption<TValue>>;
|
||||||
defaultValue?: string;
|
defaultValue?: TValue;
|
||||||
onChange?: (value: string) => void;
|
onChange?: (value: TValue) => void;
|
||||||
cols?: number;
|
cols?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function StrategySelect({
|
export function StrategySelect<TValue extends string>({
|
||||||
options,
|
options,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
onChange,
|
onChange,
|
||||||
cols
|
cols
|
||||||
}: StrategySelectProps) {
|
}: StrategySelectProps<TValue>) {
|
||||||
const [selected, setSelected] = useState(defaultValue);
|
const [selected, setSelected] = useState<TValue | undefined>(defaultValue);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
defaultValue={defaultValue}
|
defaultValue={defaultValue}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value: string) => {
|
||||||
setSelected(value);
|
const typedValue = value as TValue;
|
||||||
onChange?.(value);
|
setSelected(typedValue);
|
||||||
|
onChange?.(typedValue);
|
||||||
}}
|
}}
|
||||||
className={`grid md:grid-cols-${cols ? cols : 1} gap-4`}
|
className={`grid md:grid-cols-${cols ? cols : 1} gap-4`}
|
||||||
>
|
>
|
||||||
{options.map((option) => (
|
{options.map((option: StrategyOption<TValue>) => (
|
||||||
<label
|
<label
|
||||||
key={option.id}
|
key={option.id}
|
||||||
htmlFor={option.id}
|
htmlFor={option.id}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue