Compare commits

..

3 Commits

Author SHA1 Message Date
miloschwartz
6e6fa77625 bump version 2025-12-04 17:10:59 -05:00
Owen
5c0c12cabe Update lock 2025-12-04 17:02:45 -05:00
miloschwartz
10a00ff225 update next version 2025-12-04 16:56:39 -05:00
9 changed files with 1816 additions and 1883 deletions

View File

@@ -238,6 +238,7 @@ func main() {
}
fmt.Println("CrowdSec installed successfully!")
return
}
}
}

3615
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -94,7 +94,7 @@
"lucide-react": "^0.552.0",
"maxmind": "5.0.0",
"moment": "2.30.1",
"next": "15.5.6",
"next": "15.5.7",
"next-intl": "^4.4.0",
"next-themes": "0.4.6",
"nextjs-toploader": "^3.9.17",

View File

@@ -79,12 +79,6 @@ export function createApiServer() {
// Add request timeout middleware
apiServer.use(requestTimeoutMiddleware(60000)); // 60 second timeout
apiServer.use(logIncomingMiddleware);
if (build !== "oss") {
apiServer.use(`${prefix}/hybrid`, hybridRouter); // put before rate limiting because we will rate limit there separately because some of the routes are heavily used
}
if (!dev) {
apiServer.use(
rateLimit({
@@ -107,7 +101,11 @@ export function createApiServer() {
}
// API routes
apiServer.use(logIncomingMiddleware);
apiServer.use(prefix, unauthenticated);
if (build !== "oss") {
apiServer.use(`${prefix}/hybrid`, hybridRouter);
}
apiServer.use(prefix, authenticated);
// WebSocket routes

View File

@@ -2,7 +2,7 @@ import path from "path";
import { fileURLToPath } from "url";
// This is a placeholder value replaced by the build process
export const APP_VERSION = "1.12.1";
export const APP_VERSION = "1.12.3";
export const __FILENAME = fileURLToPath(import.meta.url);
export const __DIRNAME = path.dirname(__FILENAME);

View File

@@ -72,38 +72,6 @@ export class RateLimitService {
return `ratelimit:${clientId}:${messageType}`;
}
// Helper function to clean up old timestamp fields from a Redis hash
private async cleanupOldTimestamps(key: string, windowStart: number): Promise<void> {
if (!redisManager.isRedisEnabled()) return;
try {
const client = redisManager.getClient();
if (!client) return;
// Get all fields in the hash
const allData = await redisManager.hgetall(key);
if (!allData || Object.keys(allData).length === 0) return;
// Find fields that are older than the window
const fieldsToDelete: string[] = [];
for (const timestamp of Object.keys(allData)) {
const time = parseInt(timestamp);
if (time < windowStart) {
fieldsToDelete.push(timestamp);
}
}
// Delete old fields in batch
if (fieldsToDelete.length > 0) {
await client.hdel(key, ...fieldsToDelete);
logger.debug(`Cleaned up ${fieldsToDelete.length} old timestamp fields from ${key}`);
}
} catch (error) {
logger.error(`Failed to cleanup old timestamps for key ${key}:`, error);
// Don't throw - cleanup failures shouldn't block rate limiting
}
}
// Helper function to sync local rate limit data to Redis
private async syncRateLimitToRedis(
clientId: string,
@@ -113,12 +81,8 @@ export class RateLimitService {
try {
const currentTime = Math.floor(Date.now() / 1000);
const windowStart = currentTime - RATE_LIMIT_WINDOW;
const globalKey = this.getRateLimitKey(clientId);
// Clean up old timestamp fields before writing
await this.cleanupOldTimestamps(globalKey, windowStart);
// Get current value and add pending count
const currentValue = await redisManager.hget(
globalKey,
@@ -129,7 +93,7 @@ export class RateLimitService {
).toString();
await redisManager.hset(globalKey, currentTime.toString(), newValue);
// Set TTL using the client directly - this prevents the key from persisting forever
// Set TTL using the client directly
if (redisManager.getClient()) {
await redisManager
.getClient()
@@ -155,12 +119,8 @@ export class RateLimitService {
try {
const currentTime = Math.floor(Date.now() / 1000);
const windowStart = currentTime - RATE_LIMIT_WINDOW;
const messageTypeKey = this.getMessageTypeRateLimitKey(clientId, messageType);
// Clean up old timestamp fields before writing
await this.cleanupOldTimestamps(messageTypeKey, windowStart);
// Get current value and add pending count
const currentValue = await redisManager.hget(
messageTypeKey,
@@ -175,7 +135,7 @@ export class RateLimitService {
newValue
);
// Set TTL using the client directly - this prevents the key from persisting forever
// Set TTL using the client directly
if (redisManager.getClient()) {
await redisManager
.getClient()
@@ -210,10 +170,6 @@ export class RateLimitService {
try {
const globalKey = this.getRateLimitKey(clientId);
// Clean up old timestamp fields before reading
await this.cleanupOldTimestamps(globalKey, windowStart);
const globalRateLimitData = await redisManager.hgetall(globalKey);
let count = 0;
@@ -259,10 +215,6 @@ export class RateLimitService {
try {
const messageTypeKey = this.getMessageTypeRateLimitKey(clientId, messageType);
// Clean up old timestamp fields before reading
await this.cleanupOldTimestamps(messageTypeKey, windowStart);
const messageTypeRateLimitData = await redisManager.hgetall(messageTypeKey);
let count = 0;

View File

@@ -227,8 +227,6 @@ export type UserSessionWithUser = {
export const hybridRouter = Router();
hybridRouter.use(verifySessionRemoteExitNodeMiddleware);
// TODO: ADD RATE LIMITING TO THESE ROUTES AS NEEDED BASED ON USAGE PATTERNS
hybridRouter.get(
"/general-config",
async (req: Request, res: Response, next: NextFunction) => {

View File

@@ -1,14 +1 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.
* You may not use this file except in compliance with the License.
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
*
* This file is not licensed under the AGPLv3.
*/
export * from "./sendSupportEmail";

View File

@@ -68,7 +68,7 @@ export async function sendSupportEmail(
{
name: req.user?.email || "Support User",
to: "support@pangolin.net",
from: config.getNoReplyEmail(),
from: req.user?.email || config.getNoReplyEmail(),
subject: `Support Request: ${subject}`
}
);