Initial release: ghost_protocol privacy toolkit

This commit is contained in:
ghost
2026-03-04 09:13:16 -05:00
commit 973cede31f
99 changed files with 12158 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
# phantom modules
+126
View File
@@ -0,0 +1,126 @@
"""All-in-one single-server deployment module.
Composes multiple services onto a single server with nginx reverse proxy
and TLS via Certbot. Includes clear warnings about single-server risks.
"""
CYAN = "\033[38;5;51m"
WHITE = "\033[38;5;255m"
GREY = "\033[38;5;244m"
YELLOW = "\033[38;5;214m"
RED = "\033[38;5;196m"
RESET = "\033[0m"
SERVICES = [
("matrix", "Matrix + Element", "Encrypted messaging"),
("vpn", "WireGuard VPN", "Private VPN server"),
("dns", "Pi-hole DNS", "Ad-blocking DNS"),
("cloud", "Nextcloud", "File sync (stub)"),
("vault", "Vaultwarden", "Password manager (stub)"),
("media", "Jellyfin", "Media server (stub)"),
]
def gather_config(config):
"""Gather all-in-one deployment configuration."""
# Risk warning
print(f"\n{RED} ╔═══════════════════════════════════════════════════════╗{RESET}")
print(f" {RED}{RESET} {YELLOW}WARNING: Single-Server Deployment{RESET} {RED}{RESET}")
print(f" {RED}{RESET} {RED}{RESET}")
print(f" {RED}{RESET} Running multiple services on one server means: {RED}{RESET}")
print(f" {RED}{RESET} - A compromise of one service risks ALL services {RED}{RESET}")
print(f" {RED}{RESET} - Resource contention between services {RED}{RESET}")
print(f" {RED}{RESET} - Single point of failure for all infrastructure {RED}{RESET}")
print(f" {RED}{RESET} - More complex backup and recovery {RED}{RESET}")
print(f" {RED}{RESET} {RED}{RESET}")
print(f" {RED}{RESET} For production use, prefer one service per server. {RED}{RESET}")
print(f" {RED}{RESET} This mode is intended for lab/testing or personal {RED}{RESET}")
print(f" {RED}{RESET} use where convenience outweighs isolation. {RED}{RESET}")
print(f" {RED}╚═══════════════════════════════════════════════════════╝{RESET}")
confirm = input(f"\n {YELLOW}Acknowledge risks and continue? [y/N]:{RESET} ").strip().lower()
if confirm != "y":
return None
# Service selection
print(f"\n{CYAN} ┌─ Select Services ────────────────────────────────────┐{RESET}")
for i, (svc_id, label, desc) in enumerate(SERVICES, 1):
print(f" {CYAN}{RESET} {WHITE}{i}{RESET}) {label:<20} {GREY}{desc}{RESET}")
print(f" {CYAN}└────────────────────────────────────────────────────────┘{RESET}")
selections = input(
f"\n {CYAN}Services to deploy (comma-separated, e.g. 1,2,3):{RESET} "
).strip()
selected_services = []
for s in selections.split(","):
s = s.strip()
try:
idx = int(s) - 1
if 0 <= idx < len(SERVICES):
selected_services.append(SERVICES[idx][0])
except ValueError:
pass
if not selected_services:
print(f" {RED}No services selected.{RESET}")
return None
# Warn about stub services
STUB_SERVICES = {"cloud", "vault", "media", "email"}
stubs_selected = [s for s in selected_services if s in STUB_SERVICES]
if stubs_selected:
stub_labels = {s[0]: s[1] for s in SERVICES}
print(f"\n {YELLOW}Warning: The following services are stubs (playbook not yet implemented):{RESET}")
for s in stubs_selected:
print(f" {YELLOW}- {stub_labels.get(s, s)}{RESET}")
proceed = input(f" {YELLOW}Continue anyway? [y/N]:{RESET} ").strip().lower()
if proceed != "y":
return None
config["services"] = selected_services
config["all_in_one"] = True
# Base domain for nginx vhosts
config["domain"] = input(
f"\n {CYAN}Base domain (e.g. example.com):{RESET} "
).strip()
if not config["domain"]:
print(f" {RED}Domain is required for reverse proxy.{RESET}")
return None
config["certbot_email"] = input(
f" {CYAN}Email for Let's Encrypt [{GREY}optional{RESET}]: "
).strip()
# Gather per-service configs
# Save base domain — each service stores config under its own prefixed keys
base_domain = config["domain"]
for svc in selected_services:
try:
mod = __import__(f"modules.{svc}", fromlist=[svc])
if hasattr(mod, "gather_config"):
# Set per-service subdomain default
svc_subdomains = {
"matrix": f"matrix.{base_domain}",
"cloud": f"cloud.{base_domain}",
"vault": f"vault.{base_domain}",
"media": f"media.{base_domain}",
"email": f"mail.{base_domain}",
"dns": f"dns.{base_domain}",
"vpn": base_domain,
}
if svc in svc_subdomains:
config["domain"] = svc_subdomains[svc]
config = mod.gather_config(config)
if config is None:
return None
except ImportError:
pass # Stub module, skip
# Restore base domain
config["domain"] = base_domain
config["nginx_reverse_proxy"] = True
config["certbot_enabled"] = bool(config.get("certbot_email"))
return config
+27
View File
@@ -0,0 +1,27 @@
"""Nextcloud deployment module (stub — playbook TODO)."""
CYAN = "\033[38;5;51m"
WHITE = "\033[38;5;255m"
GREY = "\033[38;5;244m"
RESET = "\033[0m"
def gather_config(config):
"""Gather Nextcloud configuration."""
print(f"\n{CYAN} ┌─ Nextcloud Configuration ─────────────────────────┐{RESET}")
print(f" {CYAN}{RESET} {GREY}Note: Playbook coming soon{RESET}")
config["domain"] = config.get("domain") or input(
f" {CYAN}{RESET} Domain (e.g. cloud.example.com): "
).strip()
config["cloud_admin_user"] = input(
f" {CYAN}{RESET} Admin username [{WHITE}admin{RESET}]: "
).strip() or "admin"
config["cloud_storage_gb"] = input(
f" {CYAN}{RESET} Storage quota per user (GB) [{WHITE}10{RESET}]: "
).strip() or "10"
print(f" {CYAN}└─────────────────────────────────────────────────────┘{RESET}")
return config
+49
View File
@@ -0,0 +1,49 @@
"""Pi-hole / AdGuard DNS server deployment module."""
CYAN = "\033[38;5;51m"
WHITE = "\033[38;5;255m"
GREY = "\033[38;5;244m"
YELLOW = "\033[38;5;214m"
RESET = "\033[0m"
def gather_config(config):
"""Gather DNS server configuration."""
print(f"\n{CYAN} ┌─ DNS Server Configuration ────────────────────────┐{RESET}")
print(f" {CYAN}{RESET} Upstream DNS provider:")
print(f" {CYAN}{RESET} {WHITE}1{RESET}) Quad9 (9.9.9.9) — security-focused")
print(f" {CYAN}{RESET} {WHITE}2{RESET}) Cloudflare (1.1.1.1) — privacy-focused")
print(f" {CYAN}{RESET} {WHITE}3{RESET}) Custom")
dns_choice = input(f" {CYAN}{RESET} Choice [{WHITE}1{RESET}]: ").strip() or "1"
if dns_choice == "1":
config["dns_upstream"] = "9.9.9.9;149.112.112.112"
config["dns_upstream_name"] = "Quad9"
elif dns_choice == "2":
config["dns_upstream"] = "1.1.1.1;1.0.0.1"
config["dns_upstream_name"] = "Cloudflare"
else:
config["dns_upstream"] = input(
f" {CYAN}{RESET} Custom DNS (semicolon-separated): "
).strip()
config["dns_upstream_name"] = "Custom"
config["dns_domain"] = input(
f" {CYAN}{RESET} Admin interface domain (optional): "
).strip()
print(f" {CYAN}{RESET}")
print(f" {CYAN}{RESET} Blocklist presets:")
print(f" {CYAN}{RESET} {WHITE}1{RESET}) Standard (ads + trackers)")
print(f" {CYAN}{RESET} {WHITE}2{RESET}) Aggressive (+ social media trackers)")
print(f" {CYAN}{RESET} {WHITE}3{RESET}) Minimal (ads only)")
bl_choice = input(f" {CYAN}{RESET} Choice [{WHITE}1{RESET}]: ").strip() or "1"
config["dns_blocklist"] = {"1": "standard", "2": "aggressive", "3": "minimal"}.get(
bl_choice, "standard"
)
print(f" {CYAN}└─────────────────────────────────────────────────────┘{RESET}")
return config
+23
View File
@@ -0,0 +1,23 @@
"""Mail-in-a-Box deployment module (stub — playbook TODO)."""
CYAN = "\033[38;5;51m"
WHITE = "\033[38;5;255m"
GREY = "\033[38;5;244m"
RESET = "\033[0m"
def gather_config(config):
"""Gather Mail-in-a-Box configuration."""
print(f"\n{CYAN} ┌─ Mail-in-a-Box Configuration ─────────────────────┐{RESET}")
print(f" {CYAN}{RESET} {GREY}Note: Playbook coming soon{RESET}")
config["domain"] = config.get("domain") or input(
f" {CYAN}{RESET} Mail domain (e.g. mail.example.com): "
).strip()
config["email_first_user"] = input(
f" {CYAN}{RESET} First email user (e.g. admin@example.com): "
).strip()
print(f" {CYAN}└─────────────────────────────────────────────────────┘{RESET}")
return config
+47
View File
@@ -0,0 +1,47 @@
"""Matrix + Element homeserver deployment module."""
import getpass
import secrets
CYAN = "\033[38;5;51m"
WHITE = "\033[38;5;255m"
GREY = "\033[38;5;244m"
RESET = "\033[0m"
def gather_config(config):
"""Gather Matrix/Synapse + Element configuration."""
print(f"\n{CYAN} ┌─ Matrix Homeserver Configuration ─────────────────┐{RESET}")
config["domain"] = config.get("domain") or input(
f" {CYAN}{RESET} Domain (e.g. matrix.example.com): "
).strip()
if not config["domain"]:
print(f" {CYAN}{RESET} Domain is required.")
return None
config["matrix_admin_user"] = input(
f" {CYAN}{RESET} Admin username [{WHITE}admin{RESET}]: "
).strip() or "admin"
config["matrix_admin_password"] = getpass.getpass(
f" {CYAN}{RESET} Admin password (blank=generate): "
) or secrets.token_urlsafe(20)
config["matrix_registration"] = input(
f" {CYAN}{RESET} Open registration? [{WHITE}no{RESET}]: "
).strip().lower()
config["matrix_registration"] = config["matrix_registration"] in ("yes", "y", "true")
config["matrix_element_web"] = input(
f" {CYAN}{RESET} Deploy Element Web? [{WHITE}yes{RESET}]: "
).strip().lower()
config["matrix_element_web"] = config["matrix_element_web"] not in ("no", "n", "false")
config["matrix_server_name"] = config["domain"].replace("matrix.", "", 1) \
if config["domain"].startswith("matrix.") else config["domain"]
config["matrix_signing_key"] = secrets.token_hex(32)
print(f" {CYAN}└─────────────────────────────────────────────────────┘{RESET}")
return config
+23
View File
@@ -0,0 +1,23 @@
"""Jellyfin media server deployment module (stub — playbook TODO)."""
CYAN = "\033[38;5;51m"
WHITE = "\033[38;5;255m"
GREY = "\033[38;5;244m"
RESET = "\033[0m"
def gather_config(config):
"""Gather Jellyfin configuration."""
print(f"\n{CYAN} ┌─ Jellyfin Configuration ──────────────────────────┐{RESET}")
print(f" {CYAN}{RESET} {GREY}Note: Playbook coming soon{RESET}")
config["domain"] = config.get("domain") or input(
f" {CYAN}{RESET} Domain (e.g. media.example.com): "
).strip()
config["media_library_path"] = input(
f" {CYAN}{RESET} Media library path [{WHITE}/srv/media{RESET}]: "
).strip() or "/srv/media"
print(f" {CYAN}└─────────────────────────────────────────────────────┘{RESET}")
return config
+29
View File
@@ -0,0 +1,29 @@
"""Vaultwarden (Bitwarden) deployment module (stub — playbook TODO)."""
import secrets
CYAN = "\033[38;5;51m"
WHITE = "\033[38;5;255m"
GREY = "\033[38;5;244m"
RESET = "\033[0m"
def gather_config(config):
"""Gather Vaultwarden configuration."""
print(f"\n{CYAN} ┌─ Vaultwarden Configuration ───────────────────────┐{RESET}")
print(f" {CYAN}{RESET} {GREY}Note: Playbook coming soon{RESET}")
config["domain"] = config.get("domain") or input(
f" {CYAN}{RESET} Domain (e.g. vault.example.com): "
).strip()
config["vault_admin_token"] = input(
f" {CYAN}{RESET} Admin token (blank=generate): "
).strip() or secrets.token_urlsafe(32)
config["vault_signups_allowed"] = input(
f" {CYAN}{RESET} Allow signups? [{WHITE}no{RESET}]: "
).strip().lower() in ("yes", "y", "true")
print(f" {CYAN}└─────────────────────────────────────────────────────┘{RESET}")
return config
+39
View File
@@ -0,0 +1,39 @@
"""WireGuard VPN server deployment module."""
CYAN = "\033[38;5;51m"
WHITE = "\033[38;5;255m"
GREY = "\033[38;5;244m"
RESET = "\033[0m"
def gather_config(config):
"""Gather WireGuard VPN configuration."""
print(f"\n{CYAN} ┌─ WireGuard VPN Configuration ──────────────────────┐{RESET}")
config["vpn_port"] = input(
f" {CYAN}{RESET} Listen port [{WHITE}51820{RESET}]: "
).strip() or "51820"
config["vpn_client_count"] = input(
f" {CYAN}{RESET} Number of client configs [{WHITE}3{RESET}]: "
).strip() or "3"
try:
config["vpn_client_count"] = int(config["vpn_client_count"])
except ValueError:
config["vpn_client_count"] = 3
config["vpn_dns"] = input(
f" {CYAN}{RESET} Client DNS server [{WHITE}1.1.1.1{RESET}]: "
).strip() or "1.1.1.1"
config["vpn_allowed_ips"] = input(
f" {CYAN}{RESET} Allowed IPs [{WHITE}0.0.0.0/0, ::/0{RESET}]: "
).strip() or "0.0.0.0/0, ::/0"
config["vpn_subnet"] = input(
f" {CYAN}{RESET} VPN subnet [{WHITE}10.66.66.0/24{RESET}]: "
).strip() or "10.66.66.0/24"
print(f" {CYAN}└─────────────────────────────────────────────────────┘{RESET}")
return config