Refactor: Implement WARP ACL configuration in Python

- remove WARP Plus/Key
This commit is contained in:
Whispering Wind
2025-05-02 18:24:58 +03:30
committed by GitHub
parent 07cb999259
commit 9d0a13a226
7 changed files with 178 additions and 122 deletions

View File

@ -365,16 +365,13 @@ def uninstall_warp():
@click.option('--popular-sites', '-p', is_flag=True, help='Use WARP for popular sites like Google, OpenAI, etc') @click.option('--popular-sites', '-p', is_flag=True, help='Use WARP for popular sites like Google, OpenAI, etc')
@click.option('--domestic-sites', '-d', is_flag=True, help='Use WARP for Iran domestic sites') @click.option('--domestic-sites', '-d', is_flag=True, help='Use WARP for Iran domestic sites')
@click.option('--block-adult-sites', '-x', is_flag=True, help='Block adult content (porn)') @click.option('--block-adult-sites', '-x', is_flag=True, help='Block adult content (porn)')
@click.option('--warp-option', '-w', type=click.Choice(['warp', 'warp plus'], case_sensitive=False), help='Specify whether to use WARP or WARP Plus') def configure_warp(all: bool, popular_sites: bool, domestic_sites: bool, block_adult_sites: bool):
@click.option('--warp-key', '-k', help="WARP Plus key (required if warp-option is 'warp plus')")
def configure_warp(all: bool, popular_sites: bool, domestic_sites: bool, block_adult_sites: bool, warp_option: str, warp_key: str):
try: try:
cli_api.configure_warp(all, popular_sites, domestic_sites, block_adult_sites, warp_option, warp_key) cli_api.configure_warp(all, popular_sites, domestic_sites, block_adult_sites)
click.echo('WARP configured successfully.') click.echo('WARP configured successfully.')
except Exception as e: except Exception as e:
click.echo(f'{e}', err=True) click.echo(f'{e}', err=True)
@cli.command('warp-status') @cli.command('warp-status')
def warp_status(): def warp_status():
try: try:

View File

