Add full application source
This commit is contained in:
0
src/utils/__init__.py
Normal file
0
src/utils/__init__.py
Normal file
59
src/utils/file_io.py
Normal file
59
src/utils/file_io.py
Normal file
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
File I/O utilities for reading/writing password lists and proxy lists.
|
||||
"""
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
from config import PASSWORDS_FILE, PROXIES_FILE, VALID_PROXIES_FILE
|
||||
|
||||
|
||||
def save_passwords(passwords: List[str], filepath: Optional[Path] = None, append: bool = True):
|
||||
"""Save password list to file. Appends by default."""
|
||||
path = filepath or PASSWORDS_FILE
|
||||
mode = "a" if append else "w"
|
||||
with open(path, mode, encoding="utf-8") as f:
|
||||
for pwd in passwords:
|
||||
f.write(pwd + "\n")
|
||||
|
||||
|
||||
def load_passwords(filepath: Optional[Path] = None) -> List[str]:
|
||||
"""Load passwords from file, stripping whitespace and removing empties."""
|
||||
path = filepath or PASSWORDS_FILE
|
||||
if not path.exists():
|
||||
return []
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return [line.strip() for line in f if line.strip()]
|
||||
|
||||
|
||||
def save_proxies(proxies: List[str], filepath: Optional[Path] = None):
|
||||
"""Save proxy list to file."""
|
||||
path = filepath or PROXIES_FILE
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
for proxy in proxies:
|
||||
f.write(proxy + "\n")
|
||||
|
||||
|
||||
def load_proxies(filepath: Optional[Path] = None) -> List[str]:
|
||||
"""Load proxies from file."""
|
||||
path = filepath or PROXIES_FILE
|
||||
if not path.exists():
|
||||
return []
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return [line.strip() for line in f if line.strip()]
|
||||
|
||||
|
||||
def save_valid_proxies(proxies: List[str]):
|
||||
"""Save validated proxies to their dedicated file."""
|
||||
save_proxies(proxies, VALID_PROXIES_FILE)
|
||||
|
||||
|
||||
def load_valid_proxies() -> List[str]:
|
||||
"""Load validated proxies."""
|
||||
return load_proxies(VALID_PROXIES_FILE)
|
||||
|
||||
|
||||
def count_lines(filepath: Path) -> int:
|
||||
"""Count non-empty lines in a file."""
|
||||
if not filepath.exists():
|
||||
return 0
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
return sum(1 for line in f if line.strip())
|
||||
116
src/utils/logger.py
Normal file
116
src/utils/logger.py
Normal file
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
Structured logging for the Facebook Recovery System.
|
||||
Provides both file logging and in-memory log capture for the GUI.
|
||||
"""
|
||||
import csv
|
||||
import logging
|
||||
import threading
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from config import ATTEMPT_LOG_FILE
|
||||
|
||||
|
||||
class AttemptLogger:
|
||||
"""Logs each login attempt to CSV and maintains an in-memory buffer for the GUI."""
|
||||
|
||||
def __init__(self, log_path: Optional[Path] = None):
|
||||
self.log_path = log_path or ATTEMPT_LOG_FILE
|
||||
self.buffer = [] # In-memory list of log entries for GUI display
|
||||
self._lock = threading.Lock()
|
||||
self._init_csv()
|
||||
|
||||
def _init_csv(self):
|
||||
"""Create CSV with headers if it doesn't exist."""
|
||||
if not self.log_path.exists():
|
||||
self.log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(self.log_path, "w", newline="") as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow([
|
||||
"timestamp", "password", "proxy_ip", "proxy_port",
|
||||
"proxy_protocol", "status_code", "result", "response_time_ms",
|
||||
"message",
|
||||
])
|
||||
|
||||
def log_attempt(
|
||||
self,
|
||||
password: str,
|
||||
proxy_ip: str,
|
||||
proxy_port: int,
|
||||
proxy_protocol: str,
|
||||
status_code: int,
|
||||
result: str,
|
||||
response_time_ms: float,
|
||||
message: str = "",
|
||||
):
|
||||
"""Log a single attempt."""
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
||||
entry = {
|
||||
"timestamp": timestamp,
|
||||
"password": password,
|
||||
"proxy_ip": proxy_ip,
|
||||
"proxy_port": proxy_port,
|
||||
"proxy_protocol": proxy_protocol,
|
||||
"status_code": status_code,
|
||||
"result": result,
|
||||
"response_time_ms": f"{response_time_ms:.1f}",
|
||||
"message": message,
|
||||
}
|
||||
with self._lock:
|
||||
# Write to CSV
|
||||
with open(self.log_path, "a", newline="") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=entry.keys())
|
||||
writer.writerow(entry)
|
||||
|
||||
# Keep in memory buffer (limit to last 10000 for performance)
|
||||
self.buffer.append(entry)
|
||||
if len(self.buffer) > 10000:
|
||||
self.buffer = self.buffer[-5000:]
|
||||
|
||||
def get_recent(self, count: int = 100) -> list:
|
||||
"""Get the most recent log entries."""
|
||||
with self._lock:
|
||||
return self.buffer[-count:]
|
||||
|
||||
def get_stats(self) -> dict:
|
||||
"""Get aggregate statistics from the log."""
|
||||
with self._lock:
|
||||
total = len(self.buffer)
|
||||
successes = sum(1 for e in self.buffer if e["result"] == "SUCCESS")
|
||||
failures = total - successes
|
||||
return {
|
||||
"total": total,
|
||||
"successes": successes,
|
||||
"failures": failures,
|
||||
}
|
||||
|
||||
|
||||
class FileLogger:
|
||||
"""General purpose file logger for system events."""
|
||||
|
||||
def __init__(self, name: str = "facebook_recovery"):
|
||||
self.logger = logging.getLogger(name)
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
|
||||
# Guard against adding duplicate handlers when re-instantiated
|
||||
if not self.logger.handlers:
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter(
|
||||
"[%(asctime)s] %(levelname)s: %(message)s",
|
||||
datefmt="%H:%M:%S"
|
||||
)
|
||||
ch.setFormatter(formatter)
|
||||
self.logger.addHandler(ch)
|
||||
|
||||
def info(self, msg: str):
|
||||
self.logger.info(msg)
|
||||
|
||||
def debug(self, msg: str):
|
||||
self.logger.debug(msg)
|
||||
|
||||
def warning(self, msg: str):
|
||||
self.logger.warning(msg)
|
||||
|
||||
def error(self, msg: str):
|
||||
self.logger.error(msg)
|
||||
Reference in New Issue
Block a user