197 lines
9.1 KiB
SQL
197 lines
9.1 KiB
SQL
-- Geofeed Manager Database Schema
|
|
-- For MariaDB/MySQL
|
|
|
|
CREATE DATABASE IF NOT EXISTS geofeed_manager;
|
|
USE geofeed_manager;
|
|
|
|
-- Main geofeed entries table with IP enrichment data
|
|
CREATE TABLE IF NOT EXISTS geofeed_entries (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
ip_prefix VARCHAR(50) NOT NULL,
|
|
country_code CHAR(2) DEFAULT NULL,
|
|
region_code VARCHAR(10) DEFAULT NULL,
|
|
city VARCHAR(255) DEFAULT NULL,
|
|
postal_code VARCHAR(50) DEFAULT NULL,
|
|
client_short_name VARCHAR(100) DEFAULT NULL,
|
|
notes TEXT DEFAULT NULL,
|
|
sort_order INT DEFAULT 0,
|
|
|
|
-- IP Registry enrichment data
|
|
ipr_enriched_at TIMESTAMP NULL DEFAULT NULL,
|
|
ipr_hostname VARCHAR(255) DEFAULT NULL,
|
|
ipr_isp VARCHAR(255) DEFAULT NULL,
|
|
ipr_org VARCHAR(255) DEFAULT NULL,
|
|
ipr_asn INT DEFAULT NULL,
|
|
ipr_asn_name VARCHAR(255) DEFAULT NULL,
|
|
ipr_connection_type VARCHAR(50) DEFAULT NULL,
|
|
ipr_country_name VARCHAR(100) DEFAULT NULL,
|
|
ipr_region_name VARCHAR(100) DEFAULT NULL,
|
|
ipr_timezone VARCHAR(100) DEFAULT NULL,
|
|
ipr_latitude DECIMAL(10, 7) DEFAULT NULL,
|
|
ipr_longitude DECIMAL(10, 7) DEFAULT NULL,
|
|
|
|
-- Security flags from IP Registry
|
|
flag_abuser TINYINT(1) DEFAULT 0,
|
|
flag_attacker TINYINT(1) DEFAULT 0,
|
|
flag_bogon TINYINT(1) DEFAULT 0,
|
|
flag_cloud_provider TINYINT(1) DEFAULT 0,
|
|
flag_proxy TINYINT(1) DEFAULT 0,
|
|
flag_relay TINYINT(1) DEFAULT 0,
|
|
flag_tor TINYINT(1) DEFAULT 0,
|
|
flag_tor_exit TINYINT(1) DEFAULT 0,
|
|
flag_vpn TINYINT(1) DEFAULT 0,
|
|
flag_anonymous TINYINT(1) DEFAULT 0,
|
|
flag_threat TINYINT(1) DEFAULT 0,
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
UNIQUE KEY unique_prefix (ip_prefix),
|
|
INDEX idx_country (country_code),
|
|
INDEX idx_region (region_code),
|
|
INDEX idx_city (city),
|
|
INDEX idx_client (client_short_name),
|
|
INDEX idx_sort_order (sort_order),
|
|
INDEX idx_isp (ipr_isp),
|
|
INDEX idx_asn (ipr_asn)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- Audit log for tracking changes
|
|
CREATE TABLE IF NOT EXISTS geofeed_audit_log (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
entry_id INT,
|
|
action ENUM('INSERT', 'UPDATE', 'DELETE') NOT NULL,
|
|
old_values JSON DEFAULT NULL,
|
|
new_values JSON DEFAULT NULL,
|
|
changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
changed_by VARCHAR(255) DEFAULT NULL,
|
|
INDEX idx_entry (entry_id),
|
|
INDEX idx_action (action),
|
|
INDEX idx_changed_at (changed_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- Settings table for app configuration
|
|
CREATE TABLE IF NOT EXISTS geofeed_settings (
|
|
setting_key VARCHAR(100) PRIMARY KEY,
|
|
setting_value TEXT,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- Client logos table for storing logo URLs per shortname
|
|
CREATE TABLE IF NOT EXISTS client_logos (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
short_name VARCHAR(100) NOT NULL,
|
|
logo_url VARCHAR(500) NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
UNIQUE KEY unique_short_name (short_name),
|
|
INDEX idx_short_name (short_name)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- Webhook queue table for debounced notifications
|
|
CREATE TABLE IF NOT EXISTS webhook_queue (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
webhook_type VARCHAR(50) NOT NULL DEFAULT 'geofeed_update',
|
|
trigger_reason VARCHAR(255) DEFAULT NULL,
|
|
entries_affected INT DEFAULT 0,
|
|
queued_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
scheduled_for TIMESTAMP NULL,
|
|
processed_at TIMESTAMP NULL,
|
|
status ENUM('pending', 'processing', 'completed', 'failed') DEFAULT 'pending',
|
|
response_code INT DEFAULT NULL,
|
|
response_body TEXT DEFAULT NULL,
|
|
INDEX idx_status (status),
|
|
INDEX idx_scheduled (scheduled_for)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- User sessions table for authentication
|
|
CREATE TABLE IF NOT EXISTS user_sessions (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
session_token VARCHAR(64) NOT NULL,
|
|
username VARCHAR(100) NOT NULL,
|
|
ip_address VARCHAR(45) DEFAULT NULL,
|
|
user_agent TEXT DEFAULT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
expires_at TIMESTAMP NOT NULL,
|
|
UNIQUE KEY unique_token (session_token),
|
|
INDEX idx_expires (expires_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- PTR records cache table for Route53 A records
|
|
CREATE TABLE IF NOT EXISTS ptr_records_cache (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
zone_id VARCHAR(50) NOT NULL,
|
|
zone_name VARCHAR(255) DEFAULT NULL,
|
|
hostname VARCHAR(255) NOT NULL,
|
|
ip_address VARCHAR(45) NOT NULL,
|
|
ttl INT DEFAULT NULL,
|
|
ptr_record VARCHAR(255) DEFAULT NULL,
|
|
ptr_status ENUM('unknown', 'match', 'mismatch', 'missing', 'error') DEFAULT 'unknown',
|
|
ptr_checked_at TIMESTAMP NULL DEFAULT NULL,
|
|
aws_synced_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
UNIQUE KEY unique_zone_hostname (zone_id, hostname),
|
|
INDEX idx_zone (zone_id),
|
|
INDEX idx_ip (ip_address),
|
|
INDEX idx_status (ptr_status),
|
|
INDEX idx_synced (aws_synced_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- Insert default settings
|
|
INSERT INTO geofeed_settings (setting_key, setting_value) VALUES
|
|
('bunny_cdn_storage_zone', ''),
|
|
('bunny_cdn_api_key', ''),
|
|
('bunny_cdn_file_path', '/geofeed.csv'),
|
|
('last_export_at', NULL),
|
|
('n8n_webhook_url', ''),
|
|
('n8n_webhook_enabled', '0'),
|
|
('n8n_webhook_delay_minutes', '3'),
|
|
('ipregistry_api_key', ''),
|
|
('ipregistry_enabled', '0'),
|
|
('aws_access_key_id', ''),
|
|
('aws_secret_access_key', ''),
|
|
('aws_region', 'us-east-1'),
|
|
('aws_hosted_zones', '')
|
|
ON DUPLICATE KEY UPDATE setting_key = setting_key;
|
|
|
|
-- ============================================
|
|
-- MIGRATION: Add columns for existing databases
|
|
-- These statements safely add columns if they don't exist
|
|
-- ============================================
|
|
|
|
-- Add sort_order column
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS sort_order INT DEFAULT 0 AFTER notes;
|
|
|
|
-- Add IP Registry enrichment columns
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_enriched_at TIMESTAMP NULL DEFAULT NULL AFTER sort_order;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_hostname VARCHAR(255) DEFAULT NULL AFTER ipr_enriched_at;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_isp VARCHAR(255) DEFAULT NULL AFTER ipr_hostname;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_org VARCHAR(255) DEFAULT NULL AFTER ipr_isp;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_asn INT DEFAULT NULL AFTER ipr_org;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_asn_name VARCHAR(255) DEFAULT NULL AFTER ipr_asn;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_connection_type VARCHAR(50) DEFAULT NULL AFTER ipr_asn_name;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_country_name VARCHAR(100) DEFAULT NULL AFTER ipr_connection_type;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_region_name VARCHAR(100) DEFAULT NULL AFTER ipr_country_name;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_timezone VARCHAR(100) DEFAULT NULL AFTER ipr_region_name;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_latitude DECIMAL(10, 7) DEFAULT NULL AFTER ipr_timezone;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS ipr_longitude DECIMAL(10, 7) DEFAULT NULL AFTER ipr_latitude;
|
|
|
|
-- Add security flag columns
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_abuser TINYINT(1) DEFAULT 0 AFTER ipr_longitude;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_attacker TINYINT(1) DEFAULT 0 AFTER flag_abuser;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_bogon TINYINT(1) DEFAULT 0 AFTER flag_attacker;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_cloud_provider TINYINT(1) DEFAULT 0 AFTER flag_bogon;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_proxy TINYINT(1) DEFAULT 0 AFTER flag_cloud_provider;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_relay TINYINT(1) DEFAULT 0 AFTER flag_proxy;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_tor TINYINT(1) DEFAULT 0 AFTER flag_relay;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_tor_exit TINYINT(1) DEFAULT 0 AFTER flag_tor;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_vpn TINYINT(1) DEFAULT 0 AFTER flag_tor_exit;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_anonymous TINYINT(1) DEFAULT 0 AFTER flag_vpn;
|
|
ALTER TABLE geofeed_entries ADD COLUMN IF NOT EXISTS flag_threat TINYINT(1) DEFAULT 0 AFTER flag_anonymous;
|
|
|
|
-- Add indexes if they don't exist (MariaDB 10.5+ supports IF NOT EXISTS for indexes)
|
|
-- For older versions, these will show warnings but won't fail
|
|
ALTER TABLE geofeed_entries ADD INDEX IF NOT EXISTS idx_sort_order (sort_order);
|
|
ALTER TABLE geofeed_entries ADD INDEX IF NOT EXISTS idx_isp (ipr_isp);
|
|
ALTER TABLE geofeed_entries ADD INDEX IF NOT EXISTS idx_asn (ipr_asn);
|