Fix all 47 bugs — hardened attack engine, UI/UX, proxy, CAPTCHA, config
This commit is contained in:
@@ -2,26 +2,92 @@
|
||||
File I/O utilities for reading/writing password lists and proxy lists.
|
||||
"""
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
from typing import Generator, Iterator, 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."""
|
||||
def save_passwords(passwords: List[str], filepath: Optional[Path] = None,
|
||||
append: bool = True, dedupe: bool = False):
|
||||
"""
|
||||
Save password list to file.
|
||||
|
||||
Args:
|
||||
passwords: list of passwords to save.
|
||||
filepath: destination path (default: PASSWORDS_FILE).
|
||||
append: append to existing file when True; overwrite when False.
|
||||
dedupe: when True, load existing file, union with new passwords,
|
||||
deduplicate (preserving order), then write back. (bug #18)
|
||||
"""
|
||||
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")
|
||||
if dedupe:
|
||||
existing = load_passwords(path)
|
||||
merged = list(dict.fromkeys(existing + passwords))
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
for pwd in merged:
|
||||
f.write(pwd + "\n")
|
||||
else:
|
||||
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."""
|
||||
"""
|
||||
Load passwords from file, stripping whitespace and removing empties.
|
||||
Deduplicates while preserving order. (bug #30)
|
||||
"""
|
||||
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()]
|
||||
lines = [line.strip() for line in f if line.strip()]
|
||||
# bug #30: deduplicate, preserve order
|
||||
return list(dict.fromkeys(lines))
|
||||
|
||||
|
||||
def stream_passwords(
|
||||
filepath: Optional[Path] = None,
|
||||
chunk_size: int = 1000,
|
||||
) -> Generator[List[str], None, None]:
|
||||
"""
|
||||
Streaming generator that yields lists of passwords in chunks.
|
||||
Avoids loading the full wordlist into RAM. (bug #4)
|
||||
|
||||
Usage:
|
||||
for chunk in stream_passwords():
|
||||
process(chunk)
|
||||
"""
|
||||
path = filepath or PASSWORDS_FILE
|
||||
if not path.exists():
|
||||
return
|
||||
chunk: List[str] = []
|
||||
seen = set()
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line and line not in seen:
|
||||
seen.add(line)
|
||||
chunk.append(line)
|
||||
if len(chunk) >= chunk_size:
|
||||
yield chunk
|
||||
chunk = []
|
||||
if chunk:
|
||||
yield chunk
|
||||
|
||||
|
||||
def count_passwords(filepath: Optional[Path] = None) -> int:
|
||||
"""Count deduplicated passwords without loading them all into RAM."""
|
||||
path = filepath or PASSWORDS_FILE
|
||||
if not path.exists():
|
||||
return 0
|
||||
seen = set()
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line:
|
||||
seen.add(line)
|
||||
return len(seen)
|
||||
|
||||
|
||||
def save_proxies(proxies: List[str], filepath: Optional[Path] = None):
|
||||
@@ -42,8 +108,19 @@ def load_proxies(filepath: Optional[Path] = None) -> List[str]:
|
||||
|
||||
|
||||
def save_valid_proxies(proxies: List[str]):
|
||||
"""Save validated proxies to their dedicated file."""
|
||||
save_proxies(proxies, VALID_PROXIES_FILE)
|
||||
"""
|
||||
Save validated proxies, merging with any existing file entries.
|
||||
Deduplicates before writing so committed proxies are never lost. (bug #12)
|
||||
"""
|
||||
path = VALID_PROXIES_FILE
|
||||
existing: List[str] = []
|
||||
if path.exists():
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
existing = [line.strip() for line in f if line.strip()]
|
||||
merged = list(dict.fromkeys(existing + proxies))
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
for proxy in merged:
|
||||
f.write(proxy + "\n")
|
||||
|
||||
|
||||
def load_valid_proxies() -> List[str]:
|
||||
|
||||
Reference in New Issue
Block a user