Migrate configuration from environment variables to YAML file

- Add YAML-based configuration loaded from config.yaml (CONFIG_LOCATION env var)
  - Add PyYAML dependency and install requirements in Dockerfile
  - Replace Config.from_env() with get_config() singleton pattern
  - Remove server_header from config (now randomized from wordlists only)
  - Update docker-compose.yaml to mount config.yaml read-only
  - Update Helm chart: restructure values.yaml, generate config.yaml in ConfigMap
  - Update Kubernetes manifests: ConfigMap now contains config.yaml, deployments mount it
  - Remove Helm secret.yaml (dashboard path now auto-generated in config.yaml)
This commit is contained in:
Phillip Tarrant
2026-01-02 13:39:54 -06:00
parent 5a00e374e6
commit d458eb471d
14 changed files with 307 additions and 181 deletions

View File

@@ -4,6 +4,9 @@ LABEL org.opencontainers.image.source=https://github.com/BlessedRebuS/Krawl
WORKDIR /app WORKDIR /app
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ /app/src/ COPY src/ /app/src/
COPY wordlists.json /app/ COPY wordlists.json /app/

35
config.yaml Normal file
View File

@@ -0,0 +1,35 @@
# Krawl Honeypot Configuration
server:
port: 5000
delay: 100 # Response delay in milliseconds
timezone: null # e.g., "America/New_York" or null for system default
links:
min_length: 5
max_length: 15
min_per_page: 10
max_per_page: 15
char_space: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
max_counter: 10
canary:
token_url: null # Optional canary token URL
token_tries: 10
dashboard:
# if set to "null" this will Auto-generates random path if not set
# can be set to "dashboard" or similar
secret_path: dashboard
api:
server_url: null
server_port: 8080
server_path: "/api/v2/users"
database:
path: "data/krawl.db"
retention_days: 30
behavior:
probability_error_codes: 0 # 0-100 percentage

View File

@@ -10,23 +10,9 @@ services:
- "5000:5000" - "5000:5000"
volumes: volumes:
- ./wordlists.json:/app/wordlists.json:ro - ./wordlists.json:/app/wordlists.json:ro
- ./config.yaml:/app/config.yaml:ro
environment: environment:
- PORT=5000 - CONFIG_LOCATION=config.yaml
- DELAY=100
- LINKS_MIN_LENGTH=5
- LINKS_MAX_LENGTH=15
- LINKS_MIN_PER_PAGE=10
- LINKS_MAX_PER_PAGE=15
- MAX_COUNTER=10
- CANARY_TOKEN_TRIES=10
- PROBABILITY_ERROR_CODES=0
# - SERVER_HEADER=Apache/2.2.22 (Ubuntu)
# Optional: Set your canary token URL
# - CANARY_TOKEN_URL=http://canarytokens.com/api/users/YOUR_TOKEN/passwords.txt
# Optional: Set custom dashboard path (auto-generated if not set)
# - DASHBOARD_SECRET_PATH=/my-secret-dashboard
# Optional: Set timezone for logs and dashboard (e.g., America/New_York, Europe/Rome)
# - TIMEZONE=UTC
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: ["CMD", "python3", "-c", "import requests; requests.get('http://localhost:5000')"] test: ["CMD", "python3", "-c", "import requests; requests.get('http://localhost:5000')"]

View File

