Format and make ban-suspicious-ips more better

This commit is contained in:
2025-07-22 09:20:01 -05:00
parent 77c88ea9de
commit f071b6c19b
36 changed files with 716 additions and 444 deletions

View File

@@ -1,7 +1,8 @@
import { type NextRequest, NextResponse } from 'next/server';
// In-memory store for tracking IPs (use Redis in production)
// In-memory stores for tracking IPs (use Redis in production)
const ipAttempts = new Map<string, { count: number; lastAttempt: number }>();
const ip404Attempts = new Map<string, { count: number; lastAttempt: number }>();
const bannedIPs = new Set<string>();
// Ban Arctic Wolf Explicitly
@@ -9,6 +10,7 @@ bannedIPs.add('::ffff:10.0.1.49');
// Suspicious patterns that indicate malicious activity
const MALICIOUS_PATTERNS = [
// Your existing patterns
/web-inf/i,
/\.jsp/i,
/\.php/i,
@@ -28,6 +30,37 @@ const MALICIOUS_PATTERNS = [
/\.%00/i,
/\.\./,
/lcgi/i,
// New patterns from your logs
/\/appliance\//i,
/bomgar/i,
/netburner-logo/i,
/\/ui\/images\//i,
/logon_merge/i,
/logon_t\.gif/i,
/login_top\.gif/i,
/theme1\/images/i,
/\.well-known\/acme-challenge\/.*\.jpg$/i,
/\.well-known\/pki-validation\/.*\.jpg$/i,
// Path traversal and system file access patterns
/\/etc\/passwd/i,
/\/etc%2fpasswd/i,
/\/etc%5cpasswd/i,
/\/\/+etc/i,
/\\\\+.*etc/i,
/%2f%2f/i,
/%5c%5c/i,
/\/\/+/,
/\\\\+/,
/%00/i,
/%23/i,
// Encoded path traversal attempts
/%2e%2e/i,
/%252e/i,
/%c0%ae/i,
/%c1%9c/i,
];
// Suspicious HTTP methods
@@ -37,6 +70,10 @@ const RATE_LIMIT_WINDOW = 60 * 1000; // 1 minute
const MAX_ATTEMPTS = 10; // Max suspicious requests per window
const BAN_DURATION = 30 * 60 * 1000; // 30 minutes
// 404 rate limiting settings
const RATE_404_WINDOW = 2 * 60 * 1000; // 2 minutes
const MAX_404_ATTEMPTS = 10; // Max 404s before ban
const getClientIP = (request: NextRequest): string => {
const forwarded = request.headers.get('x-forwarded-for');
const realIP = request.headers.get('x-real-ip');
@@ -64,17 +101,51 @@ const updateIPAttempts = (ip: string): boolean => {
ipAttempts.set(ip, { count: 1, lastAttempt: now });
return false;
}
attempts.count++;
attempts.lastAttempt = now;
if (attempts.count > MAX_ATTEMPTS) {
bannedIPs.add(ip);
ipAttempts.delete(ip);
// Auto-unban after duration (in production, use a proper scheduler)
setTimeout(() => {
bannedIPs.delete(ip);
}, BAN_DURATION);
return true;
}
return false;
};
const update404Attempts = (ip: string): boolean => {
const now = Date.now();
const attempts = ip404Attempts.get(ip);
if (!attempts || now - attempts.lastAttempt > RATE_404_WINDOW) {
ip404Attempts.set(ip, { count: 1, lastAttempt: now });
return false;
}
attempts.count++;
attempts.lastAttempt = now;
if (attempts.count > MAX_404_ATTEMPTS) {
bannedIPs.add(ip);
ip404Attempts.delete(ip);
console.log(
`🔨 IP ${ip} banned for excessive 404 requests (${attempts.count} in ${RATE_404_WINDOW / 1000}s)`,
);
setTimeout(() => {
bannedIPs.delete(ip);
}, BAN_DURATION);
return true;
}
return false;
};
@@ -83,20 +154,48 @@ export const banSuspiciousIPs = (request: NextRequest): NextResponse | null => {
const method = request.method;
const ip = getClientIP(request);
if (bannedIPs.has(ip)) return new NextResponse('Access denied.', { status: 403 });
// Check if IP is already banned
if (bannedIPs.has(ip)) {
return new NextResponse('Access denied.', { status: 403 });
}
const isSuspiciousPath = isPathSuspicious(pathname);
const isSuspiciousMethod = isMethodSuspicious(method);
// Handle suspicious activity
if (isSuspiciousPath || isSuspiciousMethod) {
const shouldBan = updateIPAttempts(ip);
if (shouldBan) {
console.log(`🔨 IP ${ip} has been banned for suspicious activity`);
return new NextResponse('Access denied - IP banned. Please fuck off.', {
status: 403,
});
}
return new NextResponse('Not Found', { status: 404 });
}
return null;
};
// Call this function when you detect a 404 response
export const handle404Response = (
request: NextRequest,
): NextResponse | null => {
const ip = getClientIP(request);
if (bannedIPs.has(ip)) {
return new NextResponse('Access denied.', { status: 403 });
}
const shouldBan = update404Attempts(ip);
if (shouldBan) {
return new NextResponse('Access denied - IP banned for excessive 404s.', {
status: 403,
});
}
return null;
};

View File

@@ -5,7 +5,7 @@ import type { Database, SBClientWithDatabase } from '@/utils/supabase';
let client: SBClientWithDatabase | undefined;
const getSupbaseClient = (): SBClientWithDatabase | undefined => {
if (client) return client;
if (client) return client;
client = createBrowserClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,

View File

@@ -4,197 +4,196 @@ export type Json =
| boolean
| null
| { [key: string]: Json | undefined }
| Json[]
| Json[];
export type Database = {
public: {
Tables: {
profiles: {
Row: {
avatar_url: string | null
current_status_id: string | null
email: string | null
full_name: string | null
id: string
provider: string | null
updated_at: string | null
}
avatar_url: string | null;
current_status_id: string | null;
email: string | null;
full_name: string | null;
id: string;
provider: string | null;
updated_at: string | null;
};
Insert: {
avatar_url?: string | null
current_status_id?: string | null
email?: string | null
full_name?: string | null
id: string
provider?: string | null
updated_at?: string | null
}
avatar_url?: string | null;
current_status_id?: string | null;
email?: string | null;
full_name?: string | null;
id: string;
provider?: string | null;
updated_at?: string | null;
};
Update: {
avatar_url?: string | null
current_status_id?: string | null
email?: string | null
full_name?: string | null
id?: string
provider?: string | null
updated_at?: string | null
}
avatar_url?: string | null;
current_status_id?: string | null;
email?: string | null;
full_name?: string | null;
id?: string;
provider?: string | null;
updated_at?: string | null;
};
Relationships: [
{
foreignKeyName: "profiles_current_status_id_fkey"
columns: ["current_status_id"]
isOneToOne: false
referencedRelation: "statuses"
referencedColumns: ["id"]
foreignKeyName: 'profiles_current_status_id_fkey';
columns: ['current_status_id'];
isOneToOne: false;
referencedRelation: 'statuses';
referencedColumns: ['id'];
},
]
}
];
};
statuses: {
Row: {
created_at: string
id: string
status: string
updated_by_id: string | null
user_id: string
}
created_at: string;
id: string;
status: string;
updated_by_id: string | null;
user_id: string;
};
Insert: {
created_at?: string
id?: string
status: string
updated_by_id?: string | null
user_id: string
}
created_at?: string;
id?: string;
status: string;
updated_by_id?: string | null;
user_id: string;
};
Update: {
created_at?: string
id?: string
status?: string
updated_by_id?: string | null
user_id?: string
}
Relationships: []
}
}
created_at?: string;
id?: string;
status?: string;
updated_by_id?: string | null;
user_id?: string;
};
Relationships: [];
};
};
Views: {
[_ in never]: never
}
[_ in never]: never;
};
Functions: {
[_ in never]: never
}
[_ in never]: never;
};
Enums: {
[_ in never]: never
}
[_ in never]: never;
};
CompositeTypes: {
[_ in never]: never
}
}
}
[_ in never]: never;
};
};
};
type DefaultSchema = Database[Extract<keyof Database, "public">]
type DefaultSchema = Database[Extract<keyof Database, 'public'>];
export type Tables<
DefaultSchemaTableNameOrOptions extends
| keyof (DefaultSchema["Tables"] & DefaultSchema["Views"])
| keyof (DefaultSchema['Tables'] & DefaultSchema['Views'])
| { schema: keyof Database },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof Database
schema: keyof Database;
}
? keyof (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] &
Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])
? keyof (Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'] &
Database[DefaultSchemaTableNameOrOptions['schema']]['Views'])
: never = never,
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
? (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] &
Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends {
Row: infer R
? (Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'] &
Database[DefaultSchemaTableNameOrOptions['schema']]['Views'])[TableName] extends {
Row: infer R;
}
? R
: never
: DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] &
DefaultSchema["Views"])
? (DefaultSchema["Tables"] &
DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends {
Row: infer R
: DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema['Tables'] &
DefaultSchema['Views'])
? (DefaultSchema['Tables'] &
DefaultSchema['Views'])[DefaultSchemaTableNameOrOptions] extends {
Row: infer R;
}
? R
: never
: never
: never;
export type TablesInsert<
DefaultSchemaTableNameOrOptions extends
| keyof DefaultSchema["Tables"]
| keyof DefaultSchema['Tables']
| { schema: keyof Database },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof Database
schema: keyof Database;
}
? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"]
? keyof Database[DefaultSchemaTableNameOrOptions['schema']]['Tables']
: never = never,
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends {
Insert: infer I
? Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends {
Insert: infer I;
}
? I
: never
: DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"]
? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends {
Insert: infer I
: DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables']
? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends {
Insert: infer I;
}
? I
: never
: never
: never;
export type TablesUpdate<
DefaultSchemaTableNameOrOptions extends
| keyof DefaultSchema["Tables"]
| keyof DefaultSchema['Tables']
| { schema: keyof Database },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof Database
schema: keyof Database;
}
? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"]
? keyof Database[DefaultSchemaTableNameOrOptions['schema']]['Tables']
: never = never,
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends {
Update: infer U
? Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends {
Update: infer U;
}
? U
: never
: DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"]
? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends {
Update: infer U
: DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables']
? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends {
Update: infer U;
}
? U
: never
: never
: never;
export type Enums<
DefaultSchemaEnumNameOrOptions extends
| keyof DefaultSchema["Enums"]
| keyof DefaultSchema['Enums']
| { schema: keyof Database },
EnumName extends DefaultSchemaEnumNameOrOptions extends {
schema: keyof Database
schema: keyof Database;
}
? keyof Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"]
? keyof Database[DefaultSchemaEnumNameOrOptions['schema']]['Enums']
: never = never,
> = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database }
? Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName]
: DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"]
? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions]
: never
? Database[DefaultSchemaEnumNameOrOptions['schema']]['Enums'][EnumName]
: DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema['Enums']
? DefaultSchema['Enums'][DefaultSchemaEnumNameOrOptions]
: never;
export type CompositeTypes<
PublicCompositeTypeNameOrOptions extends
| keyof DefaultSchema["CompositeTypes"]
| keyof DefaultSchema['CompositeTypes']
| { schema: keyof Database },
CompositeTypeName extends PublicCompositeTypeNameOrOptions extends {
schema: keyof Database
schema: keyof Database;
}
? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"]
? keyof Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes']
: never = never,
> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database }
? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName]
: PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"]
? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions]
: never
? Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName]
: PublicCompositeTypeNameOrOptions extends keyof DefaultSchema['CompositeTypes']
? DefaultSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions]
: never;
export const Constants = {
public: {
Enums: {},
},
} as const
} as const;

View File

@@ -1,5 +1,5 @@
import type { Database } from '@/utils/supabase/database.types';
import type { SupabaseClient as SBClient } from '@supabase/supabase-js'
import type { SupabaseClient as SBClient } from '@supabase/supabase-js';
export type SBClientWithDatabase = SBClient<Database>;
@@ -11,17 +11,17 @@ export type Result<T> = {
};
export type UserRecord = {
id: string,
updated_at: string | null,
email: string | null,
full_name: string | null,
avatar_url: string | null,
provider: string | null,
id: string;
updated_at: string | null;
email: string | null;
full_name: string | null;
avatar_url: string | null;
provider: string | null;
status: {
status: string,
created_at: string,
updated_by: Profile | null,
}
status: string;
created_at: string;
updated_by: Profile | null;
};
};
export type AsyncReturnType<T extends (...args: any) => Promise<any>> =