@ -45,7 +45,7 @@ class Command(Enum):
INSTALL_TCP_BRUTAL = os.path.join(SCRIPT_DIR, 'tcp-brutal', 'install.sh') INSTALL_TCP_BRUTAL = os.path.join(SCRIPT_DIR, 'tcp-brutal', 'install.sh')
INSTALL_WARP = os.path.join(SCRIPT_DIR, 'warp', 'install.py') INSTALL_WARP = os.path.join(SCRIPT_DIR, 'warp', 'install.py')
UNINSTALL_WARP = os.path.join(SCRIPT_DIR, 'warp', 'uninstall.py') UNINSTALL_WARP = os.path.join(SCRIPT_DIR, 'warp', 'uninstall.py')
CONFIGURE_WARP = os.path.join(SCRIPT_DIR, 'warp', 'configure.sh') CONFIGURE_WARP = os.path.join(SCRIPT_DIR, 'warp', 'configure.py')
STATUS_WARP = os.path.join(SCRIPT_DIR, 'warp', 'status.py') STATUS_WARP = os.path.join(SCRIPT_DIR, 'warp', 'status.py')
SERVICES_STATUS = os.path.join(SCRIPT_DIR, 'services_status.sh') SERVICES_STATUS = os.path.join(SCRIPT_DIR, 'services_status.sh')
VERSION = os.path.join(SCRIPT_DIR, 'hysteria2', 'version.py') VERSION = os.path.join(SCRIPT_DIR, 'hysteria2', 'version.py')
@ -442,30 +442,22 @@ def uninstall_warp():
run_cmd(['python3', 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): def configure_warp(all: bool, popular_sites: bool, domestic_sites: bool, block_adult_sites: bool):
''' '''
Configures WARP with various options. Configures WARP with various options.
''' '''
if warp_option == 'warp plus' and not warp_key:
raise InvalidInputError('Error: WARP Plus key is required when \'warp plus\' is selected.')
options = {
'all': 'true' if all else 'false',
'popular_sites': 'true' if popular_sites else 'false',
'domestic_sites': 'true' if domestic_sites else 'false',
'block_adult_sites': 'true' if block_adult_sites else 'false',
'warp_option': warp_option or '',
'warp_key': warp_key or ''
}
cmd_args = [ cmd_args = [
'bash', Command.CONFIGURE_WARP.value, 'python3', Command.CONFIGURE_WARP.value
options['all'],
options['popular_sites'],
options['domestic_sites'],
options['block_adult_sites'],
options['warp_option']
] ]
if options['warp_key']: if all:
cmd_args.append(options['warp_key']) cmd_args.append('--all')
if popular_sites:
cmd_args.append('--popular-sites')
if domestic_sites:
cmd_args.append('--domestic-sites')
if block_adult_sites:
cmd_args.append('--block-adult')
run_cmd(cmd_args) run_cmd(cmd_args)

View File

@ -0,0 +1,159 @@
#!/usr/bin/env python3
import json
import sys
import subprocess
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 *
def warp_configure_handler(all_traffic=False, popular_sites=False, domestic_sites=False, block_adult_sites=False):
"""
Configure WARP routing rules based on provided parameters
Args:
all_traffic (bool): Toggle WARP for all traffic
popular_sites (bool): Toggle WARP for popular sites (Google, Netflix, etc.)
domestic_sites (bool): Toggle between WARP and Reject for domestic sites
block_adult_sites (bool): Toggle blocking of adult content
"""
with open(CONFIG_FILE, 'r') as f:
config = json.load(f)
modified = False
if all_traffic:
warp_all_active = any(rule == "warps(all)" for rule in config.get('acl', {}).get('inline', []))
if warp_all_active:
config['acl']['inline'] = [rule for rule in config['acl']['inline'] if rule != "warps(all)"]
print("Traffic configuration changed to Direct.")
modified = True
else:
if 'acl' not in config:
config['acl'] = {}
if 'inline' not in config['acl']:
config['acl']['inline'] = []
config['acl']['inline'].append("warps(all)")
print("Traffic configuration changed to WARP.")
modified = True
if popular_sites:
popular_rules = [
"warps(geoip:google)",
"warps(geosite:google)",
"warps(geosite:netflix)",
"warps(geosite:spotify)",
"warps(geosite:openai)",
"warps(geoip:openai)"
]
rule_exists = any(rule in config.get('acl', {}).get('inline', []) for rule in popular_rules)
if rule_exists:
config['acl']['inline'] = [rule for rule in config['acl']['inline']
if rule not in popular_rules]
print("WARP configuration for Google, OpenAI, etc. removed.")
modified = True
else:
if 'acl' not in config:
config['acl'] = {}
if 'inline' not in config['acl']:
config['acl']['inline'] = []
config['acl']['inline'].extend(popular_rules)
print("WARP configured for Google, OpenAI, etc.")
modified = True
if domestic_sites:
ir_site_rule = "warps(geosite:ir)"
ir_ip_rule = "warps(geoip:ir)"
reject_site_rule = "reject(geosite:ir)"
reject_ip_rule = "reject(geoip:ir)"
using_warp = (ir_site_rule in config.get('acl', {}).get('inline', []) and
ir_ip_rule in config.get('acl', {}).get('inline', []))
using_reject = (reject_site_rule in config.get('acl', {}).get('inline', []) and
reject_ip_rule in config.get('acl', {}).get('inline', []))
if 'acl' not in config:
config['acl'] = {}
if 'inline' not in config['acl']:
config['acl']['inline'] = []
if using_warp:
config['acl']['inline'] = [reject_site_rule if rule == ir_site_rule else
reject_ip_rule if rule == ir_ip_rule else
rule for rule in config['acl']['inline']]
print("Configuration changed to Reject for geosite:ir and geoip:ir.")
modified = True
elif using_reject:
config['acl']['inline'] = [ir_site_rule if rule == reject_site_rule else
ir_ip_rule if rule == reject_ip_rule else
rule for rule in config['acl']['inline']]
print("Configuration changed to Use WARP for geosite:ir and geoip:ir.")
modified = True
else:
config['acl']['inline'].extend([reject_site_rule, reject_ip_rule])
print("Added Reject configuration for geosite:ir and geoip:ir.")
modified = True
if block_adult_sites:
nsfw_rule = "reject(geosite:nsfw)"
blocked = nsfw_rule in config.get('acl', {}).get('inline', [])
if blocked:
config['acl']['inline'] = [rule for rule in config['acl']['inline']
if rule != nsfw_rule]
if 'resolver' not in config:
config['resolver'] = {}
if 'tls' not in config['resolver']:
config['resolver']['tls'] = {}
config['resolver']['tls']['addr'] = "1.1.1.1:853"
print("Adult content blocking removed and resolver updated.")
modified = True
else:
if 'acl' not in config:
config['acl'] = {}
if 'inline' not in config['acl']:
config['acl']['inline'] = []
config['acl']['inline'].append(nsfw_rule)
if 'resolver' not in config:
config['resolver'] = {}
if 'tls' not in config['resolver']:
config['resolver']['tls'] = {}
config['resolver']['tls']['addr'] = "1.1.1.3:853"
print("Adult content blocked and resolver updated.")
modified = True
if modified:
with open(CONFIG_FILE, 'w') as f:
json.dump(config, f, indent=2)
try:
subprocess.run(["python3", CLI_PATH, "restart-hysteria2"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
except subprocess.CalledProcessError:
print("Warning: Failed to restart hysteria2")
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Configure WARP settings")
parser.add_argument("--all", action="store_true", help="Toggle WARP for all traffic")
parser.add_argument("--popular-sites", action="store_true", help="Toggle WARP for popular sites")
parser.add_argument("--domestic-sites", action="store_true", help="Toggle between WARP and Reject for domestic sites")
parser.add_argument("--block-adult", action="store_true", help="Toggle blocking of adult content")
args = parser.parse_args()
warp_configure_handler(
all_traffic=args.all,
popular_sites=args.popular_sites,
domestic_sites=args.domestic_sites,
block_adult_sites=args.block_adult
)

View File

@ -1,78 +0,0 @@
#!/bin/bash
source /etc/hysteria/core/scripts/path.sh
warp_configure_handler() {
local all=$1
local popular_sites=$2
local domestic_sites=$3
local block_adult_sites=$4
local warp_option=$5
local warp_key=$6
if [ "$all" == "true" ]; then
if [ "$(jq -r 'if .acl.inline | index("warps(all)") then "WARP active" else "Direct" end' "$CONFIG_FILE")" == "WARP active" ]; then
jq 'del(.acl.inline[] | select(. == "warps(all)"))' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
echo "Traffic configuration changed to Direct."
else
jq '.acl.inline += ["warps(all)"]' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
echo "Traffic configuration changed to WARP."
fi
fi
if [ "$popular_sites" == "true" ]; then
if [ "$(jq -r 'if (.acl.inline | index("warps(geoip:google)")) or (.acl.inline | index("warps(geosite:google)")) or (.acl.inline | index("warps(geosite:netflix)")) or (.acl.inline | index("warps(geosite:spotify)")) or (.acl.inline | index("warps(geosite:openai)")) or (.acl.inline | index("warps(geoip:openai)")) then "WARP active" else "Direct" end' "$CONFIG_FILE")" == "WARP active" ]; then
jq 'del(.acl.inline[] | select(. == "warps(geoip:google)" or . == "warps(geosite:google)" or . == "warps(geosite:netflix)" or . == "warps(geosite:spotify)" or . == "warps(geosite:openai)" or . == "warps(geoip:openai)"))' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
echo "WARP configuration for Google, OpenAI, etc. removed."
else
jq '.acl.inline += ["warps(geoip:google)", "warps(geosite:google)", "warps(geosite:netflix)", "warps(geosite:spotify)", "warps(geosite:openai)", "warps(geoip:openai)"]' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
echo "WARP configured for Google, OpenAI, etc."
fi
fi
if [ "$domestic_sites" == "true" ]; then
if [ "$(jq -r 'if (.acl.inline | index("warps(geosite:ir)")) and (.acl.inline | index("warps(geoip:ir)")) then "Use WARP" else "Reject" end' "$CONFIG_FILE")" == "Use WARP" ]; then
jq '(.acl.inline[] | select(. == "warps(geosite:ir)")) = "reject(geosite:ir)" | (.acl.inline[] | select(. == "warps(geoip:ir)")) = "reject(geoip:ir)"' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
echo "Configuration changed to Reject for geosite:ir and geoip:ir."
else
jq '(.acl.inline[] | select(. == "reject(geosite:ir)")) = "warps(geosite:ir)" | (.acl.inline[] | select(. == "reject(geoip:ir)")) = "warps(geoip:ir)"' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
echo "Configuration changed to Use WARP for geosite:ir and geoip:ir."
fi
fi
if [ "$block_adult_sites" == "true" ]; then
if [ "$(jq -r 'if .acl.inline | index("reject(geosite:nsfw)") then "Blocked" else "Not blocked" end' "$CONFIG_FILE")" == "Blocked" ]; then
jq 'del(.acl.inline[] | select(. == "reject(geosite:nsfw)"))' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
jq '.resolver.tls.addr = "1.1.1.1:853"' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
echo "Adult content blocking removed and resolver updated."
else
jq '.acl.inline += ["reject(geosite:nsfw)"]' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
jq '.resolver.tls.addr = "1.1.1.3:853"' "$CONFIG_FILE" > "${CONFIG_FILE}.temp" && mv "${CONFIG_FILE}.temp" "$CONFIG_FILE"
echo "Adult content blocked and resolver updated."
fi
fi
if [ "$warp_option" == "warp plus" ]; then
if [ -z "$warp_key" ]; then
echo "Error: WARP Plus key is required. Exiting."
exit 1
fi
cd /etc/warp/ || { echo "Failed to change directory to /etc/warp/"; exit 1; }
WGCF_LICENSE_KEY="$warp_key" wgcf update
if [ $? -ne 0 ]; then
echo "Error: Failed to update WARP Plus configuration."
exit 1
fi
elif [ "$warp_option" == "warp" ]; then
cd /etc/warp/ || { echo "Failed to change directory to /etc/warp/"; exit 1; }
rm wgcf-account.toml && yes | wgcf register
echo "WARP configured with a new account."
fi
python3 "$CLI_PATH" restart-hysteria2 > /dev/null 2>&1
}
warp_configure_handler "$1" "$2" "$3" "$4" "$5" "$6"

View File

@ -61,7 +61,7 @@ async def configure(body: ConfigureInputBody):
""" """
try: try:
cli_api.configure_warp(body.all, body.popular_sites, body.domestic_sites, cli_api.configure_warp(body.all, body.popular_sites, body.domestic_sites,
body.block_adult_sites, body.warp_option, body.warp_key) body.block_adult_sites)
return DetailResponse(detail='WARP configured successfully.') return DetailResponse(detail='WARP configured successfully.')
except Exception as e: except Exception as e:
raise HTTPException(status_code=400, detail=f'Error: {str(e)}') raise HTTPException(status_code=400, detail=f'Error: {str(e)}')

View File

@ -7,8 +7,6 @@ class ConfigureInputBody(BaseModel):
popular_sites: bool = False popular_sites: bool = False
domestic_sites: bool = False domestic_sites: bool = False
block_adult_sites: bool = False block_adult_sites: bool = False
warp_option: Literal['warp', 'warp plus', ''] = ''
warp_key: str = ''
class StatusResponse(BaseModel): class StatusResponse(BaseModel):

18
menu.sh
View File

@ -389,10 +389,8 @@ warp_configure_handler() {
echo "2. Use WARP for popular sites" echo "2. Use WARP for popular sites"
echo "3. Use WARP for domestic sites" echo "3. Use WARP for domestic sites"
echo "4. Block adult content" echo "4. Block adult content"
echo "5. WARP (Plus) Profile" echo "5. WARP Status Profile"
echo "6. WARP (Normal) Profile" echo "6. Change IP address"
echo "7. WARP Status Profile"
echo "8. Change IP address"
echo "0. Cancel" echo "0. Cancel"
read -p "Select an option: " option read -p "Select an option: " option
@ -403,22 +401,12 @@ warp_configure_handler() {
3) python3 $CLI_PATH configure-warp --domestic-sites ;; 3) python3 $CLI_PATH configure-warp --domestic-sites ;;
4) python3 $CLI_PATH configure-warp --block-adult-sites ;; 4) python3 $CLI_PATH configure-warp --block-adult-sites ;;
5) 5)
echo "Please enter your WARP Plus key:"
read -r warp_key
if [ -z "$warp_key" ]; then
echo "Error: WARP Plus key cannot be empty. Exiting."
return
fi
python3 $CLI_PATH configure-warp --warp-option "warp plus" --warp-key "$warp_key"
;;
6) python3 $CLI_PATH configure-warp --warp-option "warp" ;;
7)
ip=$(curl -s --interface wgcf --connect-timeout 0.5 http://v4.ident.me) ip=$(curl -s --interface wgcf --connect-timeout 0.5 http://v4.ident.me)
cd /etc/warp/ && wgcf status cd /etc/warp/ && wgcf status
echo echo
echo -e "${yellow}Warp IP :${NC} ${cyan}$ip ${NC}" ;; echo -e "${yellow}Warp IP :${NC} ${cyan}$ip ${NC}" ;;
8) 6)
old_ip=$(curl -s --interface wgcf --connect-timeout 0.5 http://v4.ident.me) old_ip=$(curl -s --interface wgcf --connect-timeout 0.5 http://v4.ident.me)
echo "Current IP address: $old_ip" echo "Current IP address: $old_ip"
echo "Restarting $service_name..." echo "Restarting $service_name..."