@@ -5,25 +5,30 @@ metadata:
labels: labels:
{{- include "krawl.labels" . | nindent 4 }} {{- include "krawl.labels" . | nindent 4 }}
data: data:
PORT: {{ .Values.config.port | quote }} config.yaml: |
DELAY: {{ .Values.config.delay | quote }} # Krawl Honeypot Configuration
LINKS_MIN_LENGTH: {{ .Values.config.linksMinLength | quote }} server:
LINKS_MAX_LENGTH: {{ .Values.config.linksMaxLength | quote }} port: {{ .Values.config.server.port }}
LINKS_MIN_PER_PAGE: {{ .Values.config.linksMinPerPage | quote }} delay: {{ .Values.config.server.delay }}
LINKS_MAX_PER_PAGE: {{ .Values.config.linksMaxPerPage | quote }} timezone: {{ .Values.config.server.timezone | toYaml }}
MAX_COUNTER: {{ .Values.config.maxCounter | quote }} links:
CANARY_TOKEN_TRIES: {{ .Values.config.canaryTokenTries | quote }} min_length: {{ .Values.config.links.min_length }}
PROBABILITY_ERROR_CODES: {{ .Values.config.probabilityErrorCodes | quote }} max_length: {{ .Values.config.links.max_length }}
CANARY_TOKEN_URL: {{ .Values.config.canaryTokenUrl | quote }} min_per_page: {{ .Values.config.links.min_per_page }}
{{- if .Values.config.dashboardSecretPath }} max_per_page: {{ .Values.config.links.max_per_page }}
DASHBOARD_SECRET_PATH: {{ .Values.config.dashboardSecretPath | quote }} char_space: {{ .Values.config.links.char_space | quote }}
{{- end }} max_counter: {{ .Values.config.links.max_counter }}
{{- if .Values.config.serverHeader }} canary:
SERVER_HEADER: {{ .Values.config.serverHeader | quote }} token_url: {{ .Values.config.canary.token_url | toYaml }}
{{- end }} token_tries: {{ .Values.config.canary.token_tries }}
{{- if .Values.config.timezone }} dashboard:
TIMEZONE: {{ .Values.config.timezone | quote }} secret_path: {{ .Values.config.dashboard.secret_path | toYaml }}
{{- end }} api:
# Database configuration server_url: {{ .Values.config.api.server_url | toYaml }}
DATABASE_PATH: {{ .Values.database.path | quote }} server_port: {{ .Values.config.api.server_port }}
DATABASE_RETENTION_DAYS: {{ .Values.database.retentionDays | quote }} server_path: {{ .Values.config.api.server_path | quote }}
database:
path: {{ .Values.config.database.path | quote }}
retention_days: {{ .Values.config.database.retention_days }}
behavior:
probability_error_codes: {{ .Values.config.behavior.probability_error_codes }}

View File

@@ -38,18 +38,16 @@ spec:
imagePullPolicy: {{ .Values.image.pullPolicy }} imagePullPolicy: {{ .Values.image.pullPolicy }}
ports: ports:
- name: http - name: http
containerPort: {{ .Values.config.port }} containerPort: {{ .Values.config.server.port }}
protocol: TCP protocol: TCP
envFrom:
- configMapRef:
name: {{ include "krawl.fullname" . }}-config
env: env:
- name: DASHBOARD_SECRET_PATH - name: CONFIG_LOCATION
valueFrom: value: "config.yaml"
secretKeyRef:
name: {{ include "krawl.fullname" . }}
key: dashboard-path
volumeMounts: volumeMounts:
- name: config
mountPath: /app/config.yaml
subPath: config.yaml
readOnly: true
- name: wordlists - name: wordlists
mountPath: /app/wordlists.json mountPath: /app/wordlists.json
subPath: wordlists.json subPath: wordlists.json
@@ -63,6 +61,9 @@ spec:
{{- toYaml . | nindent 12 }} {{- toYaml . | nindent 12 }}
{{- end }} {{- end }}
volumes: volumes:
- name: config
configMap:
name: {{ include "krawl.fullname" . }}-config
- name: wordlists - name: wordlists
configMap: configMap:
name: {{ include "krawl.fullname" . }}-wordlists name: {{ include "krawl.fullname" . }}-wordlists

View File

@@ -1,16 +0,0 @@
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (include "krawl.fullname" .)) -}}
{{- $dashboardPath := "" -}}
{{- if and $secret $secret.data -}}
{{- $dashboardPath = index $secret.data "dashboard-path" | b64dec -}}
{{- else -}}
{{- $dashboardPath = printf "/%s" (randAlphaNum 32) -}}
{{- end -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "krawl.fullname" . }}
labels:
{{- include "krawl.labels" . | nindent 4 }}
type: Opaque
stringData:
dashboard-path: {{ $dashboardPath | quote }}

View File

