Template
Issue invite configs as subscription URLs with redeem-based lifetime.
Admin picks inbound once, sets duration in days from Get config, and configures the 3x-ui /sub base URL. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+46
-4
@@ -32,9 +32,21 @@ def _settings_creds(settings: dict) -> dict:
|
||||
'username': (sync.get('xui_username') or '').strip(),
|
||||
'password': sync.get('xui_password') or '',
|
||||
'inbound_id': sync.get('xui_inbound_id'),
|
||||
'sub_url': (sync.get('xui_sub_url') or '').strip().rstrip('/'),
|
||||
}
|
||||
|
||||
|
||||
def build_subscription_url(settings: dict, sub_id: str) -> str:
|
||||
"""Build public subscription URL from panel settings + client subId."""
|
||||
sub_id = (sub_id or '').strip()
|
||||
if not sub_id:
|
||||
return ''
|
||||
base = _settings_creds(settings).get('sub_url') or ''
|
||||
if not base:
|
||||
return ''
|
||||
return f"{base}/{sub_id}"
|
||||
|
||||
|
||||
class XuiApiError(RuntimeError):
|
||||
pass
|
||||
|
||||
@@ -211,6 +223,7 @@ class XuiApi:
|
||||
'email': email,
|
||||
'config': vless or '',
|
||||
'links': links,
|
||||
'expiry_time': expiry_time,
|
||||
}
|
||||
|
||||
async def get_client_links(self, email: str) -> list:
|
||||
@@ -292,8 +305,14 @@ class XuiApi:
|
||||
raise XuiApiError(f'Failed to toggle 3x-ui client {email}')
|
||||
|
||||
|
||||
async def xui_create_vless_config(settings: dict, *, name: str, inbound_id: Optional[int] = None) -> dict:
|
||||
"""Create a VLESS client on 3x-ui and return {client_id, config, links}."""
|
||||
async def xui_create_vless_config(
|
||||
settings: dict,
|
||||
*,
|
||||
name: str,
|
||||
inbound_id: Optional[int] = None,
|
||||
expiry_time: int = 0,
|
||||
) -> dict:
|
||||
"""Create a VLESS client on 3x-ui and return {client_id, config, subscription_url, links}."""
|
||||
creds = _settings_creds(settings)
|
||||
inbound = inbound_id if inbound_id is not None else creds.get('inbound_id')
|
||||
try:
|
||||
@@ -312,16 +331,39 @@ async def xui_create_vless_config(settings: dict, *, name: str, inbound_id: Opti
|
||||
base = ''.join(ch if ch.isalnum() or ch in '._-+@' else '_' for ch in (name or 'user').strip())
|
||||
base = base[:48] or f'user_{secrets.token_hex(4)}'
|
||||
email = base
|
||||
created = None
|
||||
# Avoid collisions
|
||||
for _ in range(5):
|
||||
try:
|
||||
return await api.add_vless_client(email=email, inbound_id=inbound, comment=name or email)
|
||||
created = await api.add_vless_client(
|
||||
email=email,
|
||||
inbound_id=inbound,
|
||||
comment=name or email,
|
||||
expiry_time=int(expiry_time or 0),
|
||||
)
|
||||
break
|
||||
except XuiApiError as e:
|
||||
if 'exist' in str(e).lower() or 'duplicate' in str(e).lower() or 'already' in str(e).lower():
|
||||
email = f'{base}_{secrets.token_hex(3)}'
|
||||
continue
|
||||
raise
|
||||
return await api.add_vless_client(email=email, inbound_id=inbound, comment=name or email)
|
||||
if created is None:
|
||||
created = await api.add_vless_client(
|
||||
email=email,
|
||||
inbound_id=inbound,
|
||||
comment=name or email,
|
||||
expiry_time=int(expiry_time or 0),
|
||||
)
|
||||
|
||||
sub_url = build_subscription_url(settings, created.get('sub_id') or '')
|
||||
# Prefer subscription URL as the main share string when configured
|
||||
if sub_url:
|
||||
created['subscription_url'] = sub_url
|
||||
created['config'] = sub_url
|
||||
else:
|
||||
created['subscription_url'] = ''
|
||||
created['inbound_id'] = inbound
|
||||
return created
|
||||
|
||||
|
||||
async def xui_get_config(settings: dict, email: str) -> str:
|
||||
|
||||
Reference in New Issue
Block a user