gitscope
← marzneshin / Diff · 406d607 → 406d607
Changes 406d607..406d607
Patch commit
diff --git a/.env.example b/.env.example
index c7e6ba3..a11b614 100644
--- a/.env.example
+++ b/.env.example
@@ -23,7 +23,9 @@ UVICORN_PORT = 8000
# DISCORD_WEBHOOK_URL = "https://discord.com/api/webhooks/xxxxxxx"
# CUSTOM_TEMPLATES_DIRECTORY="/var/lib/marzneshin/templates/"
-# CLASH_SUBSCRIPTION_TEMPLATE="clash/my-custom-template.yml"
+# CLASH_SUBSCRIPTION_TEMPLATE="/var/lib/marzneshin/templates/clash.yml"
+# SINGBOX_SUBSCRIPTION_TEMPLATE="/var/lib/marzneshin/templates/sing-box.json"
+# XRAY_SUBSCRIPTION_TEMPLATE="/var/lib/marzneshin/templates/xray.json"
# SUBSCRIPTION_PAGE_TEMPLATE="subscription/index.html"
# HOME_PAGE_TEMPLATE="home/index.html"
diff --git a/app/templates/sing-box.json b/app/templates/sing-box.json
new file mode 100644
index 0000000..dc0ff97
--- /dev/null
+++ b/app/templates/sing-box.json
@@ -0,0 +1,236 @@
+{
+ "log": {
+ "level": "warn",
+ "timestamp": true
+ },
+ "dns": {
+ "servers": [
+ {
+ "tag": "dns-remote",
+ "address": "1.1.1.1",
+ "detour": "Green Zone"
+ },
+ {
+ "tag": "dns-local",
+ "address": "https://free.shecan.ir/dns-query",
+ "address_resolver": "dns-resolver",
+ "detour": "direct"
+ },
+ {
+ "tag": "dns-resolver",
+ "address": "178.22.122.100",
+ "detour": "direct"
+ },
+ {
+ "tag": "dns-block",
+ "address": "rcode://success"
+ }
+ ],
+ "rules": [
+ {
+ "outbound": "any",
+ "server": "dns-local"
+ },
+ {
+ "domain_suffix": ".ir",
+ "server": "dns-local"
+ },
+ {
+ "rule_set": "geosite-ir",
+ "server": "dns-local"
+ }
+ ],
+ "final": "dns-remote",
+ "reverse_mapping": true,
+ "independent_cache": true
+ },
+ "ntp": {
+ "enabled": false,
+ "server": "pool.ntp.org"
+ },
+ "inbounds": [
+ {
+ "type": "tun",
+ "tag": "tun-in",
+ "interface_name": "tun0",
+ "mtu": 9000,
+ "inet4_address": "172.19.0.1/30",
+ "inet6_address": "fdfe:dcba:9876::1/126",
+ "auto_route": true,
+ "strict_route": true,
+ "stack": "mixed",
+ "sniff": true,
+ "sniff_override_destination": false
+ }
+ ],
+ "outbounds": [
+ {
+ "type": "selector",
+ "tag": "Green Zone",
+ "interrupt_exist_connections": true,
+ "default": "\ud83c\udde9\ud83c\uddea - CD\u03a0 - MEDI\u039b",
+ "outbounds": null
+ },
+ {
+ "type": "direct",
+ "tag": "direct"
+ },
+ {
+ "type": "block",
+ "tag": "block"
+ },
+ {
+ "type": "dns",
+ "tag": "dns-out"
+ }
+ ],
+ "route": {
+ "rules": [
+ {
+ "type": "logical",
+ "mode": "or",
+ "rules": [
+ {
+ "protocol": "dns"
+ },
+ {
+ "port": 53
+ }
+ ],
+ "outbound": "dns-out"
+ },
+ {
+ "type": "logical",
+ "mode": "or",
+ "rules": [
+ {
+ "port": 853
+ },
+ {
+ "network": "udp",
+ "port": 443
+ }
+ ],
+ "outbound": "block"
+ },
+ {
+ "domain_suffix": ".ir",
+ "outbound": "direct"
+ },
+ {
+ "ip_is_private": true,
+ "outbound": "direct"
+ },
+ {
+ "rule_set": [
+ "geosite-category-ads-all",
+ "geosite-malware",
+ "geosite-phishing",
+ "geosite-cryptominers",
+ "geoip-malware",
+ "geoip-phishing"
+ ],
+ "outbound": "block"
+ },
+ {
+ "rule_set": [
+ "geosite-ir",
+ "geoip-ir"
+ ],
+ "outbound": "direct"
+ },
+ {
+ "source_ip_cidr": [
+ "224.0.0.0/3",
+ "ff00::/8"
+ ],
+ "ip_cidr": [
+ "224.0.0.0/3",
+ "ff00::/8"
+ ],
+ "outbound": "block"
+ }
+ ],
+ "rule_set": [
+ {
+ "type": "remote",
+ "tag": "geosite-ir",
+ "format": "binary",
+ "url": "https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geosite-ir.srs",
+ "download_detour": "direct",
+ "update_interval": "1480h0m0s"
+ },
+ {
+ "type": "remote",
+ "tag": "geosite-category-ads-all",
+ "format": "binary",
+ "url": "https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geosite-category-ads-all.srs",
+ "download_detour": "direct",
+ "update_interval": "1480h0m0s"
+ },
+ {
+ "type": "remote",
+ "tag": "geosite-malware",
+ "format": "binary",
+ "url": "https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geosite-malware.srs",
+ "download_detour": "direct",
+ "update_interval": "1480h0m0s"
+ },
+ {
+ "type": "remote",
+ "tag": "geosite-phishing",
+ "format": "binary",
+ "url": "https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geosite-phishing.srs",
+ "download_detour": "direct",
+ "update_interval": "1480h0m0s"
+ },
+ {
+ "type": "remote",
+ "tag": "geosite-cryptominers",
+ "format": "binary",
+ "url": "https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geosite-cryptominers.srs",
+ "download_detour": "direct",
+ "update_interval": "1480h0m0s"
+ },
+ {
+ "type": "remote",
+ "tag": "geoip-ir",
+ "format": "binary",
+ "url": "https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geoip-ir.srs",
+ "download_detour": "direct",
+ "update_interval": "1480h0m0s"
+ },
+ {
+ "type": "remote",
+ "tag": "geoip-malware",
+ "format": "binary",
+ "url": "https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geoip-malware.srs",
+ "download_detour": "direct",
+ "update_interval": "1480h0m0s"
+ },
+ {
+ "type": "remote",
+ "tag": "geoip-phishing",
+ "format": "binary",
+ "url": "https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geoip-phishing.srs",
+ "download_detour": "direct",
+ "update_interval": "1480h0m0s"
+ }
+ ],
+ "final": "Green Zone",
+ "auto_detect_interface": true,
+ "override_android_vpn": true
+ },
+ "experimental": {
+ "cache_file": {
+ "enabled": true,
+ "store_fakeip": true
+ },
+ "clash_api": {
+ "external_controller": "127.0.0.1:9090",
+ "external_ui": "metacubexd",
+ "external_ui_download_url": "https://github.com/MetaCubeX/metacubexd/archive/gh-pages.zip",
+ "external_ui_download_detour": "direct"
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/templates/xray.json b/app/templates/xray.json
new file mode 100644
index 0000000..035a952
--- /dev/null
+++ b/app/templates/xray.json
@@ -0,0 +1,84 @@
+{
+ "log": {
+ "loglevel": "warning"
+ },
+ "dns": {
+ "queryStrategy": "UseIP",
+ "servers": [
+ "1.1.1.1",
+ "8.8.8.8"
+ ],
+ "tag": "dns_out"
+ },
+ "routing": {
+ "domainStrategy": "IPIfNonMatch",
+ "rules": [
+ {
+ "domain": [
+ "geosite:category-ads-all"
+ ],
+ "outboundTag": "block"
+ },
+ {
+ "domain": [
+ "regexp:.*\\.ir",
+ "domain:ir",
+ "geosite:private"
+ ],
+ "outboundTag": "direct"
+ },
+ {
+ "ip": [
+ "geoip:ir",
+ "geoip:private"
+ ],
+ "outboundTag": "direct"
+ }
+ ]
+ },
+ "policy": {
+ "system": {
+ "statsOutboundDownlink": true,
+ "statsOutboundUplink": true
+ }
+ },
+ "inbounds": [
+ {
+ "port": 10808,
+ "protocol": "socks",
+ "settings": {
+ "auth": "noauth",
+ "udp": true,
+ "userLevel": 8
+ },
+ "sniffing": {
+ "destOverride": [
+ "http",
+ "tls",
+ "fakedns"
+ ],
+ "enabled": true
+ },
+ "tag": "socks"
+ },
+ {
+ "port": 10809,
+ "protocol": "http",
+ "settings": {
+ "userLevel": 8
+ },
+ "tag": "http"
+ }
+ ],
+ "outbounds": [
+ {
+ "tag": "direct",
+ "protocol": "freedom"
+ },
+ {
+ "tag": "block",
+ "protocol": "blackhole"
+ }
+ ],
+ "stats": {}
+}
diff --git a/app/utils/share.py b/app/utils/share.py
index ef6d4ce..af8fc9a 100644
--- a/app/utils/share.py
+++ b/app/utils/share.py
@@ -4,6 +4,7 @@ import random
import secrets
from collections import defaultdict
from datetime import datetime as dt, timedelta
+from importlib import resources
from typing import TYPE_CHECKING, Literal, Union, List
from uuid import UUID
@@ -18,6 +19,11 @@ from app.models.proxy import (
from app.models.user import UserStatus
from app.utils.keygen import gen_uuid, gen_password
from app.utils.system import get_public_ip, readable_size
+from config import (
+ XRAY_SUBSCRIPTION_TEMPLATE,
+ SINGBOX_SUBSCRIPTION_TEMPLATE,
+ CLASH_SUBSCRIPTION_TEMPLATE,
+)
if TYPE_CHECKING:
from app.models.user import UserResponse
@@ -40,6 +46,16 @@ subscription_handlers = {
"sing-box": SingBoxConfig,
}
+handlers_templates = {
+ LinksConfig: None,
+ XrayConfig: XRAY_SUBSCRIPTION_TEMPLATE
+ or resources.files("app.templates") / "xray.json",
+ ClashConfig: CLASH_SUBSCRIPTION_TEMPLATE,
+ ClashMetaConfig: CLASH_SUBSCRIPTION_TEMPLATE,
+ SingBoxConfig: SINGBOX_SUBSCRIPTION_TEMPLATE
+ or resources.files("app.templates") / "sing-box.json",
+}
+
def generate_subscription(
user: "UserResponse",
@@ -55,8 +71,14 @@ def generate_subscription(
if config_format not in subscription_handlers.keys():
raise ValueError(f'Unsupported format "{config_format}"')
+ subscription_handler_class = subscription_handlers[config_format]
+ if template_path := handlers_templates[subscription_handler_class]:
+ subscription_handler = subscription_handler_class(template_path=template_path)
+ else:
+ subscription_handler = subscription_handler_class()
+
config = process_inbounds_and_tags(
- inbounds, key, format_variables, conf=subscription_handlers[config_format]()
+ inbounds, key, format_variables, conf=subscription_handler
)
return config if not as_base64 else base64.b64encode(config.encode()).decode()
diff --git a/config.py b/config.py
index 900df56..305fc1b 100755
--- a/config.py
+++ b/config.py
@@ -44,18 +44,15 @@ JWT_ACCESS_TOKEN_EXPIRE_MINUTES = config(
)
CUSTOM_TEMPLATES_DIRECTORY = config("CUSTOM_TEMPLATES_DIRECTORY", default=None)
-CLASH_SUBSCRIPTION_TEMPLATE = config(
- "CLASH_SUBSCRIPTION_TEMPLATE", default="clash/default.yml"
-)
+
SUBSCRIPTION_PAGE_TEMPLATE = config(
"SUBSCRIPTION_PAGE_TEMPLATE", default="subscription/index.html"
)
HOME_PAGE_TEMPLATE = config("HOME_PAGE_TEMPLATE", default="home/index.html")
-SINGBOX_SUBSCRIPTION_TEMPLATE = config(
- "SINGBOX_SUBSCRIPTION_TEMPLATE", default="singbox/default.json"
-)
-
+SINGBOX_SUBSCRIPTION_TEMPLATE = config("SINGBOX_SUBSCRIPTION_TEMPLATE", default=None)
+XRAY_SUBSCRIPTION_TEMPLATE = config("XRAY_SUBSCRIPTION_TEMPLATE", default=None)
+CLASH_SUBSCRIPTION_TEMPLATE = config("CLASH_SUBSCRIPTION_TEMPLATE", default=None)
WEBHOOK_ADDRESS = config("WEBHOOK_ADDRESS", default=None)
WEBHOOK_SECRET = config("WEBHOOK_SECRET", default=None)
diff --git a/requirements.txt b/requirements.txt
index 20a3714..a3d1ba8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -35,4 +35,4 @@ python-multipart==0.0.7
xxhash==3.4.1
grpcio==1.60.0
psycopg==3.1.18
-v2share==0.1.0b6
+v2share==0.1.0b7