@@ -62,29 +62,36 @@ tolerations: []
affinity: {} affinity: {}
# Application configuration # Application configuration (config.yaml structure)
config: config:
port: 5000 server:
delay: 100 port: 5000
linksMinLength: 5 delay: 100
linksMaxLength: 15 timezone: null # IANA timezone (e.g., "America/New_York", "Europe/Rome"). If not set, system timezone is used.
linksMinPerPage: 10 links:
linksMaxPerPage: 15 min_length: 5
maxCounter: 10 max_length: 15
canaryTokenTries: 10 min_per_page: 10
probabilityErrorCodes: 0 max_per_page: 15
# timezone: "UTC" char_space: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
# serverHeader: "Apache/2.2.22 (Ubuntu)" max_counter: 10
# dashboardSecretPath: "/my-secret-dashboard" canary:
# canaryTokenUrl: set-your-canary-token-url-here token_url: null # Set your canary token URL here
# timezone: "UTC" # IANA timezone (e.g., "America/New_York", "Europe/Rome"). If not set, system timezone is used. token_tries: 10
dashboard:
secret_path: null # Auto-generated if not set, or set to "/my-secret-dashboard"
api:
server_url: null
server_port: 8080
server_path: "/api/v2/users"
database:
path: "data/krawl.db"
retention_days: 30
behavior:
probability_error_codes: 0
# Database configuration # Database persistence configuration
database: database:
# Path to the SQLite database file
path: "data/krawl.db"
# Number of days to retain access logs and attack data
retentionDays: 30
# Persistence configuration # Persistence configuration
persistence: persistence:
enabled: true enabled: true

View File

@@ -10,19 +10,41 @@ metadata:
name: krawl-config name: krawl-config
namespace: krawl-system namespace: krawl-system
data: data:
PORT: "5000" config.yaml: |
DELAY: "100" # Krawl Honeypot Configuration
LINKS_MIN_LENGTH: "5" server:
LINKS_MAX_LENGTH: "15" port: 5000
LINKS_MIN_PER_PAGE: "10" delay: 100
LINKS_MAX_PER_PAGE: "15" timezone: null # e.g., "America/New_York" or null for system default
MAX_COUNTER: "10"
CANARY_TOKEN_TRIES: "10" links:
PROBABILITY_ERROR_CODES: "0" min_length: 5
# CANARY_TOKEN_URL: set-your-canary-token-url-here max_length: 15
# Database configuration min_per_page: 10
DATABASE_PATH: "data/krawl.db" max_per_page: 15
DATABASE_RETENTION_DAYS: "30" char_space: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
max_counter: 10
canary:
token_url: null # Optional canary token URL
token_tries: 10
dashboard:
# Auto-generates random path if null
# Can be set to "/dashboard" or similar
secret_path: null
api:
server_url: null
server_port: 8080
server_path: "/api/v2/users"
database:
path: "data/krawl.db"
retention_days: 30
behavior:
probability_error_codes: 0 # 0-100 percentage
--- ---
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
@@ -227,6 +249,14 @@ data:
500, 500,
502, 502,
503 503
],
"server_headers": [
"Apache/2.4.41 (Ubuntu)",
"nginx/1.18.0",
"Microsoft-IIS/10.0",
"cloudflare",
"AmazonS3",
"gunicorn/20.1.0"
] ]
} }
--- ---
@@ -269,10 +299,14 @@ spec:
- containerPort: 5000 - containerPort: 5000
name: http name: http
protocol: TCP protocol: TCP
envFrom: env:
- configMapRef: - name: CONFIG_LOCATION
name: krawl-config value: "config.yaml"
volumeMounts: volumeMounts:
- name: config
mountPath: /app/config.yaml
subPath: config.yaml
readOnly: true
- name: wordlists - name: wordlists
mountPath: /app/wordlists.json mountPath: /app/wordlists.json
subPath: wordlists.json subPath: wordlists.json
@@ -287,6 +321,9 @@ spec:
memory: "256Mi" memory: "256Mi"
cpu: "500m" cpu: "500m"
volumes: volumes:
- name: config
configMap:
name: krawl-config
- name: wordlists - name: wordlists
configMap: configMap:
name: krawl-wordlists name: krawl-wordlists
@@ -353,7 +390,7 @@ spec:
- podSelector: {} - podSelector: {}
- namespaceSelector: {} - namespaceSelector: {}
- ipBlock: - ipBlock:
cidr: 0.0.0.0/0 cidr: 0.0.0.0/0
ports: ports:
- protocol: TCP - protocol: TCP
port: 5000 port: 5000

View File

