fix: waf page

This commit is contained in:
naiba
2024-11-30 21:31:55 +08:00
parent 7463bbe3a6
commit 3dc6da8ea9
9 changed files with 52 additions and 23 deletions

View File

@@ -1,10 +1,10 @@
import { ModelWAF } from "@/types" import { ModelWAFApiMock } from "@/types"
import { fetcher, FetcherMethod } from "./api" import { fetcher, FetcherMethod } from "./api"
export const deleteWAF = async (ip: string[]): Promise<void> => { export const deleteWAF = async (ip: string[]): Promise<void> => {
return fetcher<void>(FetcherMethod.POST, '/api/v1/batch-delete/waf', ip); return fetcher<void>(FetcherMethod.POST, '/api/v1/batch-delete/waf', ip);
} }
export const getWAFList = async (): Promise<ModelWAF[]> => { export const getWAFList = async (): Promise<ModelWAFApiMock[]> => {
return fetcher<ModelWAF[]>(FetcherMethod.GET, '/api/v1/waf', null); return fetcher<ModelWAFApiMock[]>(FetcherMethod.GET, '/api/v1/waf', null);
} }

View File

@@ -141,8 +141,18 @@ export function joinIP(p?: ModelIP) {
return ''; return '';
} }
export function ip16Str(p: number[]) { function base64toUint8Array(base64str: string) {
const buf = new Uint8Array(p); const binary = atob(base64str);
const len = binary.length;
const buf = new Uint8Array(len);
for (let i = 0; i < len; i++) {
buf[i] = binary.charCodeAt(i);
}
return buf;
}
export function ip16Str(base64str: string) {
const buf = base64toUint8Array(base64str);
const ip4 = buf.slice(-6); const ip4 = buf.slice(-6);
if (ip4[0] === 255 && ip4[1] === 255) { if (ip4[0] === 255 && ip4[1] === 255) {
return ip4.slice(2).join('.'); return ip4.slice(2).join('.');

View File

@@ -134,6 +134,7 @@
"CustomCodesDashboard": "Custom Codes for Dashboard", "CustomCodesDashboard": "Custom Codes for Dashboard",
"CustomPublicDNSNameserversforDDNS": "Custom Public DNS Nameservers for DDNS", "CustomPublicDNSNameserversforDDNS": "Custom Public DNS Nameservers for DDNS",
"RealIPHeader": "Real IP request header", "RealIPHeader": "Real IP request header",
"UseDirectConnectingIP": "Use direct connection IP",
"IPChangeNotification": "IP Change notification", "IPChangeNotification": "IP Change notification",
"FullIPNotification": "Show Full IP Address in Notification Messages", "FullIPNotification": "Show Full IP Address in Notification Messages",
"EditService": "Editing services", "EditService": "Editing services",

View File

@@ -141,6 +141,7 @@
"DashboardOriginalHost": "Nome di dominio/IP del server Dashboard (no CDN)", "DashboardOriginalHost": "Nome di dominio/IP del server Dashboard (no CDN)",
"CustomPublicDNSNameserversforDDNS": "Server dei nomi DNS pubblici personalizzati per DDNS", "CustomPublicDNSNameserversforDDNS": "Server dei nomi DNS pubblici personalizzati per DDNS",
"RealIPHeader": "Intestazione della richiesta IP reale", "RealIPHeader": "Intestazione della richiesta IP reale",
"UseDirectConnectingIP": "Utilizzare l'IP di connessione diretta",
"IPChangeNotification": "Notifica di modifica IP", "IPChangeNotification": "Notifica di modifica IP",
"FullIPNotification": "Mostra l'indirizzo IP completo nei messaggi di notifica", "FullIPNotification": "Mostra l'indirizzo IP completo nei messaggi di notifica",
"LoginFailed": "Accesso non riuscito", "LoginFailed": "Accesso non riuscito",

View File

@@ -140,6 +140,7 @@
"DashboardOriginalHost": "仪表板服务器域名/IP无 CDN", "DashboardOriginalHost": "仪表板服务器域名/IP无 CDN",
"CustomPublicDNSNameserversforDDNS": "DDNS 的自定义公共 DNS 名称服务器", "CustomPublicDNSNameserversforDDNS": "DDNS 的自定义公共 DNS 名称服务器",
"RealIPHeader": "真实IP请求头", "RealIPHeader": "真实IP请求头",
"UseDirectConnectingIP": "使用直连 IP",
"IPChangeNotification": "IP变更通知", "IPChangeNotification": "IP变更通知",
"FullIPNotification": "在通知消息中显示完整的 IP 地址", "FullIPNotification": "在通知消息中显示完整的 IP 地址",
"LoginFailed": "登录失败", "LoginFailed": "登录失败",

View File

@@ -140,6 +140,7 @@
"DashboardOriginalHost": "儀表板伺服器網域/IP無 CDN", "DashboardOriginalHost": "儀表板伺服器網域/IP無 CDN",
"CustomPublicDNSNameserversforDDNS": "DDNS 的自訂公共 DNS 名稱伺服器", "CustomPublicDNSNameserversforDDNS": "DDNS 的自訂公共 DNS 名稱伺服器",
"RealIPHeader": "真實IP請求頭", "RealIPHeader": "真實IP請求頭",
"UseDirectConnectingIP": "使用直連 IP",
"IPChangeNotification": "IP變更通知", "IPChangeNotification": "IP變更通知",
"FullIPNotification": "在通知訊息中顯示完整的 IP 位址", "FullIPNotification": "在通知訊息中顯示完整的 IP 位址",
"LoginFailed": "登入失敗", "LoginFailed": "登入失敗",

View File

@@ -220,7 +220,21 @@ export default function SettingsPage() {
<FormItem> <FormItem>
<FormLabel>{t("RealIPHeader")}</FormLabel> <FormLabel>{t("RealIPHeader")}</FormLabel>
<FormControl> <FormControl>
<Input placeholder="NZ::Use-Peer-IP" {...field} /> <div className="flex items-center">
<Input disabled={field.value == 'NZ::Use-Peer-IP'} className="w-1/2" placeholder="CF-Connecting-IP" {...field} />
<Checkbox checked={field.value == 'NZ::Use-Peer-IP'} className="ml-2" onCheckedChange={(checked) => {
if (checked) {
field.disabled = true;
form.setValue("real_ip_header", "NZ::Use-Peer-IP");
} else {
field.disabled = false;
form.setValue("real_ip_header", "");
}
}} />
<FormLabel className="font-normal ml-2">
{t("UseDirectConnectingIP")}
</FormLabel>
</div>
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>

View File

@@ -14,7 +14,7 @@ import { useEffect, useMemo } from "react";
import { ActionButtonGroup } from "@/components/action-button-group"; import { ActionButtonGroup } from "@/components/action-button-group";
import { HeaderButtonGroup } from "@/components/header-button-group"; import { HeaderButtonGroup } from "@/components/header-button-group";
import { toast } from "sonner"; import { toast } from "sonner";
import { ModelWAF, wafBlockReasons } from "@/types"; import { ModelWAFApiMock, wafBlockReasons } from "@/types";
import { deleteWAF } from "@/api/waf"; import { deleteWAF } from "@/api/waf";
import { ip16Str } from "@/lib/utils"; import { ip16Str } from "@/lib/utils";
import { SettingsTab } from "@/components/settings-tab"; import { SettingsTab } from "@/components/settings-tab";
@@ -23,7 +23,7 @@ import { useTranslation } from "react-i18next";
export default function WAFPage() { export default function WAFPage() {
const { t } = useTranslation(); const { t } = useTranslation();
const { data, mutate, error, isLoading } = useSWR<ModelWAF[]>("/api/v1/waf", swrFetcher); const { data, mutate, error, isLoading } = useSWR<ModelWAFApiMock[]>("/api/v1/waf", swrFetcher);
useEffect(() => { useEffect(() => {
if (error) if (error)
@@ -33,7 +33,7 @@ export default function WAFPage() {
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [error]); }, [error]);
const columns: ColumnDef<ModelWAF>[] = [ const columns: ColumnDef<ModelWAFApiMock>[] = [
{ {
id: "select", id: "select",
header: ({ table }) => ( header: ({ table }) => (
@@ -59,7 +59,7 @@ export default function WAFPage() {
{ {
header: "IP", header: "IP",
accessorKey: "ip", accessorKey: "ip",
accessorFn: (row) => ip16Str(row.ip ?? []), accessorFn: (row) => ip16Str(row.ip ?? ""),
}, },
{ {
header: t("Count"), header: t("Count"),
@@ -78,7 +78,7 @@ export default function WAFPage() {
accessorFn: (row) => row.last_block_timestamp, accessorFn: (row) => row.last_block_timestamp,
cell: ({ row }) => { cell: ({ row }) => {
const s = row.original; const s = row.original;
const date = new Date(s.last_block_timestamp || 0); const date = new Date((s.last_block_timestamp || 0)*1000);
return <span>{date.toISOString()}</span>; return <span>{date.toISOString()}</span>;
}, },
}, },
@@ -92,7 +92,7 @@ export default function WAFPage() {
className="flex gap-2" className="flex gap-2"
delete={{ delete={{
fn: deleteWAF, fn: deleteWAF,
id: ip16Str(s.ip ?? []), id: ip16Str(s.ip ?? ""),
mutate: mutate, mutate: mutate,
}} }}
> >
@@ -123,7 +123,7 @@ export default function WAFPage() {
className="flex-2 flex gap-2 ml-auto" className="flex-2 flex gap-2 ml-auto"
delete={{ delete={{
fn: deleteWAF, fn: deleteWAF,
id: selectedRows.map((r) => ip16Str(r.original.ip ?? [])), id: selectedRows.map((r) => ip16Str(r.original.ip ?? "")),
mutate: mutate, mutate: mutate,
}} }}
> >

View File

@@ -75,8 +75,8 @@ export interface GithubComNezhahqNezhaModelCommonResponseArrayModelUser {
success?: boolean; success?: boolean;
} }
export interface GithubComNezhahqNezhaModelCommonResponseArrayModelWAF { export interface GithubComNezhahqNezhaModelCommonResponseArrayModelWAFApiMock {
data?: ModelWAF[]; data?: ModelWAFApiMock[];
error?: string; error?: string;
success?: boolean; success?: boolean;
} }
@@ -425,6 +425,7 @@ export interface ModelProfile {
export interface ModelProfileForm { export interface ModelProfileForm {
new_password?: string; new_password?: string;
new_username?: string;
original_password?: string; original_password?: string;
} }
@@ -647,9 +648,9 @@ export interface ModelUserForm {
username?: string; username?: string;
} }
export interface ModelWAF { export interface ModelWAFApiMock {
count?: number; count?: number;
ip?: number[]; ip?: string;
last_block_reason?: number; last_block_reason?: number;
last_block_timestamp?: number; last_block_timestamp?: number;
} }