Compare commits

...

15 Commits

Author SHA1 Message Date
Owen Schwartz
ddabfb5ca1 Merge pull request #3154 from RitwijParmar/codex/pangolin-refresh-live-log-window
fix(logs): refresh default end time
2026-05-26 11:52:10 -07:00
Owen Schwartz
ec0666a612 Merge pull request #3151 from shleeable/patch-1
Installer: Handle both Maxmind Country and ASN databases.
2026-05-26 09:50:08 -07:00
Shlee
bbf42c5802 Update main.go 2026-05-26 17:14:06 +09:30
Ritwij Aryan Parmar
6aa1d3b094 fix(logs): refresh default end time 2026-05-26 01:26:53 -04:00
Shlee
f1ec1a2fb1 Update docker-compose.yml 2026-05-26 13:49:06 +09:30
Shlee
32fcf90467 Update docker-compose.yml 2026-05-26 13:48:00 +09:30
Shlee
5a53f88fd6 Update main.go 2026-05-26 13:37:28 +09:30
Shlee
51971c7ef2 Update config.yml 2026-05-26 13:36:01 +09:30
Shlee
491096109a Update main.go 2026-05-26 13:31:07 +09:30
Shlee
802a41b1bd Update main.go 2026-05-26 13:25:53 +09:30
Shlee
f59fbabede Update main.go 2026-05-26 13:12:48 +09:30
Shlee
5a7d54058e Update main.go 2026-05-26 13:06:35 +09:30
Owen Schwartz
5ef4490692 Merge pull request #3148 from bishnubista/fix-audit-log-replica-routing
fix(audit-logs): route request audit log reads through logsDb
2026-05-25 12:02:24 -07:00
bishnubista
817e848d08 fix(audit-logs): route request audit log reads through logsDb
Route the read paths in queryRequestAuditLog.ts and
queryRequestAnalytics.ts through `logsDb` instead of
`primaryLogsDb`, matching the existing private audit log routes
(queryActionAuditLog, queryAccessAuditLog, queryConnectionAuditLog
all already use `logsDb`). In PostgreSQL deployments configured
with a read replica via `withReplicas` (see server/db/pg/logsDriver.ts),
this keeps high-volume audit log reads off the primary. No-op
in OSS-SQLite where `logsDb === primaryDb`.

Investigated rewriting `queryUniqueFilterAttributes` per the
in-line TODO ("SOMEONE PLEASE OPTIMIZE THIS!!!!!"). A candidate
rewrite using UNION ALL with six GROUP BY...LIMIT 500 arms
benchmarked 48-61% slower than the current SELECT DISTINCT
LIMIT 501 approach on SQLite (100k/300k/1M rows, 20 runs each):
each grouped arm materializes a temp B-tree before applying LIMIT,
while DISTINCT short-circuits via hash dedup with early exit.
A materialized facets table is likely the right long-term fix,
not a query-shape rewrite.
2026-05-25 10:37:47 -07:00
Owen Schwartz
35ad235f49 Merge pull request #3129 from fosrl/fix-site-delete
Improve delete function speed & order of ops
2026-05-21 12:06:18 -07:00
8 changed files with 78 additions and 46 deletions

View File

@@ -22,7 +22,8 @@ server:
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
allowed_headers: ["X-CSRF-Token", "Content-Type"]
credentials: false
{{if .EnableGeoblocking}}maxmind_db_path: "./config/GeoLite2-Country.mmdb"{{end}}
{{if .EnableMaxMind}}maxmind_db_path: "./config/GeoLite2-Country.mmdb"{{end}}
{{if .EnableMaxMind}}maxmind_asn_path: "./config/GeoLite2-ASN.mmdb"{{end}}
{{if .EnableEmail}}
email:
smtp_host: "{{.EmailSMTPHost}}"

View File