@@ -4,18 +4,38 @@ metadata:
name: krawl-config name: krawl-config
namespace: krawl-system namespace: krawl-system
data: data:
PORT: "5000" config.yaml: |
DELAY: "100" # Krawl Honeypot Configuration
LINKS_MIN_LENGTH: "5" server:
LINKS_MAX_LENGTH: "15" port: 5000
LINKS_MIN_PER_PAGE: "10" delay: 100
LINKS_MAX_PER_PAGE: "15" timezone: null # e.g., "America/New_York" or null for system default
MAX_COUNTER: "10"
CANARY_TOKEN_TRIES: "10" links:
PROBABILITY_ERROR_CODES: "0" min_length: 5
SERVER_HEADER: "Apache/2.2.22 (Ubuntu)" max_length: 15
# CANARY_TOKEN_URL: set-your-canary-token-url-here min_per_page: 10
# TIMEZONE: "UTC" # IANA timezone (e.g., "America/New_York", "Europe/Rome") max_per_page: 15
# Database configuration char_space: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
DATABASE_PATH: "data/krawl.db" max_counter: 10
DATABASE_RETENTION_DAYS: "30"
canary:
token_url: null # Optional canary token URL
token_tries: 10
dashboard:
# Auto-generates random path if null
# Can be set to "/dashboard" or similar
secret_path: null
api:
server_url: null
server_port: 8080
server_path: "/api/v2/users"
database:
path: "data/krawl.db"
retention_days: 30
behavior:
probability_error_codes: 0 # 0-100 percentage

View File

@@ -23,10 +23,14 @@ spec:
- containerPort: 5000 - containerPort: 5000
name: http name: http
protocol: TCP protocol: TCP
envFrom: env:
- configMapRef: - name: CONFIG_LOCATION
name: krawl-config value: "config.yaml"
volumeMounts: volumeMounts:
- name: config
mountPath: /app/config.yaml
subPath: config.yaml
readOnly: true
- name: wordlists - name: wordlists
mountPath: /app/wordlists.json mountPath: /app/wordlists.json
subPath: wordlists.json subPath: wordlists.json
@@ -41,6 +45,9 @@ spec:
memory: "256Mi" memory: "256Mi"
cpu: "500m" cpu: "500m"
volumes: volumes:
- name: config
configMap:
name: krawl-config
- name: wordlists - name: wordlists
configMap: configMap:
name: krawl-wordlists name: krawl-wordlists

View File

@@ -1,5 +1,8 @@
# Krawl Honeypot Dependencies # Krawl Honeypot Dependencies
# Install with: pip install -r requirements.txt # Install with: pip install -r requirements.txt
# Configuration
PyYAML>=6.0
# Database ORM # Database ORM
SQLAlchemy>=2.0.0,<3.0.0 SQLAlchemy>=2.0.0,<3.0.0

View File

