Initial release: ghost_protocol privacy toolkit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
# phantom modules
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user