feat: Add WARP management tab to settings page
Integrates WARP (install, uninstall, configure, status) functionality into the web panel's settings page. Users can now manage WARP directly from the UI.
This commit is contained in:
29
core/cli.py
29
core/cli.py
@ -367,16 +367,29 @@ def uninstall_warp():
|
|||||||
|
|
||||||
|
|
||||||
@cli.command('configure-warp')
|
@cli.command('configure-warp')
|
||||||
@click.option('--all', '-a', is_flag=True, help='Use WARP for all connections')
|
@click.option('--set-all', 'set_all_traffic', type=click.Choice(['on', 'off']), help='Set WARP for all connections (on/off)', required=False)
|
||||||
@click.option('--popular-sites', '-p', is_flag=True, help='Use WARP for popular sites like Google, OpenAI, etc')
|
@click.option('--set-popular-sites', type=click.Choice(['on', 'off']), help='Set WARP for popular sites (on/off)', required=False)
|
||||||
@click.option('--domestic-sites', '-d', is_flag=True, help='Use WARP for Iran domestic sites')
|
@click.option('--set-domestic-sites', type=click.Choice(['on', 'off']), help='Set behavior for domestic sites (on=WARP, off=REJECT)', required=False)
|
||||||
@click.option('--block-adult-sites', '-x', is_flag=True, help='Block adult content (porn)')
|
@click.option('--set-block-adult-sites', type=click.Choice(['on', 'off']), help='Set block adult content (on/off)', required=False)
|
||||||
def configure_warp(all: bool, popular_sites: bool, domestic_sites: bool, block_adult_sites: bool):
|
def configure_warp_cmd(set_all_traffic: str | None,
|
||||||
|
set_popular_sites: str | None,
|
||||||
|
set_domestic_sites: str | None,
|
||||||
|
set_block_adult_sites: str | None):
|
||||||
|
if not any([set_all_traffic, set_popular_sites, set_domestic_sites, set_block_adult_sites]):
|
||||||
|
click.echo("Error: At least one configuration option must be provided to configure-warp.", err=True)
|
||||||
|
click.echo("Use --help for more information.")
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cli_api.configure_warp(all, popular_sites, domestic_sites, block_adult_sites)
|
cli_api.configure_warp(
|
||||||
click.echo('WARP configured successfully.')
|
all_state=set_all_traffic,
|
||||||
|
popular_sites_state=set_popular_sites,
|
||||||
|
domestic_sites_state=set_domestic_sites,
|
||||||
|
block_adult_sites_state=set_block_adult_sites
|
||||||
|
)
|
||||||
|
click.echo('WARP configuration update process initiated.')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
click.echo(f'{e}', err=True)
|
click.echo(f'Error configuring WARP: {e}', err=True)
|
||||||
|
|
||||||
@cli.command('warp-status')
|
@cli.command('warp-status')
|
||||||
def warp_status():
|
def warp_status():
|
||||||
|
|||||||
@ -462,21 +462,28 @@ 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):
|
def configure_warp(all_state: str | None = None,
|
||||||
|
popular_sites_state: str | None = None,
|
||||||
|
domestic_sites_state: str | None = None,
|
||||||
|
block_adult_sites_state: str | None = None):
|
||||||
'''
|
'''
|
||||||
Configures WARP with various options.
|
Configures WARP with various options. States are 'on' or 'off'.
|
||||||
'''
|
'''
|
||||||
cmd_args = [
|
cmd_args = [
|
||||||
'python3', Command.CONFIGURE_WARP.value
|
'python3', Command.CONFIGURE_WARP.value
|
||||||
]
|
]
|
||||||
if all:
|
if all_state:
|
||||||
cmd_args.append('--all')
|
cmd_args.extend(['--set-all', all_state])
|
||||||
if popular_sites:
|
if popular_sites_state:
|
||||||
cmd_args.append('--popular-sites')
|
cmd_args.extend(['--set-popular-sites', popular_sites_state])
|
||||||
if domestic_sites:
|
if domestic_sites_state:
|
||||||
cmd_args.append('--domestic-sites')
|
cmd_args.extend(['--set-domestic-sites', domestic_sites_state])
|
||||||
if block_adult_sites:
|
if block_adult_sites_state:
|
||||||
cmd_args.append('--block-adult')
|
cmd_args.extend(['--set-block-adult', block_adult_sites_state])
|
||||||
|
|
||||||
|
if len(cmd_args) == 2:
|
||||||
|
print("No WARP configuration options provided to cli_api.configure_warp.")
|
||||||
|
return
|
||||||
|
|
||||||
run_cmd(cmd_args)
|
run_cmd(cmd_args)
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import json
|
|||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
|
||||||
core_scripts_dir = Path(__file__).resolve().parents[1]
|
core_scripts_dir = Path(__file__).resolve().parents[1]
|
||||||
if str(core_scripts_dir) not in sys.path:
|
if str(core_scripts_dir) not in sys.path:
|
||||||
@ -11,149 +12,184 @@ if str(core_scripts_dir) not in sys.path:
|
|||||||
|
|
||||||
from paths import *
|
from paths import *
|
||||||
|
|
||||||
def warp_configure_handler(all_traffic=False, popular_sites=False, domestic_sites=False, block_adult_sites=False):
|
def warp_configure_handler(
|
||||||
"""
|
set_all_traffic_state: str | None = None,
|
||||||
Configure WARP routing rules based on provided parameters
|
set_popular_sites_state: str | None = None,
|
||||||
|
set_domestic_sites_state: str | None = None,
|
||||||
Args:
|
set_block_adult_sites_state: str | None = None
|
||||||
all_traffic (bool): Toggle WARP for all traffic
|
):
|
||||||
popular_sites (bool): Toggle WARP for popular sites (Google, Netflix, etc.)
|
try:
|
||||||
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:
|
with open(CONFIG_FILE, 'r') as f:
|
||||||
config = json.load(f)
|
config = json.load(f)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"Error: Configuration file {CONFIG_FILE} not found.")
|
||||||
|
sys.exit(1)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
print(f"Error: Could not decode JSON from {CONFIG_FILE}.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
modified = False
|
modified = False
|
||||||
|
|
||||||
if all_traffic:
|
if 'acl' not in config:
|
||||||
warp_all_active = any(rule == "warps(all)" for rule in config.get('acl', {}).get('inline', []))
|
config['acl'] = {}
|
||||||
|
if 'inline' not in config['acl']:
|
||||||
|
config['acl']['inline'] = []
|
||||||
|
|
||||||
|
if set_all_traffic_state is not None:
|
||||||
|
warp_all_rule = "warps(all)"
|
||||||
|
warp_all_active = warp_all_rule in config['acl']['inline']
|
||||||
|
if set_all_traffic_state == "on":
|
||||||
|
if not warp_all_active:
|
||||||
|
config['acl']['inline'].append(warp_all_rule)
|
||||||
|
print("All traffic rule: Enabled.")
|
||||||
|
modified = True
|
||||||
|
else:
|
||||||
|
print("All traffic rule: Already enabled.")
|
||||||
|
elif set_all_traffic_state == "off":
|
||||||
if warp_all_active:
|
if warp_all_active:
|
||||||
config['acl']['inline'] = [rule for rule in config['acl']['inline'] if rule != "warps(all)"]
|
config['acl']['inline'] = [rule for rule in config['acl']['inline'] if rule != warp_all_rule]
|
||||||
print("Traffic configuration changed to Direct.")
|
print("All traffic rule: Disabled.")
|
||||||
modified = True
|
modified = True
|
||||||
else:
|
else:
|
||||||
if 'acl' not in config:
|
print("All traffic rule: Already disabled.")
|
||||||
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:
|
if set_popular_sites_state is not None:
|
||||||
popular_rules = [
|
popular_rules = [
|
||||||
"warps(geoip:google)",
|
"warps(geoip:google)", "warps(geosite:google)", "warps(geosite:netflix)",
|
||||||
"warps(geosite:google)",
|
"warps(geosite:spotify)", "warps(geosite:openai)", "warps(geoip:openai)"
|
||||||
"warps(geosite:netflix)",
|
|
||||||
"warps(geosite:spotify)",
|
|
||||||
"warps(geosite:openai)",
|
|
||||||
"warps(geoip:openai)"
|
|
||||||
]
|
]
|
||||||
|
if set_popular_sites_state == "on":
|
||||||
rule_exists = any(rule in config.get('acl', {}).get('inline', []) for rule in popular_rules)
|
added_any = False
|
||||||
|
for rule in popular_rules:
|
||||||
if rule_exists:
|
if rule not in config['acl']['inline']:
|
||||||
config['acl']['inline'] = [rule for rule in config['acl']['inline']
|
config['acl']['inline'].append(rule)
|
||||||
if rule not in popular_rules]
|
added_any = True
|
||||||
print("WARP configuration for Google, OpenAI, etc. removed.")
|
if added_any:
|
||||||
|
print("Popular sites rule: Enabled/Updated.")
|
||||||
modified = True
|
modified = True
|
||||||
else:
|
else:
|
||||||
if 'acl' not in config:
|
|
||||||
config['acl'] = {}
|
all_present = all(rule in config['acl']['inline'] for rule in popular_rules)
|
||||||
if 'inline' not in config['acl']:
|
if all_present:
|
||||||
config['acl']['inline'] = []
|
print("Popular sites rule: Already enabled.")
|
||||||
config['acl']['inline'].extend(popular_rules)
|
else:
|
||||||
print("WARP configured for Google, OpenAI, etc.")
|
print("Popular sites rule: Enabled/Updated.")
|
||||||
modified = True
|
modified = True
|
||||||
|
elif set_popular_sites_state == "off":
|
||||||
if domestic_sites:
|
removed_any = False
|
||||||
ir_site_rule = "warps(geosite:ir)"
|
initial_len = len(config['acl']['inline'])
|
||||||
ir_ip_rule = "warps(geoip:ir)"
|
config['acl']['inline'] = [rule for rule in config['acl']['inline'] if rule not in popular_rules]
|
||||||
reject_site_rule = "reject(geosite:ir)"
|
if len(config['acl']['inline']) < initial_len:
|
||||||
reject_ip_rule = "reject(geoip:ir)"
|
removed_any = True
|
||||||
|
if removed_any:
|
||||||
using_warp = (ir_site_rule in config.get('acl', {}).get('inline', []) and
|
print("Popular sites rule: Disabled.")
|
||||||
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
|
modified = True
|
||||||
else:
|
else:
|
||||||
config['acl']['inline'].extend([reject_site_rule, reject_ip_rule])
|
print("Popular sites rule: Already disabled.")
|
||||||
print("Added Reject configuration for geosite:ir and geoip:ir.")
|
|
||||||
modified = True
|
|
||||||
|
|
||||||
if block_adult_sites:
|
if set_domestic_sites_state is not None:
|
||||||
|
ir_site_warp_rule = "warps(geosite:ir)"
|
||||||
|
ir_ip_warp_rule = "warps(geoip:ir)"
|
||||||
|
ir_site_reject_rule = "reject(geosite:ir)"
|
||||||
|
ir_ip_reject_rule = "reject(geoip:ir)"
|
||||||
|
|
||||||
|
if set_domestic_sites_state == "on":
|
||||||
|
changed_to_warp = False
|
||||||
|
if ir_site_reject_rule in config['acl']['inline'] or ir_ip_reject_rule in config['acl']['inline']:
|
||||||
|
config['acl']['inline'] = [r for r in config['acl']['inline'] if r not in [ir_site_reject_rule, ir_ip_reject_rule]]
|
||||||
|
changed_to_warp = True
|
||||||
|
if ir_site_warp_rule not in config['acl']['inline']:
|
||||||
|
config['acl']['inline'].append(ir_site_warp_rule)
|
||||||
|
changed_to_warp = True
|
||||||
|
if ir_ip_warp_rule not in config['acl']['inline']:
|
||||||
|
config['acl']['inline'].append(ir_ip_warp_rule)
|
||||||
|
changed_to_warp = True
|
||||||
|
if changed_to_warp:
|
||||||
|
print("Domestic sites: Configured to use WARP.")
|
||||||
|
modified = True
|
||||||
|
else:
|
||||||
|
print("Domestic sites: Already configured to use WARP.")
|
||||||
|
elif set_domestic_sites_state == "off":
|
||||||
|
changed_to_reject = False
|
||||||
|
if ir_site_warp_rule in config['acl']['inline'] or ir_ip_warp_rule in config['acl']['inline']:
|
||||||
|
config['acl']['inline'] = [r for r in config['acl']['inline'] if r not in [ir_site_warp_rule, ir_ip_warp_rule]]
|
||||||
|
changed_to_reject = True
|
||||||
|
if ir_site_reject_rule not in config['acl']['inline']:
|
||||||
|
config['acl']['inline'].append(ir_site_reject_rule)
|
||||||
|
changed_to_reject = True
|
||||||
|
if ir_ip_reject_rule not in config['acl']['inline']:
|
||||||
|
config['acl']['inline'].append(ir_ip_reject_rule)
|
||||||
|
changed_to_reject = True
|
||||||
|
if changed_to_reject:
|
||||||
|
print("Domestic sites: Configured to REJECT.")
|
||||||
|
modified = True
|
||||||
|
else:
|
||||||
|
print("Domestic sites: Already configured to REJECT.")
|
||||||
|
|
||||||
|
if set_block_adult_sites_state is not None:
|
||||||
nsfw_rule = "reject(geosite:nsfw)"
|
nsfw_rule = "reject(geosite:nsfw)"
|
||||||
|
is_blocking_nsfw = nsfw_rule in config['acl']['inline']
|
||||||
|
|
||||||
blocked = nsfw_rule in config.get('acl', {}).get('inline', [])
|
if 'resolver' not in config: config['resolver'] = {}
|
||||||
|
if 'tls' not in config['resolver']: config['resolver']['tls'] = {}
|
||||||
|
|
||||||
if blocked:
|
desired_resolver = ""
|
||||||
config['acl']['inline'] = [rule for rule in config['acl']['inline']
|
if set_block_adult_sites_state == "on":
|
||||||
if rule != nsfw_rule]
|
desired_resolver = "1.1.1.3:853"
|
||||||
if 'resolver' not in config:
|
if not is_blocking_nsfw:
|
||||||
config['resolver'] = {}
|
config['acl']['inline'].append(nsfw_rule)
|
||||||
if 'tls' not in config['resolver']:
|
print("Adult content blocking: Enabled.")
|
||||||
config['resolver']['tls'] = {}
|
|
||||||
config['resolver']['tls']['addr'] = "1.1.1.1:853"
|
|
||||||
print("Adult content blocking removed and resolver updated.")
|
|
||||||
modified = True
|
modified = True
|
||||||
else:
|
else:
|
||||||
if 'acl' not in config:
|
print("Adult content blocking: Already enabled.")
|
||||||
config['acl'] = {}
|
elif set_block_adult_sites_state == "off":
|
||||||
if 'inline' not in config['acl']:
|
desired_resolver = "1.1.1.1:853"
|
||||||
config['acl']['inline'] = []
|
if is_blocking_nsfw:
|
||||||
config['acl']['inline'].append(nsfw_rule)
|
config['acl']['inline'] = [rule for rule in config['acl']['inline'] if rule != nsfw_rule]
|
||||||
if 'resolver' not in config:
|
print("Adult content blocking: Disabled.")
|
||||||
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
|
modified = True
|
||||||
|
else:
|
||||||
|
print("Adult content blocking: Already disabled.")
|
||||||
|
|
||||||
|
if config['resolver']['tls'].get('addr') != desired_resolver:
|
||||||
|
config['resolver']['tls']['addr'] = desired_resolver
|
||||||
|
print(f"Resolver: Updated to {desired_resolver}.")
|
||||||
|
modified = True
|
||||||
|
|
||||||
|
if 'acl' in config and 'inline' in config['acl']:
|
||||||
|
config['acl']['inline'] = [rule for rule in config['acl']['inline'] if rule]
|
||||||
|
|
||||||
|
|
||||||
if modified:
|
if modified:
|
||||||
with open(CONFIG_FILE, 'w') as f:
|
with open(CONFIG_FILE, 'w') as f:
|
||||||
json.dump(config, f, indent=2)
|
json.dump(config, f, indent=2)
|
||||||
|
|
||||||
|
print("Configuration updated. Attempting to restart hysteria2 service...")
|
||||||
try:
|
try:
|
||||||
subprocess.run(["python3", CLI_PATH, "restart-hysteria2"],
|
subprocess.run(["python3", CLI_PATH, "restart-hysteria2"],
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, timeout=10)
|
||||||
except subprocess.CalledProcessError:
|
print("Hysteria2 service restarted successfully.")
|
||||||
print("Warning: Failed to restart hysteria2")
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Warning: Failed to restart hysteria2. STDERR: {e.stderr.decode().strip()}")
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
print("Warning: Timeout expired while trying to restart hysteria2 service.")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import argparse
|
parser = argparse.ArgumentParser(description="Configure WARP settings. At least one option must be provided.")
|
||||||
|
parser.add_argument("--set-all", choices=['on', 'off'], help="Set WARP for all traffic (on/off)")
|
||||||
parser = argparse.ArgumentParser(description="Configure WARP settings")
|
parser.add_argument("--set-popular-sites", choices=['on', 'off'], help="Set WARP for popular sites (on/off)")
|
||||||
parser.add_argument("--all", action="store_true", help="Toggle WARP for all traffic")
|
parser.add_argument("--set-domestic-sites", choices=['on', 'off'], help="Set behavior for domestic sites (on=WARP, off=REJECT)")
|
||||||
parser.add_argument("--popular-sites", action="store_true", help="Toggle WARP for popular sites")
|
parser.add_argument("--set-block-adult", choices=['on', 'off'], help="Set blocking of adult content (on/off)")
|
||||||
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not any(vars(args).values()):
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
warp_configure_handler(
|
warp_configure_handler(
|
||||||
all_traffic=args.all,
|
set_all_traffic_state=args.set_all,
|
||||||
popular_sites=args.popular_sites,
|
set_popular_sites_state=args.set_popular_sites,
|
||||||
domestic_sites=args.domestic_sites,
|
set_domestic_sites_state=args.set_domestic_sites,
|
||||||
block_adult_sites=args.block_adult
|
set_block_adult_sites_state=args.set_block_adult
|
||||||
)
|
)
|
||||||
@ -8,7 +8,7 @@ import cli_api
|
|||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.post('/install', response_model=DetailResponse, summary='Install WARP')
|
@router.post('/install', response_model=DetailResponse, summary='Install WARP', name="install_warp")
|
||||||
async def install():
|
async def install():
|
||||||
"""
|
"""
|
||||||
Installs WARP.
|
Installs WARP.
|
||||||
@ -27,7 +27,7 @@ async def install():
|
|||||||
raise HTTPException(status_code=400, detail=f'Error: {str(e)}')
|
raise HTTPException(status_code=400, detail=f'Error: {str(e)}')
|
||||||
|
|
||||||
|
|
||||||
@router.delete('/uninstall', response_model=DetailResponse, summary='Uninstall WARP')
|
@router.delete('/uninstall', response_model=DetailResponse, summary='Uninstall WARP', name="uninstall_warp")
|
||||||
async def uninstall():
|
async def uninstall():
|
||||||
"""
|
"""
|
||||||
Uninstalls WARP.
|
Uninstalls WARP.
|
||||||
@ -45,7 +45,7 @@ async def uninstall():
|
|||||||
raise HTTPException(status_code=400, detail=f'Error: {str(e)}')
|
raise HTTPException(status_code=400, detail=f'Error: {str(e)}')
|
||||||
|
|
||||||
|
|
||||||
@router.post('/configure', response_model=DetailResponse, summary='Configure WARP')
|
@router.post('/configure', response_model=DetailResponse, summary='Configure WARP', name="configure_warp")
|
||||||
async def configure(body: ConfigureInputBody):
|
async def configure(body: ConfigureInputBody):
|
||||||
"""
|
"""
|
||||||
Configures WARP with the given options.
|
Configures WARP with the given options.
|
||||||
@ -60,14 +60,23 @@ async def configure(body: ConfigureInputBody):
|
|||||||
HTTPException: If an error occurs during configuration, an HTTP 400 error is raised with the error details.
|
HTTPException: If an error occurs during configuration, an HTTP 400 error is raised with the error details.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
cli_api.configure_warp(body.all, body.popular_sites, body.domestic_sites,
|
all_st = 'on' if body.all else 'off'
|
||||||
body.block_adult_sites)
|
pop_sites_st = 'on' if body.popular_sites else 'off'
|
||||||
|
dom_sites_st = 'on' if body.domestic_sites else 'off'
|
||||||
|
block_adult_st = 'on' if body.block_adult_sites else 'off'
|
||||||
|
|
||||||
|
cli_api.configure_warp(
|
||||||
|
all_state=all_st,
|
||||||
|
popular_sites_state=pop_sites_st,
|
||||||
|
domestic_sites_state=dom_sites_st,
|
||||||
|
block_adult_sites_state=block_adult_st
|
||||||
|
)
|
||||||
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=404, detail=f'Error configuring WARP: {str(e)}')
|
||||||
|
|
||||||
|
|
||||||
@router.get('/status', response_model=StatusResponse, summary='Get WARP Status')
|
@router.get('/status', response_model=StatusResponse, summary='Get WARP Status', name="status_warp")
|
||||||
async def status():
|
async def status():
|
||||||
try:
|
try:
|
||||||
status_json_str = cli_api.warp_status()
|
status_json_str = cli_api.warp_status()
|
||||||
|
|||||||
@ -66,6 +66,10 @@
|
|||||||
aria-controls='decoy' aria-selected='false'><i class="fas fa-mask"></i>
|
aria-controls='decoy' aria-selected='false'><i class="fas fa-mask"></i>
|
||||||
Decoy Site</a>
|
Decoy Site</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class='nav-item'>
|
||||||
|
<a class='nav-link' id='warp-tab-link' data-toggle='pill' href='#warp-content' role='tab'
|
||||||
|
aria-controls='warp-content' aria-selected='false'><i class="fas fa-cloud"></i> WARP</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class='card-body' style="margin-left: 25px;">
|
<div class='card-body' style="margin-left: 25px;">
|
||||||
@ -330,6 +334,63 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- WARP Tab -->
|
||||||
|
<div class='tab-pane fade' id='warp-content' role='tabpanel' aria-labelledby='warp-tab-link'>
|
||||||
|
<div id="warp_initial_controls">
|
||||||
|
<div class='alert alert-info'>WARP service is not active.</div>
|
||||||
|
<button id="warp_start_btn" type='button' class='btn btn-success mt-3'>
|
||||||
|
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" style="display: none;"></span>
|
||||||
|
Install & Start WARP
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="warp_active_controls" style="display: none;">
|
||||||
|
<div class='alert alert-success mb-3'>WARP service is active.</div>
|
||||||
|
|
||||||
|
<div class="card card-secondary">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title"><i class="fas fa-cogs"></i> WARP Configuration</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form id="warp_config_form">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="custom-control custom-switch">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="warp_all_traffic">
|
||||||
|
<label class="custom-control-label" for="warp_all_traffic">Route All Traffic through WARP</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="custom-control custom-switch">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="warp_popular_sites">
|
||||||
|
<label class="custom-control-label" for="warp_popular_sites">Route Popular Sites through WARP</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="custom-control custom-switch">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="warp_domestic_sites">
|
||||||
|
<label class="custom-control-label" for="warp_domestic_sites">Route Domestic Sites through WARP</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="custom-control custom-switch">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="warp_block_adult_sites">
|
||||||
|
<label class="custom-control-label" for="warp_block_adult_sites">Block Adult Sites (WARP Family DNS)</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="warp_save_config_btn" type='button' class='btn btn-primary'>
|
||||||
|
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" style="display: none;"></span>
|
||||||
|
Save Configuration
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="warp_stop_btn" type='button' class='btn btn-danger mt-3'>
|
||||||
|
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" style="display: none;"></span>
|
||||||
|
Stop & Uninstall WARP
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.card -->
|
<!-- /.card -->
|
||||||
@ -543,7 +604,8 @@
|
|||||||
const servicesMap = {
|
const servicesMap = {
|
||||||
"hysteria_telegram_bot": "#telegram_form",
|
"hysteria_telegram_bot": "#telegram_form",
|
||||||
"hysteria_normal_sub": "#normal_sub_service_form",
|
"hysteria_normal_sub": "#normal_sub_service_form",
|
||||||
"hysteria_iplimit": "#ip-limit-service"
|
"hysteria_iplimit": "#ip-limit-service",
|
||||||
|
"hysteria_warp": "warp_service"
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(servicesMap).forEach(service => {
|
Object.keys(servicesMap).forEach(service => {
|
||||||
@ -599,6 +661,17 @@
|
|||||||
$("#max_ips").val("");
|
$("#max_ips").val("");
|
||||||
$("#block_duration, #max_ips").removeClass('is-invalid');
|
$("#block_duration, #max_ips").removeClass('is-invalid');
|
||||||
}
|
}
|
||||||
|
} else if (service === "hysteria_warp") {
|
||||||
|
const isWarpServiceRunning = data[service];
|
||||||
|
if (isWarpServiceRunning) {
|
||||||
|
$("#warp_initial_controls").hide();
|
||||||
|
$("#warp_active_controls").show();
|
||||||
|
fetchWarpFullStatusAndConfig();
|
||||||
|
} else {
|
||||||
|
$("#warp_initial_controls").show();
|
||||||
|
$("#warp_active_controls").hide();
|
||||||
|
$("#warp_config_form")[0].reset();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const $formSelector = $(targetSelector);
|
const $formSelector = $(targetSelector);
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
@ -1013,6 +1086,84 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fetchWarpFullStatusAndConfig() {
|
||||||
|
$.ajax({
|
||||||
|
url: "{{ url_for('status_warp') }}",
|
||||||
|
type: "GET",
|
||||||
|
success: function (data) {
|
||||||
|
$("#warp_all_traffic").prop('checked', data.all_traffic_via_warp || false);
|
||||||
|
$("#warp_popular_sites").prop('checked', data.popular_sites_via_warp || false);
|
||||||
|
$("#warp_domestic_sites").prop('checked', data.domestic_sites_via_warp || false);
|
||||||
|
$("#warp_block_adult_sites").prop('checked', data.block_adult_content || false);
|
||||||
|
|
||||||
|
$("#warp_initial_controls").hide();
|
||||||
|
$("#warp_active_controls").show();
|
||||||
|
},
|
||||||
|
error: function (xhr, status, error) {
|
||||||
|
let errorMsg = "Failed to fetch WARP configuration.";
|
||||||
|
if (xhr.responseJSON && xhr.responseJSON.detail) {
|
||||||
|
errorMsg = xhr.responseJSON.detail;
|
||||||
|
}
|
||||||
|
console.error("Error fetching WARP config:", errorMsg, xhr.responseText);
|
||||||
|
|
||||||
|
if (xhr.status === 404) {
|
||||||
|
$("#warp_initial_controls").show();
|
||||||
|
$("#warp_active_controls").hide();
|
||||||
|
$("#warp_config_form")[0].reset();
|
||||||
|
Swal.fire("Info", "WARP service might not be fully configured. Please try reinstalling if issues persist.", "info");
|
||||||
|
} else {
|
||||||
|
$("#warp_config_form")[0].reset();
|
||||||
|
Swal.fire("Warning", "Could not load current WARP configuration values. Please check manually or re-save.", "warning");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#warp_start_btn").on("click", function() {
|
||||||
|
confirmAction("install and start WARP", function () {
|
||||||
|
sendRequest(
|
||||||
|
"{{ url_for('install_warp') }}",
|
||||||
|
"POST",
|
||||||
|
null,
|
||||||
|
"WARP installation request sent. The page will reload.",
|
||||||
|
"#warp_start_btn",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#warp_stop_btn").on("click", function() {
|
||||||
|
confirmAction("stop and uninstall WARP", function () {
|
||||||
|
sendRequest(
|
||||||
|
"{{ url_for('uninstall_warp') }}",
|
||||||
|
"DELETE",
|
||||||
|
null,
|
||||||
|
"WARP uninstallation request sent. The page will reload.",
|
||||||
|
"#warp_stop_btn",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#warp_save_config_btn").on("click", function() {
|
||||||
|
const configData = {
|
||||||
|
all: $("#warp_all_traffic").is(":checked"),
|
||||||
|
popular_sites: $("#warp_popular_sites").is(":checked"),
|
||||||
|
domestic_sites: $("#warp_domestic_sites").is(":checked"),
|
||||||
|
block_adult_sites: $("#warp_block_adult_sites").is(":checked")
|
||||||
|
};
|
||||||
|
confirmAction("save WARP configuration", function () {
|
||||||
|
sendRequest(
|
||||||
|
"{{ url_for('configure_warp') }}",
|
||||||
|
"POST",
|
||||||
|
configData,
|
||||||
|
"WARP configuration saved successfully!",
|
||||||
|
"#warp_save_config_btn",
|
||||||
|
false,
|
||||||
|
fetchWarpFullStatusAndConfig
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
$("#telegram_start").on("click", startTelegram);
|
$("#telegram_start").on("click", startTelegram);
|
||||||
|
|||||||
60
menu.sh
60
menu.sh
@ -384,18 +384,17 @@ warp_configure_handler() {
|
|||||||
|
|
||||||
if systemctl is-active --quiet "$service_name"; then
|
if systemctl is-active --quiet "$service_name"; then
|
||||||
echo -e "${cyan}=== WARP Status ===${NC}"
|
echo -e "${cyan}=== WARP Status ===${NC}"
|
||||||
|
|
||||||
status_json=$(python3 $CLI_PATH warp-status)
|
status_json=$(python3 $CLI_PATH warp-status)
|
||||||
|
|
||||||
all_traffic=$(echo "$status_json" | grep -o '"all_traffic_via_warp": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
|
all_traffic=$(echo "$status_json" | grep -o '"all_traffic_via_warp": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
|
||||||
popular_sites=$(echo "$status_json" | grep -o '"popular_sites_via_warp": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
|
popular_sites=$(echo "$status_json" | grep -o '"popular_sites_via_warp": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
|
||||||
domestic_sites=$(echo "$status_json" | grep -o '"domestic_sites_via_warp": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
|
domestic_sites_via_warp=$(echo "$status_json" | grep -o '"domestic_sites_via_warp": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
|
||||||
block_adult=$(echo "$status_json" | grep -o '"block_adult_content": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
|
block_adult=$(echo "$status_json" | grep -o '"block_adult_content": *[^,}]*' | cut -d':' -f2 | tr -d ' "')
|
||||||
|
|
||||||
display_status() {
|
display_status() {
|
||||||
local label="$1"
|
local label="$1"
|
||||||
local status="$2"
|
local status_val="$2"
|
||||||
if [ "$status" = "true" ]; then
|
if [ "$status_val" = "true" ]; then
|
||||||
echo -e " ${green}✓${NC} $label: ${green}Enabled${NC}"
|
echo -e " ${green}✓${NC} $label: ${green}Enabled${NC}"
|
||||||
else
|
else
|
||||||
echo -e " ${red}✗${NC} $label: ${red}Disabled${NC}"
|
echo -e " ${red}✗${NC} $label: ${red}Disabled${NC}"
|
||||||
@ -404,38 +403,49 @@ warp_configure_handler() {
|
|||||||
|
|
||||||
display_status "All Traffic via WARP" "$all_traffic"
|
display_status "All Traffic via WARP" "$all_traffic"
|
||||||
display_status "Popular Sites via WARP" "$popular_sites"
|
display_status "Popular Sites via WARP" "$popular_sites"
|
||||||
display_status "Domestic Sites via WARP" "$domestic_sites"
|
display_status "Domestic Sites via WARP" "$domestic_sites_via_warp"
|
||||||
display_status "Block Adult Content" "$block_adult"
|
display_status "Block Adult Content" "$block_adult"
|
||||||
|
|
||||||
echo -e "${cyan}==================${NC}"
|
echo -e "${cyan}==================${NC}"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
echo "Configure WARP Options:"
|
echo "Configure WARP Options (Toggle):"
|
||||||
echo "1. Use WARP for all traffic"
|
echo "1. All traffic via WARP"
|
||||||
echo "2. Use WARP for popular sites"
|
echo "2. Popular sites via WARP"
|
||||||
echo "3. Use WARP for domestic sites"
|
echo "3. Domestic sites (WARP/Reject)"
|
||||||
echo "4. Block adult content"
|
echo "4. Block adult content"
|
||||||
echo "5. WARP Status Profile"
|
echo "5. WARP Status Profile (IP etc.)"
|
||||||
echo "6. Change IP address"
|
echo "6. Change WARP IP address"
|
||||||
echo "0. Cancel"
|
echo "0. Cancel"
|
||||||
|
|
||||||
read -p "Select an option: " option
|
read -p "Select an option to toggle: " option
|
||||||
|
|
||||||
case $option in
|
case $option in
|
||||||
1) python3 $CLI_PATH configure-warp --all ;;
|
1)
|
||||||
2) python3 $CLI_PATH configure-warp --popular-sites ;;
|
target_state=$([ "$all_traffic" = "true" ] && echo "off" || echo "on")
|
||||||
3) python3 $CLI_PATH configure-warp --domestic-sites ;;
|
python3 $CLI_PATH configure-warp --set-all "$target_state" ;;
|
||||||
4) python3 $CLI_PATH configure-warp --block-adult-sites ;;
|
2)
|
||||||
|
target_state=$([ "$popular_sites" = "true" ] && echo "off" || echo "on")
|
||||||
|
python3 $CLI_PATH configure-warp --set-popular-sites "$target_state" ;;
|
||||||
|
3)
|
||||||
|
target_state=$([ "$domestic_sites_via_warp" = "true" ] && echo "off" || echo "on")
|
||||||
|
python3 $CLI_PATH configure-warp --set-domestic-sites "$target_state" ;;
|
||||||
|
4)
|
||||||
|
target_state=$([ "$block_adult" = "true" ] && echo "off" || echo "on")
|
||||||
|
python3 $CLI_PATH configure-warp --set-block-adult-sites "$target_state" ;;
|
||||||
5)
|
5)
|
||||||
ip=$(curl -s --interface wgcf --connect-timeout 0.5 http://v4.ident.me)
|
current_ip=$(python3 $CLI_PATH warp-status | grep -o '"ip": *"[^"]*"' | cut -d':' -f2- | tr -d '" ')
|
||||||
|
if [ -z "$current_ip" ]; then
|
||||||
|
current_ip=$(curl -s --interface wgcf --connect-timeout 1 http://v4.ident.me || echo "N/A")
|
||||||
|
fi
|
||||||
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}${current_ip}${NC}"
|
||||||
;;
|
;;
|
||||||
6)
|
6)
|
||||||
old_ip=$(curl -s --interface wgcf --connect-timeout 0.5 http://v4.ident.me)
|
old_ip=$(curl -s --interface wgcf --connect-timeout 1 http://v4.ident.me || echo "N/A")
|
||||||
echo -e "${yellow}Current IP:${NC} ${cyan}$old_ip${NC}"
|
echo -e "${yellow}Current IP:${NC} ${cyan}$old_ip${NC}"
|
||||||
echo "Restarting $service_name..."
|
echo "Restarting $service_name to attempt IP change..."
|
||||||
systemctl restart "$service_name"
|
systemctl restart "$service_name"
|
||||||
|
|
||||||
echo -n "Waiting for service to restart"
|
echo -n "Waiting for service to restart"
|
||||||
@ -445,18 +455,22 @@ warp_configure_handler() {
|
|||||||
done
|
done
|
||||||
echo
|
echo
|
||||||
|
|
||||||
new_ip=$(curl -s --interface wgcf --connect-timeout 0.5 http://v4.ident.me)
|
new_ip=$(curl -s --interface wgcf --connect-timeout 1 http://v4.ident.me || echo "N/A")
|
||||||
echo -e "${yellow}New IP:${NC} ${green}$new_ip${NC}"
|
echo -e "${yellow}New IP:${NC} ${green}$new_ip${NC}"
|
||||||
|
|
||||||
if [ "$old_ip" != "$new_ip" ]; then
|
if [ "$old_ip" != "N/A" ] && [ "$new_ip" != "N/A" ] && [ "$old_ip" != "$new_ip" ]; then
|
||||||
echo -e "${green}✓ IP address changed successfully${NC}"
|
echo -e "${green}✓ IP address changed successfully${NC}"
|
||||||
else
|
elif [ "$old_ip" = "$new_ip" ] && [ "$old_ip" != "N/A" ]; then
|
||||||
echo -e "${yellow}⚠ IP address remained the same${NC}"
|
echo -e "${yellow}⚠ IP address remained the same${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${red}✗ Could not verify IP change.${NC}"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
0) echo "WARP configuration canceled." ;;
|
0) echo "WARP configuration canceled." ;;
|
||||||
*) echo -e "${red}Invalid option. Please try again.${NC}" ;;
|
*) echo -e "${red}Invalid option. Please try again.${NC}" ;;
|
||||||
esac
|
esac
|
||||||
|
# echo "Command sent. Check status again to see changes."
|
||||||
|
|
||||||
else
|
else
|
||||||
echo -e "${red}$service_name is not active. Please start the service before configuring WARP.${NC}"
|
echo -e "${red}$service_name is not active. Please start the service before configuring WARP.${NC}"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user