@@ -1,11 +1,15 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import sys
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path
from typing import Optional, Tuple from typing import Optional, Tuple
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
import time import time
import yaml
@dataclass @dataclass
class Config: class Config:
@@ -23,12 +27,11 @@ class Config:
api_server_port: int = 8080 api_server_port: int = 8080
api_server_path: str = "/api/v2/users" api_server_path: str = "/api/v2/users"
probability_error_codes: int = 0 # Percentage (0-100) probability_error_codes: int = 0 # Percentage (0-100)
server_header: Optional[str] = None
# Database settings # Database settings
database_path: str = "data/krawl.db" database_path: str = "data/krawl.db"
database_retention_days: int = 30 database_retention_days: int = 30
timezone: str = None # IANA timezone (e.g., 'America/New_York', 'Europe/Rome') timezone: str = None # IANA timezone (e.g., 'America/New_York', 'Europe/Rome')
@staticmethod @staticmethod
# Try to fetch timezone before if not set # Try to fetch timezone before if not set
def get_system_timezone() -> str: def get_system_timezone() -> str:
@@ -38,16 +41,16 @@ class Config:
tz_path = os.readlink('/etc/localtime') tz_path = os.readlink('/etc/localtime')
if 'zoneinfo/' in tz_path: if 'zoneinfo/' in tz_path:
return tz_path.split('zoneinfo/')[-1] return tz_path.split('zoneinfo/')[-1]
local_tz = time.tzname[time.daylight] local_tz = time.tzname[time.daylight]
if local_tz and local_tz != 'UTC': if local_tz and local_tz != 'UTC':
return local_tz return local_tz
except Exception: except Exception:
pass pass
# Default fallback to UTC # Default fallback to UTC
return 'UTC' return 'UTC'
def get_timezone(self) -> ZoneInfo: def get_timezone(self) -> ZoneInfo:
"""Get configured timezone as ZoneInfo object""" """Get configured timezone as ZoneInfo object"""
if self.timezone: if self.timezone:
@@ -55,7 +58,7 @@ class Config:
return ZoneInfo(self.timezone) return ZoneInfo(self.timezone)
except Exception: except Exception:
pass pass
system_tz = self.get_system_timezone() system_tz = self.get_system_timezone()
try: try:
return ZoneInfo(system_tz) return ZoneInfo(system_tz)
@@ -63,31 +66,71 @@ class Config:
return ZoneInfo('UTC') return ZoneInfo('UTC')
@classmethod @classmethod
def from_env(cls) -> 'Config': def from_yaml(cls) -> 'Config':
"""Create configuration from environment variables""" """Create configuration from YAML file"""
config_location = os.getenv('CONFIG_LOCATION', 'config.yaml')
config_path = Path(__file__).parent.parent / config_location
try:
with open(config_path, 'r') as f:
data = yaml.safe_load(f)
except FileNotFoundError:
print(f"Error: Configuration file '{config_path}' not found.", file=sys.stderr)
print(f"Please create a config.yaml file or set CONFIG_LOCATION environment variable.", file=sys.stderr)
sys.exit(1)
except yaml.YAMLError as e:
print(f"Error: Invalid YAML in configuration file '{config_path}': {e}", file=sys.stderr)
sys.exit(1)
if data is None:
data = {}
# Extract nested values with defaults
server = data.get('server', {})
links = data.get('links', {})
canary = data.get('canary', {})
dashboard = data.get('dashboard', {})
api = data.get('api', {})
database = data.get('database', {})
behavior = data.get('behavior', {})
# Handle dashboard_secret_path - auto-generate if null/not set
dashboard_path = dashboard.get('secret_path')
if dashboard_path is None:
dashboard_path = f'/{os.urandom(16).hex()}'
return cls( return cls(
port=int(os.getenv('PORT', 5000)), port=server.get('port', 5000),
delay=int(os.getenv('DELAY', 100)), delay=server.get('delay', 100),
timezone=server.get('timezone'),
links_length_range=( links_length_range=(
int(os.getenv('LINKS_MIN_LENGTH', 5)), links.get('min_length', 5),
int(os.getenv('LINKS_MAX_LENGTH', 15)) links.get('max_length', 15)
), ),
links_per_page_range=( links_per_page_range=(
int(os.getenv('LINKS_MIN_PER_PAGE', 10)), links.get('min_per_page', 10),
int(os.getenv('LINKS_MAX_PER_PAGE', 15)) links.get('max_per_page', 15)
), ),
char_space=os.getenv('CHAR_SPACE', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'), char_space=links.get('char_space', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'),
max_counter=int(os.getenv('MAX_COUNTER', 10)), max_counter=links.get('max_counter', 10),
canary_token_url=os.getenv('CANARY_TOKEN_URL'), canary_token_url=canary.get('token_url'),
canary_token_tries=int(os.getenv('CANARY_TOKEN_TRIES', 10)), canary_token_tries=canary.get('token_tries', 10),
dashboard_secret_path=os.getenv('DASHBOARD_SECRET_PATH', f'/{os.urandom(16).hex()}'), dashboard_secret_path=dashboard_path,
api_server_url=os.getenv('API_SERVER_URL'), api_server_url=api.get('server_url'),
api_server_port=int(os.getenv('API_SERVER_PORT', 8080)), api_server_port=api.get('server_port', 8080),
api_server_path=os.getenv('API_SERVER_PATH', '/api/v2/users'), api_server_path=api.get('server_path', '/api/v2/users'),
probability_error_codes=int(os.getenv('PROBABILITY_ERROR_CODES', 0)), probability_error_codes=behavior.get('probability_error_codes', 0),
server_header=os.getenv('SERVER_HEADER'), database_path=database.get('path', 'data/krawl.db'),
database_path=os.getenv('DATABASE_PATH', 'data/krawl.db'), database_retention_days=database.get('retention_days', 30),
database_retention_days=int(os.getenv('DATABASE_RETENTION_DAYS', 30)),
timezone=os.getenv('TIMEZONE') # If not set, will use system timezone
) )
_config_instance = None
def get_config() -> Config:
"""Get the singleton Config instance"""
global _config_instance
if _config_instance is None:
_config_instance = Config.from_yaml()
return _config_instance

View File

