From 0e0d054d5dde489aa942b7de26a8f90d2e82b4e6 Mon Sep 17 00:00:00 2001 From: Whispering Wind <151555003+ReturnFI@users.noreply.github.com> Date: Fri, 2 May 2025 17:21:26 +0330 Subject: [PATCH] Refactor: Warp setup and uninstallation scripts to Python3 --- core/cli_api.py | 8 +-- core/scripts/warp/install.py | 77 ++++++++++++++++++++++ core/scripts/warp/install.sh | 41 ------------ core/scripts/warp/uninstall.py | 117 +++++++++++++++++++++++++++++++++ core/scripts/warp/uninstall.sh | 43 ------------ 5 files changed, 198 insertions(+), 88 deletions(-) create mode 100644 core/scripts/warp/install.py delete mode 100644 core/scripts/warp/install.sh create mode 100644 core/scripts/warp/uninstall.py delete mode 100644 core/scripts/warp/uninstall.sh diff --git a/core/cli_api.py b/core/cli_api.py index 6a9867f..7245195 100644 --- a/core/cli_api.py +++ b/core/cli_api.py @@ -43,8 +43,8 @@ class Command(Enum): SHELL_WEBPANEL = os.path.join(SCRIPT_DIR, 'webpanel', 'webpanel_shell.sh') INSTALL_NORMALSUB = os.path.join(SCRIPT_DIR, 'normalsub', 'normalsub.sh') INSTALL_TCP_BRUTAL = os.path.join(SCRIPT_DIR, 'tcp-brutal', 'install.sh') - INSTALL_WARP = os.path.join(SCRIPT_DIR, 'warp', 'install.sh') - UNINSTALL_WARP = os.path.join(SCRIPT_DIR, 'warp', 'uninstall.sh') + INSTALL_WARP = os.path.join(SCRIPT_DIR, 'warp', 'install.py') + UNINSTALL_WARP = os.path.join(SCRIPT_DIR, 'warp', 'uninstall.py') CONFIGURE_WARP = os.path.join(SCRIPT_DIR, 'warp', 'configure.sh') STATUS_WARP = os.path.join(SCRIPT_DIR, 'warp', 'status.sh') SERVICES_STATUS = os.path.join(SCRIPT_DIR, 'services_status.sh') @@ -434,12 +434,12 @@ def install_tcp_brutal(): def install_warp(): '''Installs WARP.''' - run_cmd(['bash', Command.INSTALL_WARP.value]) + run_cmd(['python3', Command.INSTALL_WARP.value]) def uninstall_warp(): '''Uninstalls WARP.''' - run_cmd(['bash', Command.UNINSTALL_WARP.value]) + run_cmd(['python3', Command.UNINSTALL_WARP.value]) def configure_warp(all: bool, popular_sites: bool, domestic_sites: bool, block_adult_sites: bool, warp_option: str, warp_key: str): diff --git a/core/scripts/warp/install.py b/core/scripts/warp/install.py new file mode 100644 index 0000000..1dfcd30 --- /dev/null +++ b/core/scripts/warp/install.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +import subprocess +import sys +import json +from pathlib import Path +core_scripts_dir = Path(__file__).resolve().parents[1] + +if str(core_scripts_dir) not in sys.path: + sys.path.append(str(core_scripts_dir)) + +from paths import * + +WARP_DEVICE = "wgcf" + +def is_service_active(service_name: str) -> bool: + return subprocess.run(["systemctl", "is-active", "--quiet", service_name]).returncode == 0 + + +def install_warp(): + print("Installing WARP...") + result = subprocess.run("bash <(curl -fsSL https://raw.githubusercontent.com/ReturnFI/Warp/main/warp.sh) wgx", + shell=True, executable="/bin/bash") + return result.returncode == 0 + + +def add_warp_outbound_to_config(): + if not CONFIG_FILE.exists(): + print(f"Error: Config file {CONFIG_FILE} not found.") + return + + with open(CONFIG_FILE, "r") as f: + config = json.load(f) + + outbounds = config.get("outbounds", []) + if any(outbound.get("name") == "warps" for outbound in outbounds): + print("WARP outbound already exists in the configuration.") + return + + outbounds.append({ + "name": "warps", + "type": "direct", + "direct": { + "mode": 4, + "bindDevice": WARP_DEVICE + } + }) + config["outbounds"] = outbounds + + with open(CONFIG_FILE, "w") as f: + json.dump(config, f, indent=2) + + print("WARP outbound added to config.json.") + + +def restart_hysteria(): + subprocess.run(["python3", str(CLI_PATH), "restart-hysteria2"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + print("Hysteria2 restarted with updated configuration.") + + +def main(): + warp_service = f"wg-quick@{WARP_DEVICE}.service" + + if is_service_active(warp_service): + print("WARP is already active. Checking configuration...") + add_warp_outbound_to_config() + restart_hysteria() + else: + if install_warp() and is_service_active(warp_service): + print("WARP installation successful.") + add_warp_outbound_to_config() + restart_hysteria() + else: + print("WARP installation failed.") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/core/scripts/warp/install.sh b/core/scripts/warp/install.sh deleted file mode 100644 index ecd29e2..0000000 --- a/core/scripts/warp/install.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -source /etc/hysteria/core/scripts/path.sh - -if systemctl is-active --quiet wg-quick@wgcf.service; then - echo "WARP is already active. Checking configuration..." - - if [ -f "$CONFIG_FILE" ] && jq -e '.outbounds[] | select(.name == "warps")' "$CONFIG_FILE" > /dev/null 2>&1; then - echo "WARP outbound already exists in the configuration. No changes needed." - else - if [ -f "$CONFIG_FILE" ]; then - jq '.outbounds += [{"name": "warps", "type": "direct", "direct": {"mode": 4, "bindDevice": "wgcf"}}]' "$CONFIG_FILE" > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json "$CONFIG_FILE" - python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1 - echo "WARP outbound added to config.json." - else - echo "Error: Config file $CONFIG_FILE not found." - fi - fi -else - echo "Installing WARP..." - bash <(curl -fsSL https://raw.githubusercontent.com/ReturnFI/Warp/main/warp.sh) wgx - - if systemctl is-active --quiet wg-quick@wgcf.service; then - echo "WARP installation successful." - - if [ -f "$CONFIG_FILE" ]; then - if jq -e '.outbounds[] | select(.name == "warps")' "$CONFIG_FILE" > /dev/null 2>&1; then - echo "WARP outbound already exists in the configuration." - else - jq '.outbounds += [{"name": "warps", "type": "direct", "direct": {"mode": 4, "bindDevice": "wgcf"}}]' "$CONFIG_FILE" > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json "$CONFIG_FILE" - echo "WARP outbound added to config.json." - fi - python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1 - echo "Hysteria2 restarted with updated configuration." - else - echo "Error: Config file $CONFIG_FILE not found." - fi - else - echo "WARP installation failed." - fi -fi \ No newline at end of file diff --git a/core/scripts/warp/uninstall.py b/core/scripts/warp/uninstall.py new file mode 100644 index 0000000..f6b0d78 --- /dev/null +++ b/core/scripts/warp/uninstall.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 + +import subprocess +import json +import shutil +import sys +from pathlib import Path + +core_scripts_dir = Path(__file__).resolve().parents[1] + +if str(core_scripts_dir) not in sys.path: + sys.path.append(str(core_scripts_dir)) + +from paths import CONFIG_FILE, CLI_PATH + +TEMP_CONFIG = Path("/etc/hysteria/config_temp.json") + + +def systemctl_active(service: str) -> bool: + return subprocess.run(["systemctl", "is-active", "--quiet", service]).returncode == 0 + + +def run_shell(command: str): + subprocess.run(command, shell=True, check=False) + + +def load_config(path: Path): + if path.exists(): + with path.open("r", encoding="utf-8") as f: + return json.load(f) + print(f"โŒ Config file not found: {path}") + return None + + +def save_config(config: dict, path: Path): + with path.open("w", encoding="utf-8") as f: + json.dump(config, f, indent=2) + shutil.move(str(path), str(CONFIG_FILE)) + + +def reset_acl_inline(config: dict): + default = [ + "reject(geosite:ir)", "reject(geoip:ir)", + "reject(geosite:category-ads-all)", "reject(geoip:private)", + "reject(geosite:google@ads)" + ] + updated = [] + for item in config.get("acl", {}).get("inline", []): + if item in [ + "warps(all)", "warps(geoip:google)", "warps(geosite:google)", + "warps(geosite:netflix)", "warps(geosite:spotify)", + "warps(geosite:openai)", "warps(geoip:openai)" + ]: + updated.append("direct") + elif item == "warps(geosite:ir)": + updated.append("reject(geosite:ir)") + elif item == "warps(geoip:ir)": + updated.append("reject(geoip:ir)") + else: + updated.append(item) + + final_inline = default + [i for i in updated if i not in default and i != "direct"] + config["acl"]["inline"] = final_inline + return config + + +def remove_warp_outbound(config: dict): + config["outbounds"] = [ + o for o in config.get("outbounds", []) + if not ( + o.get("name") == "warps" and + o.get("type") == "direct" and + o.get("direct", {}).get("mode") == 4 and + o.get("direct", {}).get("bindDevice") == "wgcf" + ) + ] + return config + + +def remove_porn_blocking(config: dict): + inline = config.get("acl", {}).get("inline", []) + if "reject(geosite:category-porn)" in inline: + config["acl"]["inline"] = [i for i in inline if i != "reject(geosite:category-porn)"] + print("๐Ÿ”’ Adult content blocking removed.") + return config + + +def set_dns(config: dict): + config.setdefault("resolver", {}).setdefault("tls", {})["addr"] = "1.1.1.1:853" + print("๐Ÿ”ง DNS resolver changed to 1.1.1.1:853.") + return config + + +def restart_hysteria(): + subprocess.run(["python3", str(CLI_PATH), "restart-hysteria2"], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + +def main(): + if systemctl_active("wg-quick@wgcf.service"): + print("๐Ÿงน Uninstalling WARP...") + run_shell('bash -c "bash <(curl -fsSL https://raw.githubusercontent.com/ReturnFI/Warp/main/warp.sh) dwg"') + config = load_config(CONFIG_FILE) + if config: + config = reset_acl_inline(config) + config = remove_warp_outbound(config) + config = remove_porn_blocking(config) + config = set_dns(config) + save_config(config, TEMP_CONFIG) + restart_hysteria() + print("โœ… WARP uninstalled and configuration reset.") + else: + print("โ„น๏ธ WARP is not active. Skipping uninstallation.") + + +if __name__ == "__main__": + main() diff --git a/core/scripts/warp/uninstall.sh b/core/scripts/warp/uninstall.sh deleted file mode 100644 index 0e5baf0..0000000 --- a/core/scripts/warp/uninstall.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -source /etc/hysteria/core/scripts/path.sh - -if systemctl is-active --quiet wg-quick@wgcf.service; then - echo "Uninstalling WARP..." - bash <(curl -fsSL https://raw.githubusercontent.com/ReturnFI/Warp/main/warp.sh) dwg - - if [ -f "$CONFIG_FILE" ]; then - default_config='["reject(geosite:ir)", "reject(geoip:ir)", "reject(geosite:category-ads-all)", "reject(geoip:private)", "reject(geosite:google@ads)"]' - - jq --argjson default_config "$default_config" ' - .acl.inline |= map( - if . == "warps(all)" or . == "warps(geoip:google)" or . == "warps(geosite:google)" or . == "warps(geosite:netflix)" or . == "warps(geosite:spotify)" or . == "warps(geosite:openai)" or . == "warps(geoip:openai)" then - "direct" - elif . == "warps(geosite:ir)" then - "reject(geosite:ir)" - elif . == "warps(geoip:ir)" then - "reject(geoip:ir)" - else - . - end - ) | .acl.inline |= ($default_config + (. - $default_config | map(select(. != "direct")))) - ' "$CONFIG_FILE" > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json "$CONFIG_FILE" - - jq 'del(.outbounds[] | select(.name == "warps" and .type == "direct" and .direct.mode == 4 and .direct.bindDevice == "wgcf"))' "$CONFIG_FILE" > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json "$CONFIG_FILE" - - if [ "$(jq -r 'if .acl.inline | index("reject(geosite:category-porn)") then "Blocked" else "Not blocked" end' "$CONFIG_FILE")" == "Blocked" ]; then - jq 'del(.acl.inline[] | select(. == "reject(geosite:category-porn)"))' "$CONFIG_FILE" > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json "$CONFIG_FILE" - echo "Adult content blocking removed." - fi - - jq '.resolver.tls.addr = "1.1.1.1:853"' "$CONFIG_FILE" > /etc/hysteria/config_temp.json && mv /etc/hysteria/config_temp.json "$CONFIG_FILE" - echo "DNS resolver address changed to 1.1.1.1:853." - - python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1 - echo "WARP uninstalled and configurations reset to default." - else - echo "Error: Config file $CONFIG_FILE not found." - fi -else - echo "WARP is not active. Skipping uninstallation." -fi