v1
This commit is contained in:
536
config.py
Normal file
536
config.py
Normal file
@@ -0,0 +1,536 @@
|
||||
# v6
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
APP_NAME = "Discord Client"
|
||||
APP_VERSION = "1.0.0"
|
||||
|
||||
START_URL = "https://discord.com/app"
|
||||
|
||||
WINDOW_WIDTH = 1400
|
||||
WINDOW_HEIGHT = 900
|
||||
|
||||
LOG_LEVEL = logging.INFO
|
||||
|
||||
BASE_DIR = Path.home() / ".discord-client"
|
||||
|
||||
DATABASE_PATH = BASE_DIR / "client.db"
|
||||
SETTINGS_FILE = BASE_DIR / "settings.json"
|
||||
|
||||
PROFILES_DIR = BASE_DIR / "profiles"
|
||||
DOWNLOADS_DIR = BASE_DIR / "downloads"
|
||||
LOGS_DIR = BASE_DIR / "logs"
|
||||
|
||||
THEMES_DIR = BASE_DIR / "themes"
|
||||
EXTENSIONS_DIR = BASE_DIR / "extensions"
|
||||
|
||||
EXPORTS_DIR = BASE_DIR / "exports"
|
||||
HAR_DIR = EXPORTS_DIR / "har"
|
||||
|
||||
DEFAULT_PROFILE = "default"
|
||||
|
||||
NETWORK_RETENTION = 100_000
|
||||
NETWORK_BATCH_SIZE = 100
|
||||
NETWORK_FLUSH_INTERVAL = 1.0
|
||||
|
||||
|
||||
DISCORD_TELEMETRY_BLOCKS = [
|
||||
"sentry.io",
|
||||
"www.sentry.io",
|
||||
"crash.discord.com",
|
||||
"telemetry.discord.com",
|
||||
"api.statsig.com",
|
||||
"segment.io",
|
||||
"cdn.segment.com",
|
||||
]
|
||||
|
||||
DEFAULT_PROXY = {
|
||||
"enabled": False,
|
||||
"proxy_type": "http",
|
||||
"host": "",
|
||||
"port": 0,
|
||||
"username": "",
|
||||
"password": "",
|
||||
}
|
||||
|
||||
DEFAULT_TRAY = {
|
||||
"enabled": True,
|
||||
"minimize_to_tray": True,
|
||||
"close_to_tray": True,
|
||||
}
|
||||
|
||||
DEFAULT_DEVTOOLS = {
|
||||
"enabled": True,
|
||||
"capture_requests": True,
|
||||
"capture_responses": True,
|
||||
"capture_bodies": False,
|
||||
"auto_open": False,
|
||||
}
|
||||
|
||||
DEFAULT_PERMISSIONS = {
|
||||
"microphone": False,
|
||||
"camera": False,
|
||||
"notifications": False,
|
||||
"clipboard": False,
|
||||
}
|
||||
|
||||
DEFAULT_SETTINGS: dict[str, Any] = {
|
||||
"active_profile": DEFAULT_PROFILE,
|
||||
"window_width": WINDOW_WIDTH,
|
||||
"window_height": WINDOW_HEIGHT,
|
||||
"download_directory": str(DOWNLOADS_DIR),
|
||||
"blocked_hosts": list(
|
||||
DISCORD_TELEMETRY_BLOCKS
|
||||
),
|
||||
"network_logging": True,
|
||||
"enable_cdp": False,
|
||||
"enable_vencord": False,
|
||||
"permissions": DEFAULT_PERMISSIONS,
|
||||
"proxy": DEFAULT_PROXY,
|
||||
"tray": DEFAULT_TRAY,
|
||||
"devtools": DEFAULT_DEVTOOLS,
|
||||
"blocklist_mode": "pro",
|
||||
"disabled_blocklists": [],
|
||||
}
|
||||
|
||||
FEATURE_PERMISSION_MAP = {
|
||||
"MediaAudioCapture": "microphone",
|
||||
"MediaVideoCapture": "camera",
|
||||
"MediaAudioVideoCapture": "camera",
|
||||
"Notifications": "notifications",
|
||||
"ClipboardReadWrite": "clipboard",
|
||||
"ClipboardSanitizedWrite": "clipboard",
|
||||
}
|
||||
|
||||
PLUGIN_FILE_PATTERN = "*.plugin.js"
|
||||
|
||||
PLUGIN_MAX_SIZE = 5 * 1024 * 1024
|
||||
|
||||
PLUGIN_CRASH_LIMIT = 5
|
||||
|
||||
PLUGIN_AUTOLOAD = True
|
||||
|
||||
PLUGIN_ALLOWED_EXTENSIONS = {
|
||||
".plugin.js",
|
||||
}
|
||||
|
||||
PLUGIN_ALLOWED_SCHEMES = {
|
||||
"https",
|
||||
}
|
||||
|
||||
PLUGIN_BLOCKED_PATTERNS = {
|
||||
"child_process.exec(",
|
||||
"child_process.spawn(",
|
||||
"powershell.exe",
|
||||
"cmd.exe /c",
|
||||
"process.exec(",
|
||||
}
|
||||
PLUGIN_PERMISSIONS = {
|
||||
"storage",
|
||||
"dom",
|
||||
"network",
|
||||
"websocket",
|
||||
"notifications",
|
||||
"clipboard",
|
||||
}
|
||||
PROFILE_EXPORT_VERSION = 1
|
||||
|
||||
PROFILE_EXPORT_NAME = (
|
||||
"profilebundle"
|
||||
)
|
||||
|
||||
# v1
|
||||
BLOCKLISTS_DIR = (
|
||||
BASE_DIR
|
||||
/ "blocklists"
|
||||
)
|
||||
|
||||
BLOCKLIST_CACHE_DIR = (
|
||||
BLOCKLISTS_DIR
|
||||
/ "cache"
|
||||
)
|
||||
def blocklists_dir(
|
||||
) -> Path:
|
||||
BLOCKLISTS_DIR.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
return BLOCKLISTS_DIR
|
||||
|
||||
|
||||
# v1
|
||||
def blocklist_cache_dir(
|
||||
) -> Path:
|
||||
BLOCKLIST_CACHE_DIR.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
return BLOCKLIST_CACHE_DIR
|
||||
|
||||
def ensure_directories() -> None:
|
||||
for directory in (
|
||||
BASE_DIR,
|
||||
PROFILES_DIR,
|
||||
DOWNLOADS_DIR,
|
||||
LOGS_DIR,
|
||||
THEMES_DIR,
|
||||
EXTENSIONS_DIR,
|
||||
EXPORTS_DIR,
|
||||
HAR_DIR,
|
||||
BLOCKLISTS_DIR,
|
||||
BLOCKLIST_CACHE_DIR,
|
||||
):
|
||||
directory.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
def merge_dict(
|
||||
defaults: dict,
|
||||
current: dict,
|
||||
) -> dict:
|
||||
merged = dict(defaults)
|
||||
|
||||
for key, value in current.items():
|
||||
if (
|
||||
key in merged
|
||||
and isinstance(
|
||||
merged[key],
|
||||
dict,
|
||||
)
|
||||
and isinstance(
|
||||
value,
|
||||
dict,
|
||||
)
|
||||
):
|
||||
merged[key] = merge_dict(
|
||||
merged[key],
|
||||
value,
|
||||
)
|
||||
else:
|
||||
merged[key] = value
|
||||
|
||||
return merged
|
||||
|
||||
|
||||
def _normalize_proxy(
|
||||
settings: dict[str, Any],
|
||||
) -> None:
|
||||
proxy = settings.get(
|
||||
"proxy",
|
||||
{},
|
||||
)
|
||||
|
||||
if not isinstance(
|
||||
proxy,
|
||||
dict,
|
||||
):
|
||||
settings["proxy"] = dict(
|
||||
DEFAULT_PROXY
|
||||
)
|
||||
return
|
||||
|
||||
if (
|
||||
"type" in proxy
|
||||
and "proxy_type"
|
||||
not in proxy
|
||||
):
|
||||
proxy["proxy_type"] = proxy.pop(
|
||||
"type"
|
||||
)
|
||||
|
||||
settings["proxy"] = merge_dict(
|
||||
DEFAULT_PROXY,
|
||||
proxy,
|
||||
)
|
||||
|
||||
|
||||
def _normalize_permissions(
|
||||
settings: dict[str, Any],
|
||||
) -> None:
|
||||
permissions = settings.get(
|
||||
"permissions",
|
||||
{},
|
||||
)
|
||||
|
||||
if not isinstance(
|
||||
permissions,
|
||||
dict,
|
||||
):
|
||||
permissions = {}
|
||||
|
||||
settings["permissions"] = merge_dict(
|
||||
DEFAULT_PERMISSIONS,
|
||||
permissions,
|
||||
)
|
||||
|
||||
|
||||
def _normalize_blocked_hosts(
|
||||
settings: dict[str, Any],
|
||||
) -> None:
|
||||
hosts = {
|
||||
str(host)
|
||||
.strip()
|
||||
.lower()
|
||||
for host in settings.get(
|
||||
"blocked_hosts",
|
||||
[],
|
||||
)
|
||||
if str(host).strip()
|
||||
}
|
||||
|
||||
hosts.update(
|
||||
DISCORD_TELEMETRY_BLOCKS
|
||||
)
|
||||
|
||||
settings["blocked_hosts"] = sorted(
|
||||
hosts
|
||||
)
|
||||
|
||||
|
||||
def load_settings() -> dict[str, Any]:
|
||||
ensure_directories()
|
||||
|
||||
if not SETTINGS_FILE.exists():
|
||||
settings = merge_dict(
|
||||
{},
|
||||
DEFAULT_SETTINGS,
|
||||
)
|
||||
|
||||
save_settings(
|
||||
settings
|
||||
)
|
||||
|
||||
return settings
|
||||
|
||||
try:
|
||||
loaded = json.loads(
|
||||
SETTINGS_FILE.read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
)
|
||||
|
||||
if not isinstance(
|
||||
loaded,
|
||||
dict,
|
||||
):
|
||||
raise ValueError
|
||||
|
||||
if (
|
||||
"active_profile"
|
||||
not in loaded
|
||||
and "active_account"
|
||||
in loaded
|
||||
):
|
||||
loaded[
|
||||
"active_profile"
|
||||
] = loaded[
|
||||
"active_account"
|
||||
]
|
||||
|
||||
settings = merge_dict(
|
||||
DEFAULT_SETTINGS,
|
||||
loaded,
|
||||
)
|
||||
|
||||
if not settings.get(
|
||||
"active_profile"
|
||||
):
|
||||
settings[
|
||||
"active_profile"
|
||||
] = DEFAULT_PROFILE
|
||||
|
||||
settings[
|
||||
"download_directory"
|
||||
] = str(
|
||||
settings.get(
|
||||
"download_directory"
|
||||
)
|
||||
or DOWNLOADS_DIR
|
||||
)
|
||||
|
||||
_normalize_proxy(
|
||||
settings
|
||||
)
|
||||
|
||||
_normalize_permissions(
|
||||
settings
|
||||
)
|
||||
|
||||
_normalize_blocked_hosts(
|
||||
settings
|
||||
)
|
||||
|
||||
return settings
|
||||
|
||||
except Exception:
|
||||
settings = merge_dict(
|
||||
{},
|
||||
DEFAULT_SETTINGS,
|
||||
)
|
||||
|
||||
save_settings(
|
||||
settings
|
||||
)
|
||||
|
||||
return settings
|
||||
|
||||
|
||||
def save_settings(
|
||||
settings: dict[str, Any],
|
||||
) -> None:
|
||||
ensure_directories()
|
||||
|
||||
_normalize_proxy(
|
||||
settings
|
||||
)
|
||||
|
||||
_normalize_permissions(
|
||||
settings
|
||||
)
|
||||
|
||||
_normalize_blocked_hosts(
|
||||
settings
|
||||
)
|
||||
|
||||
SETTINGS_FILE.write_text(
|
||||
json.dumps(
|
||||
settings,
|
||||
indent=2,
|
||||
sort_keys=True,
|
||||
ensure_ascii=False,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
|
||||
def profile_root(
|
||||
profile_name: str,
|
||||
) -> Path:
|
||||
profile_name = (
|
||||
str(profile_name).strip()
|
||||
or DEFAULT_PROFILE
|
||||
)
|
||||
|
||||
root = (
|
||||
PROFILES_DIR
|
||||
/ profile_name
|
||||
)
|
||||
|
||||
root.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
return root
|
||||
|
||||
|
||||
def profile_paths(
|
||||
profile_name: str,
|
||||
) -> tuple[Path, Path]:
|
||||
root = profile_root(
|
||||
profile_name
|
||||
)
|
||||
|
||||
storage = root / "storage"
|
||||
cache = root / "cache"
|
||||
|
||||
storage.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
cache.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
return (
|
||||
storage,
|
||||
cache,
|
||||
)
|
||||
|
||||
|
||||
def profile_theme_dir(
|
||||
profile_name: str,
|
||||
) -> Path:
|
||||
path = (
|
||||
THEMES_DIR
|
||||
/ profile_name
|
||||
)
|
||||
|
||||
path.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
return path
|
||||
|
||||
|
||||
def profile_extension_dir(
|
||||
profile_name: str,
|
||||
) -> Path:
|
||||
path = (
|
||||
EXTENSIONS_DIR
|
||||
/ profile_name
|
||||
)
|
||||
|
||||
path.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
return path
|
||||
|
||||
|
||||
def profile_vencord_dir(
|
||||
profile_name: str,
|
||||
) -> Path:
|
||||
path = (
|
||||
profile_root(
|
||||
profile_name
|
||||
)
|
||||
/ "vencord"
|
||||
)
|
||||
|
||||
path.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
for child in (
|
||||
"plugins",
|
||||
"themes",
|
||||
"logs",
|
||||
):
|
||||
(
|
||||
path / child
|
||||
).mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
return path
|
||||
|
||||
|
||||
def profile_plugin_dir(
|
||||
profile_name: str,
|
||||
) -> Path:
|
||||
root = (
|
||||
profile_vencord_dir(
|
||||
profile_name
|
||||
)
|
||||
/ "plugins"
|
||||
)
|
||||
|
||||
root.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
return root
|
||||
Reference in New Issue
Block a user