@@ -9,8 +9,6 @@ import string
import json import json
from templates import html_templates from templates import html_templates
from wordlists import get_wordlists from wordlists import get_wordlists
from config import Config
from logger import get_app_logger
def random_username() -> str: def random_username() -> str:
"""Generate random username""" """Generate random username"""
@@ -38,15 +36,9 @@ def random_email(username: str = None) -> str:
return f"{username}@{random.choice(wl.email_domains)}" return f"{username}@{random.choice(wl.email_domains)}"
def random_server_header() -> str: def random_server_header() -> str:
"""Generate random server header""" """Generate random server header from wordlists"""
wl = get_wordlists()
if Config.from_env().server_header: return random.choice(wl.server_headers)
server_header = Config.from_env().server_header
else:
wl = get_wordlists()
server_header = random.choice(wl.server_headers)
return server_header
def random_api_key() -> str: def random_api_key() -> str:
"""Generate random API key""" """Generate random API key"""

View File

@@ -8,7 +8,7 @@ Run this file to start the server.
import sys import sys
from http.server import HTTPServer from http.server import HTTPServer
from config import Config from config import get_config
from tracker import AccessTracker from tracker import AccessTracker
from handler import Handler from handler import Handler
from logger import initialize_logging, get_app_logger, get_access_logger, get_credential_logger from logger import initialize_logging, get_app_logger, get_access_logger, get_credential_logger
@@ -20,24 +20,29 @@ def print_usage():
print(f'Usage: {sys.argv[0]} [FILE]\n') print(f'Usage: {sys.argv[0]} [FILE]\n')
print('FILE is file containing a list of webpage names to serve, one per line.') print('FILE is file containing a list of webpage names to serve, one per line.')
print('If no file is provided, random links will be generated.\n') print('If no file is provided, random links will be generated.\n')
print('Environment Variables:') print('Configuration:')
print(' PORT - Server port (default: 5000)') print(' Configuration is loaded from a YAML file (default: config.yaml)')
print(' DELAY - Response delay in ms (default: 100)') print(' Set CONFIG_LOCATION environment variable to use a different file.\n')
print(' LINKS_MIN_LENGTH - Min link length (default: 5)') print(' Example config.yaml structure:')
print(' LINKS_MAX_LENGTH - Max link length (default: 15)') print(' server:')
print(' LINKS_MIN_PER_PAGE - Min links per page (default: 10)') print(' port: 5000')
print(' LINKS_MAX_PER_PAGE - Max links per page (default: 15)') print(' delay: 100')
print(' MAX_COUNTER - Max counter value (default: 10)') print(' timezone: null # or "America/New_York"')
print(' CANARY_TOKEN_URL - Canary token URL to display') print(' links:')
print(' CANARY_TOKEN_TRIES - Number of tries before showing token (default: 10)') print(' min_length: 5')
print(' DASHBOARD_SECRET_PATH - Secret path for dashboard (auto-generated if not set)') print(' max_length: 15')
print(' PROBABILITY_ERROR_CODES - Probability (0-100) to return HTTP error codes (default: 0)') print(' min_per_page: 10')
print(' CHAR_SPACE - Characters for random links') print(' max_per_page: 15')
print(' SERVER_HEADER - HTTP Server header for deception (default: Apache/2.2.22 (Ubuntu))') print(' canary:')
print(' DATABASE_PATH - Path to SQLite database (default: data/krawl.db)') print(' token_url: null')
print(' DATABASE_RETENTION_DAYS - Days to retain database records (default: 30)') print(' token_tries: 10')
print(' TIMEZONE - IANA timezone for logs/dashboard (e.g., America/New_York, Europe/Rome)') print(' dashboard:')
print(' If not set, system timezone will be used') print(' secret_path: null # auto-generated if not set')
print(' database:')
print(' path: "data/krawl.db"')
print(' retention_days: 30')
print(' behavior:')
print(' probability_error_codes: 0')
def main(): def main():
@@ -46,19 +51,17 @@ def main():
print_usage() print_usage()
exit(0) exit(0)
config = Config.from_env() config = get_config()
# Get timezone configuration # Get timezone configuration
tz = config.get_timezone() tz = config.get_timezone()
# Initialize logging with timezone # Initialize logging with timezone
initialize_logging(timezone=tz) initialize_logging(timezone=tz)
app_logger = get_app_logger() app_logger = get_app_logger()
access_logger = get_access_logger() access_logger = get_access_logger()
credential_logger = get_credential_logger() credential_logger = get_credential_logger()
config = Config.from_env()
# Initialize database for persistent storage # Initialize database for persistent storage
try: try:
initialize_database(config.database_path) initialize_database(config.database_path)