├── .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 |
--------------------------------------------------------------------------------