From 0f1732fa712d47a06f2f4e7dadebe345e0122569 Mon Sep 17 00:00:00 2001 From: Edward Viaene Date: Thu, 5 Sep 2024 15:31:35 -0500 Subject: [PATCH] packetlogger UI --- pkg/rest/stats.go | 35 ++++- pkg/rest/stats_test.go | 11 ++ pkg/rest/types.go | 7 +- webapp/src/App.tsx | 8 +- webapp/src/Routes/PacketLogs/PacketLogs.tsx | 160 ++++++++++++++++++++ 5 files changed, 209 insertions(+), 12 deletions(-) create mode 100644 webapp/src/Routes/PacketLogs/PacketLogs.tsx diff --git a/pkg/rest/stats.go b/pkg/rest/stats.go index e387f0d..f024fd3 100644 --- a/pkg/rest/stats.go +++ b/pkg/rest/stats.go @@ -252,6 +252,9 @@ func (c *Context) packetLogsHandler(w http.ResponseWriter, r *http.Request) { for _, user := range users { userMap[user.ID] = user.Login } + // get filter + logTypeFilterQueryString := r.URL.Query().Get("logtype") + logTypeFilter := strings.Split(logTypeFilterQueryString, ",") // logs statsFiles := []string{ path.Join(wireguard.VPN_STATS_DIR, wireguard.VPN_PACKETLOGGER_DIR, userID+"-"+date.Format("2006-01-02")+".log"), @@ -292,11 +295,14 @@ func (c *Context) packetLogsHandler(w http.ResponseWriter, r *http.Request) { if err != nil { continue // invalid record } - row := LogRow{ - Timestamp: timestamp.Add(time.Duration(offset) * time.Minute), - Data: inputSplit[1:], + if !filterLogRecord(logTypeFilter, inputSplit[1]) { + row := LogRow{ + Timestamp: timestamp.Add(time.Duration(offset) * time.Minute), + Data: inputSplit[1:], + } + logData.Data = append(logData.Data, row) + } - logData.Data = append(logData.Data, row) } if err := scanner.Err(); err != nil { @@ -312,7 +318,7 @@ func (c *Context) packetLogsHandler(w http.ResponseWriter, r *http.Request) { } } - out, err := json.Marshal(LogDataResponse{Enabled: true, LogData: logData, LogTypes: packetLogTypes}) + out, err := json.Marshal(LogDataResponse{Enabled: true, LogData: logData, LogTypes: packetLogTypes, Users: userMap}) if err != nil { c.returnError(w, fmt.Errorf("user stats response marshal error: %s", err), http.StatusBadRequest) return @@ -351,3 +357,22 @@ func dateEqual(date1, date2 time.Time) bool { y2, m2, d2 := date2.Date() return y1 == y2 && m1 == m2 && d1 == d2 } + +func filterLogRecord(logTypeFilter []string, logType string) bool { + if len(logTypeFilter) > 0 && logTypeFilter[0] != "" { + for _, logTypeFilterItem := range logTypeFilter { + if logType == logTypeFilterItem { + return false + } + + splitLogTypes := strings.Split(logTypeFilterItem, "+") + for _, splitLogType := range splitLogTypes { + if splitLogType == logType { + return false + } + } + } + return true + } + return false +} diff --git a/pkg/rest/stats_test.go b/pkg/rest/stats_test.go index 447aa69..b7c2b2a 100644 --- a/pkg/rest/stats_test.go +++ b/pkg/rest/stats_test.go @@ -67,3 +67,14 @@ func TestUserStatsHandler(t *testing.T) { } } + +func TestFilterLogRecord(t *testing.T) { + logTypeFilter := []string{"tcp", "http+https"} + expected := []bool{false, false, true, false} + for k, v := range []string{"tcp", "http", "udp", "https"} { + res := filterLogRecord(logTypeFilter, v) + if res != expected[k] { + t.Fatalf("unexpected result: %v, got: %v", res, expected[k]) + } + } +} diff --git a/pkg/rest/types.go b/pkg/rest/types.go index 59b3e09..3ca6092 100644 --- a/pkg/rest/types.go +++ b/pkg/rest/types.go @@ -209,9 +209,10 @@ type NewUserRequest struct { } type LogDataResponse struct { - LogData LogData `json:"logData"` - Enabled bool `json:"enabled"` - LogTypes []string `json:"logTypes"` + LogData LogData `json:"logData"` + Enabled bool `json:"enabled"` + LogTypes []string `json:"logTypes"` + Users map[string]string `json:"users"` } type LogData struct { diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 3d7d19c..ecc98fa 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -18,7 +18,7 @@ import { Users } from "./Routes/Users/Users"; import { Profile } from "./Routes/Profile/Profile"; import { Upgrade } from "./Routes/Upgrade/Upgrade"; import { GetMoreLicenses } from "./Routes/Licenses/GetMoreLicenses"; -import { PacketLogs } from "./Routes/Logs/PacketLogs"; +import { PacketLogs } from "./Routes/PacketLogs/PacketLogs"; const queryClient = new QueryClient() @@ -47,14 +47,14 @@ export default function App() { } /> } /> } /> + } /> + } /> + } /> } /> } /> } /> } /> } /> - } /> - } /> - } /> diff --git a/webapp/src/Routes/PacketLogs/PacketLogs.tsx b/webapp/src/Routes/PacketLogs/PacketLogs.tsx new file mode 100644 index 0000000..7a2a38c --- /dev/null +++ b/webapp/src/Routes/PacketLogs/PacketLogs.tsx @@ -0,0 +1,160 @@ +import { Card, Container, Text, Table, Title, Button, Grid, Select, MultiSelect, Popover} from "@mantine/core"; +import { AppSettings } from "../../Constants/Constants"; +import { useQuery } from "@tanstack/react-query"; +import { useAuthContext } from "../../Auth/Auth"; +import { Link, useParams, useSearchParams } from "react-router-dom"; +import { TbSettings } from "react-icons/tb"; +import { DatePickerInput } from "@mantine/dates"; +import { useState } from "react"; + +type LogsDataResponse = { + enabled: boolean; + logData: LogData; + logTypes: string[]; + users: UserMap; +} +type LogData = { + schema: LogDataSchema; + rows: LogRow[]; +} +type LogDataSchema = { + columns: string[]; +} +type LogRow = { + t: string; + d: string[]; +} +type UserMap = { + [key: string]: string; +} + +export function PacketLogs() { + const {authInfo} = useAuthContext(); + const [currentQueryParameters, setSearchParams] = useSearchParams(); + const dateParam = currentQueryParameters.get("date") + const userParam = currentQueryParameters.get("user") + const [logType, setLogType] = useState([]) + const [logsDate, setLogsDate] = useState(dateParam === null ? new Date() : new Date(dateParam)); + const [user, setUser] = useState(userParam === null ? "all" : userParam) + const { isPending, error, data } = useQuery({ + queryKey: ['packetlogs', user, logsDate, logType], + queryFn: () => + fetch(AppSettings.url + '/stats/packetlogs/'+(user === undefined ? "all" : user)+'/'+(logsDate == undefined ? new Date().toISOString().slice(0, 10) : logsDate.toISOString().slice(0, 10)) + "?logtype="+encodeURIComponent(logType.join(",")), { + headers: { + "Content-Type": "application/json", + "Authorization": "Bearer " + authInfo.token + }, + }).then((res) => { + return res.json() + } + ), + }) + + if(isPending) return "Loading..." + if(error) return 'A backend error has occurred: ' + error.message + + if(!data.enabled || data.logTypes.length == 0) { // show disabled page if not enabled + return ( + + + Packet Logs + + + + { !data.enabled ? + "Packet Logs are not activated. Activate packet logging in the VPN Settings." + : + data.logTypes.length == 0 ? "Packet logs are activated, but no packet logging types are selected. Select at least one packet log type." : null + } + + + + + + + + + + ) + } + + const rows = data.logData.rows.map((row, i) => ( + + {row.t} + {row.d.map((element, y) => { + return ( + {element} + ) + })} + + )); + return ( + + + Packet Logs + + + + + + + +