Skip to content

Commit

Permalink
feat: add support for ssconf:// outline subscription
Browse files Browse the repository at this point in the history
  • Loading branch information
dimlaitman committed Oct 28, 2023
1 parent 5982ac4 commit 0dbb063
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 8 deletions.
54 changes: 49 additions & 5 deletions app/utils/share.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,8 +488,42 @@ def get_v2ray_link(remark: str, address: str, inbound: dict, settings: dict):
address=address,
port=inbound['port'],
password=settings['password'],
method=settings['method']
)
method=settings['method'])

class OutlineConfiguration:
def __init__(self):
self.config = {}

def add_directly(self, data: dict):
self.config.update(data)

def render(self):
return json.dumps(self.config, indent=0)

def make_outbound(self, remark: str, address: str, port: int, password: str, method: str):
config = {
"method": method,
"password": password,
"server": address,
"server_port": port,
"tag": remark,
}
return config

def add(self, remark: str, address: str, inbound: dict, settings: dict):
if inbound['protocol'] != 'shadowsocks':
return

outbound = self.make_outbound(
remark=remark,
address=address,
port=inbound['port'],
password=settings['password'],
method=settings['method']
)
self.add_directly(outbound)




class SingBoxConfiguration(str):
Expand Down Expand Up @@ -711,9 +745,17 @@ def generate_v2ray_subscription(links: list) -> str:
return base64.b64encode('\n'.join(links).encode()).decode()



def generate_outline_subscription(proxies: dict, inbounds: dict, extra_data: dict) -> str:
conf = OutlineConfiguration()

format_variables = setup_format_variables(extra_data)
return process_inbounds_and_tags(inbounds, proxies, format_variables, mode="outline", conf=conf)


def generate_subscription(
user: "UserResponse",
config_format: Literal["v2ray", "clash-meta", "clash", "sing-box"],
config_format: Literal["v2ray", "clash-meta", "clash", "sing-box", "outline"],
as_base64: bool
) -> str:
kwargs = {"proxies": user.proxies, "inbounds": user.inbounds, "extra_data": user.__dict__}
Expand All @@ -726,6 +768,8 @@ def generate_subscription(
config = generate_clash_subscription(**kwargs)
elif config_format == 'sing-box':
config = generate_singbox_subscription(**kwargs)
elif config_format == 'outline':
config = generate_outline_subscription(**kwargs)
else:
raise ValueError(f'Unsupported format "{config_format}"')

Expand Down Expand Up @@ -843,15 +887,15 @@ def process_inbounds_and_tags(inbounds: dict, proxies: dict, format_variables: d
address=host['address'].format_map(format_variables),
inbound=host_inbound,
settings=settings.dict(no_obj=True)))
elif mode in ["clash", "sing-box"]:
elif mode in ["clash", "sing-box", "outline"]:
conf.add(
remark=host['remark'].format_map(format_variables),
address=host['address'].format_map(format_variables),
inbound=host_inbound,
settings=settings.dict(no_obj=True),
)

if mode in ["clash", "sing-box"]:
if mode in ["clash", "sing-box", "outline"]:
return conf.render()

return results
Expand Down
14 changes: 11 additions & 3 deletions app/views/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ def get_subscription_user_info(user: UserResponse) -> dict:
conf = generate_subscription(user=user, config_format="sing-box", as_base64=False)
return Response(content=conf, media_type="application/json", headers=response_headers)

elif re.match('^(SS|SSR|SSD|SSS|Outline|Shadowsocks|SSconf)', user_agent):
conf = generate_subscription(user=user, config_format="outline", as_base64=False)
return Response(content=conf, media_type="application/json", headers=response_headers)

else:
conf = generate_subscription(user=user, config_format="v2ray", as_base64=True)
return Response(content=conf, media_type="text/plain", headers=response_headers)
Expand All @@ -106,11 +110,11 @@ def user_subscription_info(token: str,
def user_subscription_with_client_type(
token: str,
request: Request,
client_type: str = Path(..., regex="sing-box|clash-meta|clash|v2ray"),
client_type: str = Path(..., regex="sing-box|clash-meta|clash|outline|v2ray"),
db: Session = Depends(get_db),
):
"""
Subscription link, v2ray, clash, sing-box, and clash-meta supported
Subscription link, v2ray, clash, sing-box, outline and clash-meta supported
"""

def get_subscription_user_info(user: UserResponse) -> dict:
Expand Down Expand Up @@ -163,5 +167,9 @@ def get_subscription_user_info(user: UserResponse) -> dict:
conf = generate_subscription(user=user, config_format="v2ray", as_base64=True)
return Response(content=conf, media_type="text/plain", headers=response_headers)

elif client_type == "outline":
conf = generate_subscription(user=user, config_format="outline", as_base64=False)
return Response(content=conf, media_type="application/json", headers=response_headers)

else:
raise HTTPException(status_code=400, detail="Invalid subscription type")
raise HTTPException(status_code=400, detail="Invalid subscription type")

0 comments on commit 0dbb063

Please sign in to comment.