Skip to content

Commit

Permalink
Merge pull request #75 from vvbbnn00/fix-android
Browse files Browse the repository at this point in the history
fix: Fix the issue where Clash Meta on Android is not working properly
  • Loading branch information
vvbbnn00 authored Feb 27, 2024
2 parents 92511e1 + 5b9ab55 commit 0a30b90
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 24 deletions.
84 changes: 63 additions & 21 deletions services/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import string
import tempfile
import urllib.parse

import yaml
from flask import request

Expand All @@ -26,23 +27,51 @@
GEOIP = GeoIP('./config/geolite/GeoLite2-Country.mmdb')


def getRandomEntryPoints(best=False,
logger=logging.getLogger(__name__)):
"""
Get random entry points
:param best: Whether to use the best entrypoints
:param logger:
:return: list of entrypoints
"""
entrypoints = getEntrypoints()

# If there is no entrypoints, return a message
if entrypoints is None or len(entrypoints) == 0:
return None, "No entrypoints available. Please try again later."

# Randomly select entrypoints
if len(entrypoints) < RANDOM_COUNT:
logger.warning(f"Entrypoints is less than {RANDOM_COUNT}, only {len(entrypoints)} available.")
random_points = entrypoints
else:
random_points = random.sample(entrypoints, RANDOM_COUNT) if not best else getBestEntrypoints(RANDOM_COUNT)

return random_points, ""


def generateClashSubFile(account: Account = None,
logger=logging.getLogger(__name__),
best=False,
proxy_format='full',
random_name=False):
random_name=False,
is_android=False):
"""
Generate Clash subscription file
:param random_name: Whether to use random name
:param proxy_format: full - full config, with_groups - only proxies and proxy-groups, only_proxies - only proxies
:param account:
:param logger:
:param best: Whether to use the best entrypoints
:param is_android: Whether the client is Android
:return:
"""
account = getCurrentAccount(logger) if account is None else account
entrypoints = getEntrypoints()
random_points = random.sample(entrypoints, RANDOM_COUNT) if not best else getBestEntrypoints(RANDOM_COUNT)

random_points, msg = getRandomEntryPoints(best, logger)
if random_points is None:
return msg

# Generate user configuration file
user_config = []
Expand All @@ -56,20 +85,24 @@ def generateClashSubFile(account: Account = None,
country = GEOIP.lookup(point.ip)
country_emoji = GEOIP.lookup_emoji(point.ip)
name = node_name_generator.next(country_emoji, country)
user_config.append(
{
"name": name,
"type": "wireguard",
"server": point.ip,
"port": point.port,
"ip": "172.16.0.2",
"private-key": account.private_key,
"public-key": CF_CONFIG.get("publicKey"),
"udp": True,
"remote-dns-resolve": True,
"dns": ['1.1.1.1', '1.0.0.1'],
"mtu": 1280,
})
config_data = {
"name": name,
"type": "wireguard",
"server": point.ip,
"port": point.port,
"ip": "172.16.0.2",
"private-key": account.private_key,
"public-key": CF_CONFIG.get("publicKey"),
"udp": True,
"remote-dns-resolve": True,
"mtu": 1280,
}

# It seems that `dns` will cause problem in android.
if not is_android:
config_data["dns"] = ['1.1.1.1', '1.0.0.1']

user_config.append(config_data)
clash_json = copy.deepcopy(CLASH)
clash_json["proxies"] = user_config
for proxy_group in clash_json["proxy-groups"]:
Expand Down Expand Up @@ -100,6 +133,11 @@ def generateWireguardSubFile(account: Account = None,
"""
account = getCurrentAccount(logger) if account is None else account
entrypoints = getEntrypoints()

# If there is no entrypoints, return a message
if entrypoints is None or len(entrypoints) == 0:
return "No entrypoints available. Please try again later."

random_point = random.choice(entrypoints) if not best else getBestEntrypoints(1)[0]

# Generate user configuration file
Expand Down Expand Up @@ -133,8 +171,10 @@ def generateSurgeSubFile(account: Account = None,
:return:
"""
account = getCurrentAccount(logger) if account is None else account
entrypoints = getEntrypoints()
random_points = random.sample(entrypoints, RANDOM_COUNT) if not best else getBestEntrypoints(RANDOM_COUNT)

random_points, msg = getRandomEntryPoints(best, logger)
if random_points is None:
return msg

# Generate user configuration file
user_config = []
Expand Down Expand Up @@ -213,8 +253,10 @@ def generateShadowRocketSubFile(account: Account = None,
:return:
"""
account = getCurrentAccount(logger) if account is None else account
entrypoints = getEntrypoints()
random_points = random.sample(entrypoints, RANDOM_COUNT) if not best else getBestEntrypoints(RANDOM_COUNT)

random_points, msg = getRandomEntryPoints(best, logger)
if random_points is None:
return msg

# Initialize NodeNameGenerator
node_name_generator = NodeNameGenerator(random_name)
Expand Down
15 changes: 12 additions & 3 deletions services/web_service.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import time
from functools import wraps

from faker import Faker
from flask import Flask, request, make_response, current_app, render_template

from config import SECRET_KEY, REQUEST_RATE_LIMIT, SHARE_SUBSCRIPTION
from services.account import resetAccountKey, doUpdateLicenseKey
from services.common import *
from services.subscription import generateClashSubFile, generateWireguardSubFile, generateSurgeSubFile, \
generateShadowRocketSubFile
from services.common import *
from faker import Faker

RATE_LIMIT_MAP = {}

Expand Down Expand Up @@ -161,17 +162,25 @@ def httpAccountUpdateLicense():
@rateLimit()
@authorized(can_skip=True)
def httpSubscription(sub_type: str):
user_agent = request.headers.get('User-Agent', 'unknown').lower()
account = getCurrentAccount(logger)
best = request.args.get('best', 'false').lower() == "true" or False
random_name = request.args.get('randomName', 'false').lower() == "true" or False
proxy_format = request.args.get('proxyFormat', 'full').lower()

if sub_type == "clash": # Clash

# It seems that `dns` will cause problem in android.
# So it is necessary to check if the user agent contains "android".
# https://github.com/vvbbnn00/WARP-Clash-API/issues/74
is_android = "android" in user_agent

fileData = generateClashSubFile(account,
logger,
best=best,
proxy_format=proxy_format,
random_name=random_name)
random_name=random_name,
is_android=is_android)
headers = {
'Content-Type': 'application/x-yaml; charset=utf-8',
'Content-Disposition': f'attachment; filename=Clash-{fake.color_name()}.yaml',
Expand Down

0 comments on commit 0a30b90

Please sign in to comment.