├── .gitignore ├── LICENSE ├── README.md ├── bot.py ├── config.sample.yaml ├── remove_server.py ├── remove_user.py ├── reset_traffic.py ├── server.py ├── server_manager.py ├── sqlitedb.py ├── user.py └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | server.bash 2 | config.yaml 3 | config_test.yaml 4 | *.db 5 | *.pyc 6 | __pycache__/ 7 | .ipynb_ceckpoints/ 8 | *.ipynb 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 wlfvpn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # x-ui-plugin 2 | 3 | install x-ui 4 | https://github.com/wlfvpn/x-ui 5 | 6 | Change your configs 7 | `config.yaml` 8 | 9 | `python bot.py --config_path config.yaml` 10 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import logging 4 | import requests 5 | from telegram import __version__ as TG_VER 6 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, WebAppInfo 7 | from telegram.ext import Application, CallbackQueryHandler, CommandHandler, ContextTypes 8 | from server_manager import ServerManager 9 | import yaml 10 | from utils import load_config 11 | import argparse 12 | import datetime 13 | import random 14 | import asyncio 15 | 16 | # Enable logging 17 | logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO) 18 | logger = logging.getLogger(__name__) 19 | 20 | 21 | async def instructions(update: Update, context: ContextTypes.DEFAULT_TYPE): 22 | await context.bot.send_message(chat_id=update.effective_chat.id, text="""Download the applications below and import the generated link. 23 | Android: V2rayNG 24 | IOS: NapsternetV, shadowrocket 25 | Windows: v2rayN 26 | MacOS: V2RayXS """, parse_mode="HTML") 27 | 28 | async def gen_link(update: Update, context: ContextTypes.DEFAULT_TYPE): 29 | maintenance = await is_maintenance(update, context) 30 | if maintenance: 31 | return 32 | 33 | if not update.effective_user.username: 34 | await context.bot.send_message(chat_id=update.effective_chat.id, text="Please setup a username for your telegram account.") 35 | return 36 | 37 | if not await is_member(update, context, send_thank_you=False): 38 | return 39 | 40 | lock = asyncio.Lock() 41 | 42 | async with lock: 43 | urls = server_manager.generate_url(str(update.effective_user.id),str(update.effective_user.username)) 44 | 45 | print(f'Gave link to @{update.effective_user.username}') 46 | if urls: 47 | for url in urls: 48 | if url['url']: 49 | await context.bot.send_message(chat_id=update.effective_chat.id, text=url['desc']) 50 | await context.bot.send_message(chat_id=update.effective_chat.id, text="`"+url['url']+"`", parse_mode="MarkdownV2") 51 | else: 52 | await context.bot.send_message(chat_id=update.effective_chat.id, text="Something went wrong. Please try again in few mintues. If it happened again, please contact our support.") 53 | await context.bot.send_message(chat_id=update.effective_chat.id, text="مشکلی در ارتباط با سرورها پیش آمده. لطفا مجدد تکرار کنید.") 54 | 55 | async def is_maintenance(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool: 56 | config = load_config(config_path) 57 | if config['maintenance']: 58 | await context.bot.send_message(chat_id=update.effective_chat.id, text="Sorry. The bot is under maintanance right now.") 59 | await context.bot.send_message(chat_id=update.effective_chat.id, text=".در حال ارتقا ربات هستیم. ربات بصورت موقتی غیرفعال است.") 60 | await context.bot.send_message(chat_id=update.effective_chat.id, text="در حال حاضر سرور پر شده است. ") 61 | 62 | return config['maintenance'] 63 | 64 | 65 | async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: 66 | """Sends a message with three inline buttons attached.""" 67 | maintenance = await is_maintenance(update, context) 68 | if maintenance: 69 | return 70 | 71 | if not await is_member(update,context): 72 | return 73 | 74 | keyboard = [[InlineKeyboardButton("دریافت لینک شخصی", callback_data="gen_link")], 75 | [InlineKeyboardButton("گزارش استفاده", callback_data="usage")], 76 | [InlineKeyboardButton("رو چه نرم افزاری کار میکنه؟", callback_data="instructions")], 77 | [InlineKeyboardButton("می خواهم کمک کنم",url="https://t.me/+0l8_7FaM-UkyNzIx", callback_data="contribute")], 78 | [InlineKeyboardButton("لینک کانال", url="https://t.me/WomanLifeFreedomVPN",callback_data="contact_support")], 79 | [InlineKeyboardButton("تست سرعت", web_app=WebAppInfo(url="https://pcmag.speedtestcustom.com"))]] 80 | reply_markup = InlineKeyboardMarkup(keyboard) 81 | 82 | await update.message.reply_text("Please choose one of the following options:", reply_markup=reply_markup) 83 | 84 | async def gen_report(update: Update, context: ContextTypes.DEFAULT_TYPE): 85 | await context.bot.send_message(chat_id=update.effective_chat.id, text="هنوز این دکمه پیاده سازی نشده است.") 86 | 87 | async def button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: 88 | """Parses the CallbackQuery and updates the message text.""" 89 | query = update.callback_query 90 | 91 | # CallbackQueries need to be answered, even if no notification to the user is needed 92 | # Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery 93 | await query.answer() 94 | if query.data == "instructions": 95 | await instructions(update, context) 96 | elif query.data == "gen_link": 97 | await gen_link(update,context) 98 | elif query.data == "usage": 99 | await gen_report(update, context) 100 | 101 | 102 | async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: 103 | """Displays info on how to use the bot.""" 104 | await update.message.reply_text("Use /start to test this bot.") 105 | 106 | 107 | async def is_member(update: Update, context: ContextTypes.DEFAULT_TYPE, send_thank_you=True): 108 | config = load_config(config_path) 109 | # Check if the client is a member of the specified channel 110 | user_id = update.effective_user.id # update.message.from_user.id # Get the client's user ID 111 | try: 112 | chat_member = await context.bot.get_chat_member(chat_id=config["telegram_channel_id"], user_id=user_id) 113 | if chat_member.status in ["member", "creator"]: 114 | if send_thank_you: 115 | await context.bot.send_message(chat_id=update.effective_chat.id, text="Thank you for subscribing to our channel!") 116 | else: 117 | await context.bot.send_message(chat_id=update.effective_chat.id, text=f"Please subscribe to our channel {config['telegram_channel_id']}.") 118 | await context.bot.send_message(chat_id=update.effective_chat.id, text="لطفا ابتدا عضو کانال شوید. این وی پی ان محدود به اعضای کانال می باشد.") 119 | return chat_member.status in ["member", "creator"] 120 | except: 121 | logger.error(f"Error in checking the members of the channel. Please make sure robot is admin to your channel {config['telegram_channel_id']}") 122 | return False 123 | 124 | def main() -> None: 125 | # Parse the config file path from the command line arguments 126 | parser = argparse.ArgumentParser() 127 | parser.add_argument('--config_path', help='Path to the config file', default='config.yaml') 128 | args = parser.parse_args() 129 | global config_path 130 | config_path = args.config_path 131 | global server_manager 132 | server_manager = ServerManager(config_path=config_path) 133 | # Load the config file 134 | config = load_config(config_path) 135 | 136 | 137 | """Run the bot.""" 138 | # Create the Application and pass it your bot's token. 139 | application = Application.builder().token(config['telegram_bot_token']).build() 140 | 141 | application.add_handler(CommandHandler("start", start)) 142 | application.add_handler(CallbackQueryHandler(button)) 143 | 144 | # Run the bot until the user presses Ctrl-C 145 | application.run_polling() 146 | 147 | 148 | if __name__ == "__main__": 149 | main() 150 | 151 | -------------------------------------------------------------------------------- /config.sample.yaml: -------------------------------------------------------------------------------- 1 | # This setting randomly chooses a server between pools. FOr example in here we have 2 pools i.e. pool1 and pool2. 2 | # pool1 has 2 servers and pool2 has one server. It randomly chooses one server among pool1 and gives an url link then 3 | # it chooses randomly from pool2 (which is one server) and gives another link from pool2. At the end user will get two links 4 | # one link from each pool. 5 | 6 | telegram_bot_token: "TOKEN" #change it 7 | maintenance: false #turn it to true to force the bot to go into maintanance mode. 8 | generate_unique: true 9 | telegram_channel_id: "@womanlifefreedomvpn" 10 | 11 | pools: 12 | pool1: #one server will be selected in every pool 13 | "google.womanlifefreedom.vip": #example "google.com" 14 | cdn: true #set true if cdn proxy is on 15 | ip: "92.217.201.245" # if cdn is true and multi_port is active, you have to provide the ip. Otherwise it is optional 16 | max_users: 1500 # change it 17 | username: "myadminusername" 18 | password: "myadminpassword" 19 | port: 54321 #change it 20 | same_port: 21 | active: true 22 | port: 2053 #port used for vless ws tls behind cdn 23 | multi_port: 24 | active: false # only activate multi_port or same_port on one server. DO NOT SET BOTH TO TRUE 25 | traffic_limit: 15516192768 #14 GB 26 | description: "Server Location: Finland (google)" 27 | 28 | "earth.womanlifefreedom.vip": #example "google.com" 29 | cdn: true 30 | ip: "78.42.182.42" # if cdn is true and multi_port is active, you have to provide the ip. Otherwise it is optional 31 | max_users: 1700 # change it 32 | username: "myadminusername" 33 | password: "myadminpassword" 34 | port: 54321 #change it 35 | same_port: 36 | active: true 37 | port: 2053 38 | multi_port: 39 | active: false 40 | traffic_limit: 15516192768 #7GB 41 | description: "Server Location: Finland (earth)" 42 | pool2: 43 | "fire.womanlifefreedom.vip": #example "google.com" 44 | cdn: false 45 | ip: "78.43.182.22" # if cdn is true and multi_port is active, you have to provide the ip. Otherwise it is optional 46 | max_users: 1700 # change it 47 | username: "myadminusername" 48 | password: "myadminpassword" 49 | port: 54321 #change it 50 | same_port: 51 | active: false 52 | port: 2053 53 | multi_port: 54 | active: true #for multioport xtls CDN must be false 55 | traffic_limit: 15516192768 #7GB 56 | description: "Server Location: Finland (earth)" 57 | -------------------------------------------------------------------------------- /remove_server.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from utils import load_config 3 | from sqlitedb import SQLiteDB 4 | from server import Server 5 | from datetime import datetime 6 | import random 7 | import sqlite3 8 | 9 | server='earth.womanlifefreedom.vip' 10 | 11 | con = sqlite3.connect("database.db") 12 | cur = con.cursor() 13 | res = cur.execute(f"DELETE FROM users WHERE server='{server}';") 14 | res.fetchall() 15 | con.commit() 16 | res = cur.execute(f"DELETE FROM inbounds WHERE server='{server}';") 17 | res.fetchall() 18 | con.commit() 19 | con.close() -------------------------------------------------------------------------------- /remove_user.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from utils import load_config 3 | from sqlitedb import SQLiteDB 4 | from server import Server 5 | from datetime import datetime 6 | import random 7 | import sqlite3 8 | 9 | telegram_username='mhmdreza_farokhi8' 10 | remark = '5861885059@WomanLifeFreedomVPNSupport' 11 | 12 | con = sqlite3.connect("database.db") 13 | cur = con.cursor() 14 | res = cur.execute(f"DELETE FROM users WHERE telegram_username='{telegram_username}';") 15 | res.fetchall() 16 | con.commit() 17 | con.close() 18 | 19 | 20 | # then remove manually from x-ui fro that server 21 | 22 | 23 | 24 | # con = sqlite3.connec 25 | # t("/etc/x-ui/x-ui.db") 26 | # cur = con.cursor() 27 | # res = cur.execute(f"DELETE FROM inbounds WHERE remark='{remark}';") 28 | # res.fetchall() 29 | # con.commit() 30 | # con.close() 31 | -------------------------------------------------------------------------------- /reset_traffic.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | con = sqlite3.connect("/etc/x-ui/x-ui.db") 3 | cur = con.cursor() 4 | res = cur.execute("UPDATE inbounds SET up=0, down=0, enable=1") 5 | # res = cur.execute("UPDATE inbounds SET down=0 WHERE remark='test'") 6 | # res = cur.execute("UPDATE inbounds SET enable=0 WHERE remark='test'") 7 | res.fetchone() 8 | con.commit() 9 | con.close() 10 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import uuid 3 | import random 4 | import json 5 | from user import gen_user_config_vless_xtls,gen_user_config_vless_ws 6 | from utils import load_config 7 | from sqlitedb import SQLiteDB 8 | from datetime import datetime 9 | 10 | class Server(): 11 | def __init__(self, address, max_users, username, password, port, traffic_limit, description, same_port, multi_port, cdn, ip, db): 12 | self.address = address 13 | self.max_users = max_users 14 | self.username = username 15 | self.password = password 16 | self.port = port 17 | self.traffic_limit = traffic_limit 18 | self.db = db 19 | self.description = description 20 | self.same_port = same_port 21 | self.multi_port = multi_port 22 | self.cdn = cdn 23 | self.ip = ip 24 | if self.same_port['active'] == self.multi_port['active']: 25 | raise Exception(f"Turn on either 'same_port' or 'multiport' for {self.address}.") 26 | 27 | if self.cdn and self.multi_port['active']: 28 | raise Exception(f"CDN and 'multi_port' cannot be ON at the same time for {self.address}.") 29 | 30 | cloudflare_http_ports = [80, 8080, 8880, 2052, 2082, 2086, 2095] 31 | cloudflare_https_ports = [443, 2053, 2083, 2087, 2096, 8443] 32 | 33 | if self.cdn and self.port not in cloudflare_http_ports: #change to cloudflare_http_ports if you use https panel 34 | self.url = f"{self.ip}:{self.port}" 35 | else: 36 | self.url = f"{self.address}:{self.port}" 37 | 38 | if self.same_port['active']: 39 | self.initialize_inbound() 40 | print('initialized inbound') 41 | 42 | print(f"Server {self.address} initialized successfully.") 43 | 44 | def login(self): 45 | payload = {'username': self.username, 'password': self.password} 46 | url = f"http://{self.url}/login" #TODO: Make it with https 47 | r = requests.post(url, data=payload) 48 | return r 49 | 50 | def initialize_inbound(self): 51 | remark = "vless-ws-tls-cdn" 52 | if self.db.query_from_remark_and_server('id',self.address,remark) is not None: 53 | return 54 | random_client_id = str(uuid.uuid4()) 55 | 56 | creation_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 57 | user_config = gen_user_config_vless_ws(name=remark, email="initialize@womanlifefreedom", uuid=random_client_id, server_address=self.address, port=self.same_port['port'], traffic_limit=self.traffic_limit) 58 | r = self.login() 59 | r = requests.post(f"http://{self.url}/xui/inbound/add", data=user_config, cookies=r.cookies) #TODO: Make it with http 60 | print(r) 61 | self.db.add_row('inbounds',(r.json()['obj']['id'],remark, r.json()['obj']['settings'], self.address, self.same_port['port'], 0, creation_date)) 62 | 63 | def get_load(self): 64 | return 0 65 | 66 | def generate_url(self, telegram_id, telegram_username) -> tuple[bool,str]: 67 | random_client_id = str(uuid.uuid4()) 68 | remark = telegram_id + '@' + telegram_username 69 | creation_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 70 | links = [] 71 | 72 | 73 | if self.same_port['active']: 74 | inbound_name = "vless-ws-tls-cdn" 75 | # current_setting = self.db.query_from_remark_and_server('settings',self.address,inbound_name) 76 | # clients = json.loads(current_setting)['clients'] 77 | clients = self.db.get_clients(self.address, self.traffic_limit) 78 | email = remark 79 | config = gen_user_config_vless_ws(name=inbound_name, email=email, uuid=random_client_id, server_address=self.address, port=self.same_port['port'], traffic_limit=self.traffic_limit, clients=clients) 80 | # print(config) 81 | inbound_id = self.db.query_from_remark_and_server('id',self.address,inbound_name) 82 | r = self.login() 83 | r = requests.post(f"http://{self.url}/xui/inbound/update/{inbound_id}", data=config, cookies=r.cookies) #TODO: Make it with https 84 | result = json.loads(r.text) 85 | if result['success']: 86 | self.db.update_settings(inbound_id,result['obj']['settings']) 87 | 88 | link = f"vless://{random_client_id}@66.235.200.136:{self.same_port['port']}?type=ws&security=tls&host={self.address}&sni={self.address}&alpn=http/1.1&path=/wlf?ed=2048#WomanLifeFreedomVPN@{telegram_username}" 89 | self.db.add_row('users',(telegram_id, telegram_username, remark, random_client_id, creation_date, link, self.address, self.same_port['port'],'same_port',self.description)) 90 | print(link) 91 | links.append(link) 92 | else: 93 | return False, None 94 | 95 | if self.multi_port['active']: 96 | port = self.db.generate_random_port(self.address) 97 | if port is None: 98 | print('Error, cannot get any ports from', self.address) #TODO: use logging 99 | return False, None 100 | user_config = gen_user_config_vless_xtls(remark, telegram_id, random_client_id, self.address, port, self.traffic_limit) 101 | r = self.login() 102 | r = requests.post(f"http://{self.url}/xui/inbound/add", data=user_config, cookies=r.cookies) #TODO: Make it with https 103 | if json.loads(r.text)['success']: 104 | # print('Added', remark, r.content) 105 | if self.cdn: 106 | print('ERROR: xtls is not supported in CDN mode.') 107 | link = f"vless://{random_client_id}@{self.address}:{port}?type=tcp&security=xtls&flow=xtls-rprx-direct&sni={self.address}&alpn=h2,http/1.1#{remark}" 108 | self.db.add_row('users',(telegram_id, telegram_username, remark, random_client_id, creation_date, link, self.address, port,'multi_port', self.description)) 109 | 110 | print(link) 111 | links.append(link) 112 | else: 113 | print("Error:",r.content) 114 | return False, link[0] 115 | 116 | return True, '\n \n'.join(links) 117 | 118 | if __name__=="__main__": 119 | config = load_config('config.yaml') 120 | 121 | db = SQLiteDB('database.db') 122 | server_name, server_config = config['pools']['pool1'].popitem() 123 | 124 | Server = Server(server_name, **server_config, db = db) 125 | num_accounts = 1 126 | for i in range(num_accounts): 127 | Server.generate_url(str(i),'test-gp') 128 | -------------------------------------------------------------------------------- /server_manager.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from utils import load_config 3 | from sqlitedb import SQLiteDB 4 | from server import Server 5 | from datetime import datetime 6 | import random 7 | 8 | class ServerManager(): 9 | def __init__(self,database_path='database.db',config_path='config.yaml'): 10 | self.config = load_config(config_path) 11 | self.servers = [] 12 | self.db = SQLiteDB(database_path) 13 | for pool in self.config['pools'].keys(): 14 | servers_in_a_pool = {} 15 | for server_addr, server_config in self.config['pools'][pool].items(): 16 | servers_in_a_pool[server_addr] = Server(server_addr,**server_config, db=self.db) 17 | self.servers.append(servers_in_a_pool) 18 | 19 | def get_low_load_servers(self)-> Server: 20 | # return min(self.servers.values(), key=lambda s: s.get_load()) 21 | low_load_servers = [] 22 | for pool in self.servers: 23 | low_load_servers_in_a_pool = [] 24 | for server_address, server in pool.items(): 25 | if self.db.count_entries_for_server(server=server_address)<=server.max_users: 26 | low_load_servers_in_a_pool.append(server) 27 | low_load_servers.append(low_load_servers_in_a_pool) 28 | if not low_load_servers: 29 | return None 30 | 31 | output = [] 32 | for pool in low_load_servers: 33 | output.append(random.choice(pool)) 34 | return output 35 | 36 | 37 | def generate_url(self, telegram_id, telegram_username): 38 | if self.config['generate_unique']: 39 | existing_links_and_servers_desc = self.db.get_links_and_server_desc(telegram_id) 40 | # existing_server = self.db.get_server(telegram_id) 41 | if existing_links_and_servers_desc is not None: 42 | return existing_links_and_servers_desc 43 | servers = self.get_low_load_servers() 44 | if servers is None: 45 | print('Error: server is full.') 46 | return False, 'سرور در حال حاضر پر می باشد. لطفا بعدا مجدد تلاش کنید...' 47 | output = [] 48 | remark = telegram_id + '@' + telegram_username 49 | for server in servers: 50 | ret, link = server.generate_url(telegram_id,telegram_username) 51 | if ret: 52 | output.append({'desc':server.description,'url':link}) 53 | else: 54 | print(f'Error: Cannot generate link for {telegram_username} from {server.address}') 55 | output.append({'desc':f"Error! Could not generate link for {server.address}",'url':None}) 56 | 57 | return output 58 | 59 | if __name__=="__main__": 60 | ServerManager= ServerManager('test.db') 61 | ServerManager.generate_url('211','server_manager_test') 62 | -------------------------------------------------------------------------------- /sqlitedb.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | import random 3 | 4 | class SQLiteDB: 5 | def __init__(self, db_path): 6 | self.db_path = db_path 7 | self.connect() 8 | self.conn.row_factory = sqlite3.Row 9 | 10 | self.cursor.execute(f"SELECT name FROM sqlite_master WHERE type='table' AND name='users'") 11 | if not self.cursor.fetchone(): 12 | self.cursor.execute(f"CREATE TABLE users (telegram_id, telegram_username, remark, uuid, creation_date, link, server, port, mode, server_desc)") 13 | 14 | self.cursor.execute(f"SELECT name FROM sqlite_master WHERE type='table' AND name='inbounds'") 15 | if not self.cursor.fetchone(): 16 | self.cursor.execute(f"CREATE TABLE inbounds (id, remark, settings, server, port, max_limit, creation_date)") 17 | 18 | def update_settings(self, id, settings): 19 | # update the settings for the given id 20 | self.conn.execute("UPDATE inbounds SET settings = ? WHERE id = ?", (settings, id)) 21 | 22 | # commit the changes and close the connection 23 | self.conn.commit() 24 | 25 | def get_inbound_id_from_remark_and_server(self, server, remark): 26 | """Count the number of entries with the given server in the given table""" 27 | query = f"SELECT id FROM inbounds WHERE server = ? AND remark = ?" 28 | self.cursor.execute(query, (server,remark)) 29 | row = self.cursor.fetchone() 30 | if row: 31 | return row[0] 32 | else: 33 | return None 34 | 35 | def add_row(self, table_name, values): 36 | """Insert a row into the given table, creating the table if it does not exist""" 37 | placeholders = ", ".join("?" * len(values)) 38 | query = f"INSERT INTO {table_name} VALUES ({placeholders})" 39 | self.cursor.execute(query, values) 40 | self.conn.commit() 41 | 42 | 43 | 44 | def count_entries_for_server(self, server): 45 | """Count the number of entries with the given server in the given table""" 46 | query = f"SELECT COUNT(*) FROM users WHERE server = ?" 47 | self.cursor.execute(query, (server,)) 48 | row = self.cursor.fetchone() 49 | return row[0] 50 | 51 | def query(self,table_name, requested_column, match_column_name,match_column_value ): 52 | query = f"SELECT ? FROM ? WHERE ? = ?" 53 | self.cursor.execute(query, (requested_column,table_name,match_column_name,match_column_value)) 54 | rows = self.cursor.fetchone() 55 | if rows: 56 | return rows[0] 57 | return None 58 | 59 | def query_from_remark_and_server(self, column_name, server, remark): 60 | """Count the number of entries with the given server in the given table""" 61 | query = f"SELECT {column_name} FROM inbounds WHERE server = ? AND remark = ?" 62 | self.cursor.execute(query, (server,remark)) 63 | row = self.cursor.fetchone() 64 | if row: 65 | return row[0] 66 | else: 67 | return None 68 | 69 | def get_clients(self, server,totalGB): 70 | # Select the columns you want to retrieve 71 | self.cursor.execute("SELECT remark, uuid FROM users WHERE server=?", (server,)) 72 | 73 | # Fetch all rows as a list of tuples 74 | rows = self.cursor.fetchall() 75 | 76 | # Create an empty list to store the JSON objects 77 | json_list = [] 78 | 79 | # Iterate through the rows 80 | for row in rows: 81 | json_list.append({'email': row[0], 'id': row[1], 'flow': 'xtls-rprx-direct', 'totalGB': totalGB}) 82 | 83 | return json_list 84 | 85 | # def get_links_and_server(self, telegram_id): 86 | # """Returns the link for the given telegram_id, or None if not found""" 87 | # query = f"SELECT link, server FROM users WHERE telegram_id = ?" 88 | # self.cursor.execute(query, (telegram_id,)) 89 | # rows = self.cursor.fetchall() 90 | 91 | # if rows: 92 | # return [{'url': row[0], 'server': row[1]} for row in rows] 93 | # return None 94 | 95 | def get_links_and_server_desc(self, telegram_id): 96 | """Returns a list of dictionaries containing the link and server for the given telegram_id, or None if not found""" 97 | query = f"SELECT link, server_desc FROM users WHERE telegram_id = ?" 98 | self.cursor.execute(query, (telegram_id,)) 99 | rows = self.cursor.fetchall() 100 | if rows: 101 | result = [] 102 | current_server = rows[0][1] 103 | current_urls = [] 104 | for row in rows: 105 | if row[1] == current_server: 106 | current_urls.append(row[0]) 107 | else: 108 | result.append({'desc': current_server, 'url': '\n \n'.join(current_urls)}) 109 | current_server = row[1] 110 | current_urls = [row[0]] 111 | result.append({'desc': current_server, 'url': '\n \n'.join(current_urls)}) 112 | return result 113 | return None 114 | 115 | def get_server(self, telegram_id): 116 | """Returns the link for the given telegram_id, or None if not found""" 117 | query = f"SELECT server FROM users WHERE telegram_id = ?" 118 | self.cursor.execute(query, (telegram_id,)) 119 | rows = self.cursor.fetchone() 120 | if rows: 121 | return rows[0] 122 | return None 123 | 124 | def generate_random_port(self, server): 125 | """Generates a random port that is not in the table for the given server""" 126 | port = random.randint(10000, 50000) 127 | query = f"SELECT ? WHERE NOT EXISTS (SELECT 1 FROM users WHERE server = ? AND port = ?)" 128 | self.cursor.execute(query, (port, server, port)) 129 | row = self.cursor.fetchone() 130 | if row: 131 | return row[0] 132 | return None 133 | 134 | def remove_row(self, table_name, criteria): 135 | """Delete a row from the given table based on the given criteria, creating the table if it does not exist""" 136 | query = f"DELETE FROM {table_name} WHERE {criteria}" 137 | self.cursor.execute(query) 138 | self.conn.commit() 139 | 140 | def connect(self): 141 | self.conn = sqlite3.connect(self.db_path) 142 | self.cursor = self.conn.cursor() 143 | 144 | def close(self): 145 | """Close the database connection""" 146 | self.conn.close() 147 | 148 | 149 | def __del__(self): 150 | self.cursor.close() 151 | self.conn.close() 152 | 153 | if __name__=="__main__": 154 | db = SQLiteDB('database.db') 155 | # db.add_row('users',('my_id', 'my_username', 'my_id@my_username', '2022', 'vles://xyz', '127.0.0.1', '443', 0, '700000')) 156 | # print(db.generate_random_port('127.0.0.1')) 157 | print(db.get_settings('google.womanlifefreedom.vip',1000)) 158 | db.close() -------------------------------------------------------------------------------- /user.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import uuid 3 | import random 4 | import json 5 | 6 | def gen_user_config_vless_xtls(name :str,email, my_uuid:str, server_address:str, port: int, traffic_limit, clients=None): 7 | new_client = [ 8 | {"email": email, 9 | "id": my_uuid, 10 | "flow": "xtls-rprx-direct", 11 | }] 12 | if clients: 13 | clients += new_client 14 | else: 15 | clients = new_client 16 | 17 | clients = {"clients": clients, 18 | "decryption": "none", 19 | "fallbacks": [] 20 | } 21 | 22 | streamsetting = { 23 | "network": "tcp", 24 | "security": "xtls", 25 | "xtlsSettings": { 26 | "serverName": server_address, 27 | "alpn": "h2,http/1.1", 28 | "certificates": [ 29 | { 30 | "certificateFile": "/root/cert.crt", 31 | "keyFile": "/root/private.key" 32 | } 33 | ] 34 | }, 35 | "tcpSettings": { 36 | "acceptProxyProtocol": False, 37 | "header": { 38 | "type": "none" 39 | } 40 | } 41 | } 42 | 43 | sniff_sett={ 44 | "enabled": True, 45 | "destOverride": [ 46 | "http", 47 | "tls" 48 | ] 49 | } 50 | 51 | data = {'up':0, 52 | 'down':0, 53 | 'total':traffic_limit, 54 | 'remark':name, 55 | 'enable':'true', 56 | 'expiryTime':0, 57 | 'listen':None, 58 | 'port':port , 59 | 'protocol':"vless", 60 | 'settings' : json.dumps(clients), 61 | 'streamSettings':json.dumps(streamsetting), 62 | 'sniffing':json.dumps(sniff_sett) 63 | } 64 | return data 65 | 66 | 67 | def gen_user_config_vless_ws(name :str,email, uuid:str, server_address:str, port: int, traffic_limit=0,clients=None): 68 | new_client = [ 69 | {"email": email, 70 | "id": uuid, 71 | "flow": "xtls-rprx-direct", 72 | "totalGB": traffic_limit 73 | 74 | }] 75 | if clients: 76 | clients += new_client 77 | else: 78 | clients = new_client 79 | 80 | clients = {"clients": clients, 81 | "decryption": "none", 82 | "fallbacks": [] 83 | } 84 | 85 | streamsetting = { 86 | "network": "ws", 87 | "security": "tls", 88 | "tlsSettings": { 89 | "serverName": server_address, 90 | "alpn": ["http/1.1"], 91 | "certificates": [ 92 | { 93 | "certificateFile": "/root/cert.crt", 94 | "keyFile": "/root/private.key" 95 | } 96 | ] 97 | }, 98 | "wsSettings": { 99 | "acceptProxyProtocol": False, 100 | "path": "/wlf?ed=2048", 101 | "header": { 102 | "Host": "google.womanlifefreedom.vip", 103 | "headerType": "none" 104 | } 105 | } 106 | } 107 | 108 | sniff_sett={ 109 | "enabled": True, 110 | "destOverride": [ 111 | "http", 112 | "tls" 113 | ] 114 | } 115 | 116 | data = {'up':0, 117 | 'down':0, 118 | 'total':0, 119 | 'remark':name, 120 | 'enable':'true', 121 | 'expiryTime':0, 122 | 'listen':None, 123 | 'port':port , 124 | 'protocol':"vless", 125 | 'settings' : json.dumps(clients), 126 | 'streamSettings':json.dumps(streamsetting), 127 | 'sniffing':json.dumps(sniff_sett) 128 | } 129 | return data 130 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | 3 | 4 | def load_config(path='config.yaml'): 5 | with open(path, 'r') as stream: 6 | config = yaml.safe_load(stream) 7 | return config 8 | --------------------------------------------------------------------------------