@@ -54,7 +54,7 @@ type Config struct {
InstallGerbil bool
TraefikBouncerKey string
DoCrowdsecInstall bool
EnableGeoblocking bool
EnableMaxMind bool
Secret string
IsEnterprise bool
}
@@ -123,11 +123,11 @@ func main() {
fmt.Println("\nConfiguration files created successfully!")
// Download MaxMind database if requested
if config.EnableGeoblocking {
fmt.Println("\n=== Downloading MaxMind Database ===")
// Download MaxMind Country / ASN database if requested
if config.EnableMaxMind {
fmt.Println("\n=== Downloading MaxMind Country and ASN Databases ===")
if err := downloadMaxMindDatabase(); err != nil {
fmt.Printf("Error downloading MaxMind database: %v\n", err)
fmt.Printf("Error downloading MaxMind databases: %v\n", err)
fmt.Println("You can download it manually later if needed.")
}
}
@@ -188,15 +188,15 @@ func main() {
fmt.Println("\n=== MaxMind Database Update ===")
if _, err := os.Stat("config/GeoLite2-Country.mmdb"); err == nil {
fmt.Println("MaxMind GeoLite2 Country database found.")
if readBool("Would you like to update the MaxMind database to the latest version?", false) {
if readBool("Would you like to update the MaxMind databases (Country and ASN) to the latest version?", false) {
if err := downloadMaxMindDatabase(); err != nil {
fmt.Printf("Error updating MaxMind database: %v\n", err)
fmt.Println("You can try updating it manually later if needed.")
}
}
} else {
fmt.Println("MaxMind GeoLite2 Country database not found.")
if readBool("Would you like to download the MaxMind GeoLite2 database for geoblocking functionality?", false) {
fmt.Println("MaxMind GeoLite2 Country and ASN databases not found.")
if readBool("Would you like to download the MaxMind GeoLite2 databases for blocking functionality?", false) {
if err := downloadMaxMindDatabase(); err != nil {
fmt.Printf("Error downloading MaxMind database: %v\n", err)
fmt.Println("You can try downloading it manually later if needed.")
@@ -204,8 +204,10 @@ func main() {
// Now you need to update your config file accordingly to enable geoblocking
fmt.Print("Please remember to update your config/config.yml file to enable geoblocking! \n\n")
// add maxmind_db_path: "./config/GeoLite2-Country.mmdb" under server
fmt.Println("Add the following line under the 'server' section:")
// add maxmind_asn_path: "./config/GeoLite2-ASN.mmdb" under server
fmt.Println("Add the following lines under the 'server' section:")
fmt.Println(" maxmind_db_path: \"./config/GeoLite2-Country.mmdb\"")
fmt.Println(" maxmind_asn_path: \"./config/GeoLite2-ASN.mmdb\"")
}
}
}
@@ -527,7 +529,7 @@ func collectUserInput() Config {
fmt.Println("\n=== Advanced Configuration ===")
config.EnableIPv6 = readBool("Is your server IPv6 capable?", true)
config.EnableGeoblocking = readBool("Do you want to download the MaxMind GeoLite2 database for geoblocking functionality?", true)
config.EnableMaxMind = readBool("Do you want to download the MaxMind GeoLite2 Country and ADN databases for blocking functionality?", true)
if config.DashboardDomain == "" {
fmt.Println("Error: Dashboard Domain name is required")
@@ -780,29 +782,42 @@ func checkPortsAvailable(port int) error {
}
func downloadMaxMindDatabase() error {
fmt.Println("Downloading MaxMind GeoLite2 Country database...")
fmt.Println("Downloading MaxMind GeoLite2 Country and ASN databases...")
// Download the GeoLite2 Country database
// Download the GeoLite2 Country databases
if err := run("curl", "-L", "-o", "GeoLite2-Country.tar.gz",
"https://github.com/GitSquared/node-geolite2-redist/raw/refs/heads/master/redist/GeoLite2-Country.tar.gz"); err != nil {
return fmt.Errorf("failed to download GeoLite2 database: %v", err)
return fmt.Errorf("failed to download GeoLite2 Country database: %v", err)
}
if err := run("curl", "-L", "-o", "GeoLite2-ASN.tar.gz",
"https://github.com/GitSquared/node-geolite2-redist/raw/refs/heads/master/redist/GeoLite2-ASN.tar.gz"); err != nil {
return fmt.Errorf("failed to download GeoLite2 ASN database: %v", err)
}
// Extract the database
// Extract the Country database
if err := run("tar", "-xzf", "GeoLite2-Country.tar.gz"); err != nil {
return fmt.Errorf("failed to extract GeoLite2 database: %v", err)
return fmt.Errorf("failed to extract GeoLite2 Country database: %v", err)
}
if err := run("tar", "-xzf", "GeoLite2-ASN.tar.gz"); err != nil {
return fmt.Errorf("failed to extract GeoLite2 ASN database: %v", err)
}
// Find the .mmdb file and move it to the config directory
if err := run("bash", "-c", "mv GeoLite2-Country_*/GeoLite2-Country.mmdb config/"); err != nil {
return fmt.Errorf("failed to move GeoLite2 database to config directory: %v", err)
return fmt.Errorf("failed to move GeoLite2 Country database to config directory: %v", err)
}
if err := run("bash", "-c", "mv GeoLite2-ASN_*/GeoLite2-ASN.mmdb config/"); err != nil {
return fmt.Errorf("failed to move GeoLite2 ASN database to config directory: %v", err)
}
// Clean up the downloaded files
if err := run("rm", "-rf", "GeoLite2-Country.tar.gz", "GeoLite2-Country_*"); err != nil {
fmt.Printf("Warning: failed to clean up temporary files: %v\n", err)
if err := run("sh", "-c", "rm -rf GeoLite2-Country.tar.gz GeoLite2-Country_*"); err != nil {
fmt.Printf("Warning: failed to clean up temporary country files: %v\n", err)
}
if err := run("sh", "-c", "rm -rf GeoLite2-ASN.tar.gz GeoLite2-ASN_*"); err != nil {
fmt.Printf("Warning: failed to clean up temporary ASN files: %v\n", err)
}
fmt.Println("MaxMind GeoLite2 Country database downloaded successfully!")
fmt.Println("MaxMind GeoLite2 Country and ASN database downloaded successfully!")
return nil
}

View File

@@ -1,4 +1,4 @@
import { logsDb, requestAuditLog, driver, primaryLogsDb } from "@server/db";
import { logsDb, requestAuditLog, driver } from "@server/db";
import { registry } from "@server/openApi";
import { NextFunction } from "express";
import { Request, Response } from "express";
@@ -74,12 +74,12 @@ async function query(query: Q) {
);
}
const [all] = await primaryLogsDb
const [all] = await logsDb
.select({ total: count() })
.from(requestAuditLog)
.where(baseConditions);
const [blocked] = await primaryLogsDb
const [blocked] = await logsDb
.select({ total: count() })
.from(requestAuditLog)
.where(and(baseConditions, eq(requestAuditLog.action, false)));
@@ -90,7 +90,7 @@ async function query(query: Q) {
const DISTINCT_LIMIT = 500;
const requestsPerCountry = await primaryLogsDb
const requestsPerCountry = await logsDb
.selectDistinct({
code: requestAuditLog.location,
count: totalQ
@@ -118,7 +118,7 @@ async function query(query: Q) {
const booleanTrue = driver === "pg" ? sql`true` : sql`1`;
const booleanFalse = driver === "pg" ? sql`false` : sql`0`;
const requestsPerDay = await primaryLogsDb
const requestsPerDay = await logsDb
.select({
day: groupByDayFunction.as("day"),
allowedCount:

View File

@@ -1,4 +1,4 @@
import { logsDb, primaryLogsDb, requestAuditLog, resources, siteResources, db, primaryDb } from "@server/db";
import { logsDb, requestAuditLog, resources, siteResources, db, primaryDb } from "@server/db";
import { registry } from "@server/openApi";
import { NextFunction } from "express";
import { Request, Response } from "express";
@@ -110,7 +110,7 @@ function getWhere(data: Q) {
}
export function queryRequest(data: Q) {
return primaryLogsDb
return logsDb
.select({
id: requestAuditLog.id,
timestamp: requestAuditLog.timestamp,
@@ -211,7 +211,7 @@ async function enrichWithResourceDetails(logs: Awaited<ReturnType<typeof queryRe
}
export function countRequestQuery(data: Q) {
const countQuery = primaryLogsDb
const countQuery = logsDb
.select({ count: count() })
.from(requestAuditLog)
.where(getWhere(data));
@@ -254,34 +254,34 @@ async function queryUniqueFilterAttributes(
uniqueResources,
uniqueSiteResources
] = await Promise.all([
primaryLogsDb
logsDb
.selectDistinct({ actor: requestAuditLog.actor })
.from(requestAuditLog)
.where(baseConditions)
.limit(DISTINCT_LIMIT + 1),
primaryLogsDb
logsDb
.selectDistinct({ locations: requestAuditLog.location })
.from(requestAuditLog)
.where(baseConditions)
.limit(DISTINCT_LIMIT + 1),
primaryLogsDb
logsDb
.selectDistinct({ hosts: requestAuditLog.host })
.from(requestAuditLog)
.where(baseConditions)
.limit(DISTINCT_LIMIT + 1),
primaryLogsDb
logsDb
.selectDistinct({ paths: requestAuditLog.path })
.from(requestAuditLog)
.where(baseConditions)
.limit(DISTINCT_LIMIT + 1),
primaryLogsDb
logsDb
.selectDistinct({
id: requestAuditLog.resourceId
})
.from(requestAuditLog)
.where(baseConditions)
.limit(DISTINCT_LIMIT + 1),
primaryLogsDb
logsDb
.selectDistinct({
id: requestAuditLog.siteResourceId
})

View File

@@ -280,10 +280,14 @@ export default function GeneralPage() {
console.log("Data refreshed");
setIsRefreshing(true);
try {
const endDate = searchParams.get("end")
? dateRange.endDate
: { date: new Date() };
setDateRange((current) => ({ ...current, endDate }));
// Refresh data with current date range and pagination
await queryDateTime(
dateRange.startDate,
dateRange.endDate,
endDate,
currentPage,
pageSize
);

View File

@@ -266,10 +266,14 @@ export default function GeneralPage() {
console.log("Data refreshed");
setIsRefreshing(true);
try {
const endDate = searchParams.get("end")
? dateRange.endDate
: { date: new Date() };
setDateRange((current) => ({ ...current, endDate }));
// Refresh data with current date range and pagination
await queryDateTime(
dateRange.startDate,
dateRange.endDate,
endDate,
currentPage,
pageSize
);

View File

@@ -306,10 +306,14 @@ export default function ConnectionLogsPage() {
console.log("Data refreshed");
setIsRefreshing(true);
try {
const endDate = searchParams.get("end")
? dateRange.endDate
: { date: new Date() };
setDateRange((current) => ({ ...current, endDate }));
// Refresh data with current date range and pagination
await queryDateTime(
dateRange.startDate,
dateRange.endDate,
endDate,
currentPage,
pageSize
);

View File

@@ -281,10 +281,14 @@ export default function GeneralPage() {
console.log("Data refreshed");
setIsRefreshing(true);
try {
const endDate = searchParams.get("end")
? dateRange.endDate
: { date: new Date() };
setDateRange((current) => ({ ...current, endDate }));
// Refresh data with current date range and pagination
await queryDateTime(
dateRange.startDate,
dateRange.endDate,
endDate,
currentPage,
pageSize
);