redzedbot 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
redzedbot/__init__.py ADDED
@@ -0,0 +1,9 @@
1
+ """
2
+ redzedbot - Async Free Fire Bot Library
3
+ """
4
+
5
+ from .client import redzedbot
6
+ from .guest import login
7
+
8
+ __version__ = "5.0.0"
9
+ __all__ = ["redzedbot", "login"]
redzedbot/auth.py ADDED
@@ -0,0 +1,248 @@
1
+ """
2
+ Authentication and login handling
3
+ """
4
+
5
+ import asyncio
6
+ import aiohttp
7
+ import json
8
+ import ssl
9
+ from typing import Dict, Optional, Tuple
10
+ from datetime import datetime
11
+ from .proto import ParaHex_pb2
12
+ from .utils import get_random_user_agent, encrypt_proto
13
+ from .config import Config
14
+
15
+
16
+ async def generate_access_token(uid: str, password: str) -> Tuple[Optional[str], Optional[str]]:
17
+ """Generate Garena access token"""
18
+ url = "https://100067.connect.garena.com/oauth/guest/token/grant"
19
+
20
+ headers = {
21
+ "Host": "100067.connect.garena.com",
22
+ "User-Agent": await get_random_user_agent(),
23
+ "Content-Type": "application/x-www-form-urlencoded",
24
+ "Accept-Encoding": "gzip, deflate, br",
25
+ "Connection": "close"
26
+ }
27
+
28
+ data = {
29
+ "uid": uid,
30
+ "password": password,
31
+ "response_type": "token",
32
+ "client_type": "2",
33
+ "client_secret": "2ee44819e9b4598845141067b281621874d0d5d7af9d8f7e00c1e54715b7d1e3",
34
+ "client_id": "100067"
35
+ }
36
+
37
+ try:
38
+ async with aiohttp.ClientSession() as session:
39
+ async with session.post(url, headers=headers, data=data) as response:
40
+ if response.status != 200:
41
+ return None, None
42
+
43
+ data = await response.json()
44
+ open_id = data.get("open_id")
45
+ access_token = data.get("access_token")
46
+
47
+ return (open_id, access_token) if open_id and access_token else (None, None)
48
+
49
+ except Exception as e:
50
+ print(f"Token generation error: {e}")
51
+ return None, None
52
+
53
+
54
+ async def create_payload(open_id: str, access_token: str) -> bytes:
55
+ """Create encrypted protobuf payload for login"""
56
+ major_login = ParaHex_pb2.MajorLogin()
57
+
58
+ major_login.event_time = str(datetime.now())[:-7]
59
+ major_login.game_name = "free fire"
60
+ major_login.platform_id = 1
61
+ major_login.client_version = Config.VERSION
62
+ major_login.system_software = "Android OS 9 / API-28 (PQ3B.190801.10101846/G9650ZHU2ARC6)"
63
+ major_login.system_hardware = "Handheld"
64
+ major_login.telecom_operator = "Verizon"
65
+ major_login.network_type = "WIFI"
66
+ major_login.screen_width = 1920
67
+ major_login.screen_height = 1080
68
+ major_login.screen_dpi = "280"
69
+ major_login.processor_details = "ARM64 FP ASIMD AES VMH | 2865 | 4"
70
+ major_login.memory = 3003
71
+ major_login.gpu_renderer = "Adreno (TM) 640"
72
+ major_login.gpu_version = "OpenGL ES 3.1 v1.46"
73
+ major_login.unique_device_id = "Google|34a7dcdf-a7d5-4cb6-8d7e-3b0e448a0c57"
74
+ major_login.client_ip = "223.191.51.89"
75
+ major_login.language = "en"
76
+ major_login.open_id = open_id
77
+ major_login.open_id_type = "4"
78
+ major_login.device_type = "Handheld"
79
+
80
+ memory_available = major_login.memory_available
81
+ memory_available.version = 55
82
+ memory_available.hidden_value = 81
83
+
84
+ major_login.access_token = access_token
85
+ major_login.platform_sdk_id = 1
86
+ major_login.network_operator_a = "Verizon"
87
+ major_login.network_type_a = "WIFI"
88
+ major_login.client_using_version = "7428b253defc164018c604a1ebbfebdf"
89
+ major_login.external_storage_total = 36235
90
+ major_login.external_storage_available = 31335
91
+ major_login.internal_storage_total = 2519
92
+ major_login.internal_storage_available = 703
93
+ major_login.game_disk_storage_available = 25010
94
+ major_login.game_disk_storage_total = 26628
95
+ major_login.external_sdcard_avail_storage = 32992
96
+ major_login.external_sdcard_total_storage = 36235
97
+ major_login.login_by = 3
98
+ major_login.library_path = "/data/app/com.dts.freefireth-YPKM8jHEwAJlhpmhDhv5MQ==/lib/arm64"
99
+ major_login.reg_avatar = 1
100
+ major_login.library_token = "5b892aaabd688e571f688053118a162b|/data/app/com.dts.freefireth-YPKM8jHEwAJlhpmhDhv5MQ==/base.apk"
101
+ major_login.channel_type = 3
102
+ major_login.cpu_type = 2
103
+ major_login.cpu_architecture = "64"
104
+ major_login.client_version_code = "2019118695"
105
+ major_login.graphics_api = "OpenGLES2"
106
+ major_login.supported_astc_bitset = 16383
107
+ major_login.login_open_id_type = 4
108
+ major_login.analytics_detail = b"FwQVTgUPX1UaUllDDwcWCRBpWAUOUgsvA1snWlBaO1kFYg=="
109
+ major_login.loading_time = 13564
110
+ major_login.release_channel = "android"
111
+ major_login.extra_info = "KqsHTymw5/5GB23YGniUYN2/q47GATrq7eFeRatf0NkwLKEMQ0PK5BKEk72dPflAxUlEBir6Vtey83XqF593qsl8hwY="
112
+ major_login.android_engine_init_flag = 110009
113
+ major_login.if_push = 1
114
+ major_login.is_vpn = 1
115
+ major_login.origin_platform_type = "4"
116
+ major_login.primary_platform_type = "4"
117
+
118
+ string = major_login.SerializeToString()
119
+ return await encrypt_proto(string)
120
+
121
+
122
+ async def major_login(open_id: str, access_token: str) -> Optional[bytes]:
123
+ """Perform major login"""
124
+ if not Config._updated:
125
+ await Config.auto_update()
126
+
127
+ payload = await create_payload(open_id, access_token)
128
+ url = f"{Config.LOGIN_URL}MajorLogin"
129
+
130
+ headers = {
131
+ 'User-Agent': await get_random_user_agent(),
132
+ 'Connection': "Keep-Alive",
133
+ 'Accept-Encoding': "gzip",
134
+ 'Content-Type': "application/x-www-form-urlencoded",
135
+ 'Expect': "100-continue",
136
+ 'X-Unity-Version': "2018.4.11f1",
137
+ 'X-GA': "v1 1",
138
+ 'ReleaseVersion': Config.OB
139
+ }
140
+
141
+ ssl_context = ssl.create_default_context()
142
+ ssl_context.check_hostname = False
143
+ ssl_context.verify_mode = ssl.CERT_NONE
144
+
145
+ try:
146
+ async with aiohttp.ClientSession() as session:
147
+ async with session.post(url, data=payload, headers=headers, ssl=ssl_context) as response:
148
+ response_content = await response.read()
149
+ if response.status == 200:
150
+ return response_content
151
+ return None
152
+ except Exception as e:
153
+ print(f"Major login error: {e}")
154
+ return None
155
+
156
+
157
+ async def get_login_data(major_response: bytes, open_id: str, access_token: str) -> Optional[Dict]:
158
+ """Get login data from major login response"""
159
+ try:
160
+ proto = ParaHex_pb2.MajorLoginRes()
161
+ proto.ParseFromString(major_response)
162
+
163
+ clientbp = proto.url
164
+ token = proto.token
165
+ account_uid = proto.account_uid
166
+ timestamp = proto.timestamp
167
+ key = proto.key
168
+ iv = proto.iv
169
+
170
+ payload = await create_payload(open_id, access_token)
171
+ login_url = f"{clientbp}/GetLoginData"
172
+
173
+ headers = {
174
+ 'User-Agent': await get_random_user_agent(),
175
+ 'Connection': "Keep-Alive",
176
+ 'Accept-Encoding': "gzip",
177
+ 'Content-Type': "application/x-www-form-urlencoded",
178
+ 'Expect': "100-continue",
179
+ 'X-Unity-Version': "2018.4.11f1",
180
+ 'X-GA': "v1 1",
181
+ 'ReleaseVersion': Config.OB,
182
+ 'Authorization': f"Bearer {token}"
183
+ }
184
+
185
+ ssl_context = ssl.create_default_context()
186
+ ssl_context.check_hostname = False
187
+ ssl_context.verify_mode = ssl.CERT_NONE
188
+
189
+ async with aiohttp.ClientSession() as session:
190
+ async with session.post(login_url, data=payload, headers=headers, ssl=ssl_context) as response:
191
+ if response.status != 200:
192
+ return None
193
+
194
+ response_data = await response.read()
195
+
196
+ proto = ParaHex_pb2.GetLoginData()
197
+ proto.ParseFromString(response_data)
198
+
199
+ online_ports = proto.Online_IP_Port
200
+ chat_ports = proto.AccountIP_Port
201
+ online_ip, online_port = online_ports.split(":")
202
+ chat_ip, chat_port = chat_ports.split(":")
203
+
204
+ return {
205
+ 'account_uid': account_uid,
206
+ 'nickname': proto.AccountName,
207
+ 'region': proto.Region,
208
+ 'online_ip': online_ip,
209
+ 'online_port': online_port,
210
+ 'chat_ip': chat_ip,
211
+ 'chat_port': chat_port,
212
+ 'clan_id': proto.Clan_ID if proto.Clan_ID else None,
213
+ 'token': token,
214
+ 'timestamp': timestamp,
215
+ 'key': key,
216
+ 'iv': iv,
217
+ 'url':clientbp
218
+
219
+ }
220
+
221
+ except Exception as e:
222
+ print(f"Login data error: {e}")
223
+ return None
224
+
225
+
226
+ async def create_auth_packet(account_uid: int, token: str, timestamp: int, key: bytes, iv: bytes) -> str:
227
+ """Create authentication packet"""
228
+ from .utils import encode_hex, encrypt_packet
229
+
230
+ uid_hex = hex(account_uid)[2:]
231
+ uid_length = len(uid_hex)
232
+ encrypted_timestamp = await encode_hex(timestamp)
233
+ encrypted_account_token = token.encode().hex()
234
+ encrypted_packet = await encrypt_packet(encrypted_account_token, key, iv)
235
+ encrypted_packet_length = hex(len(encrypted_packet) // 2)[2:]
236
+
237
+ if uid_length == 9:
238
+ headers = '0000000'
239
+ elif uid_length == 8:
240
+ headers = '00000000'
241
+ elif uid_length == 10:
242
+ headers = '000000'
243
+ elif uid_length == 7:
244
+ headers = '000000000'
245
+ else:
246
+ headers = '0000000'
247
+
248
+ return f"0115{headers}{uid_hex}{encrypted_timestamp}00000{encrypted_packet_length}{encrypted_packet}"
redzedbot/client.py ADDED
@@ -0,0 +1,326 @@
1
+ """
2
+ Main redzedbot client class
3
+ """
4
+
5
+ import asyncio
6
+ from typing import Callable, Dict, Optional, Any
7
+ from .auth import generate_access_token, major_login, get_login_data, create_auth_packet
8
+ from .connection import OnlineConnection, ChatConnection
9
+ from .message import Message
10
+ from .utils import get_random_user_agent
11
+ import requests
12
+ from .config import Config
13
+ from .utils import create_proto,E_AEs
14
+
15
+ class redzedbot:
16
+ """
17
+ Main bot client class with decorator-based event handling
18
+ """
19
+
20
+ def __init__(self, uid: str, password: str):
21
+ self.uid = uid
22
+ self.password = password
23
+
24
+ self.is_connected = False
25
+ self.chat_connected = False
26
+ self.online_connected = False
27
+
28
+ self.nickname = None
29
+ self.account_uid = None
30
+ self.region = None
31
+ self.clan_id = None
32
+
33
+ self._key = None
34
+ self._iv = None
35
+ self._token = None
36
+ self._timestamp = None
37
+ self._auth_packet = None
38
+
39
+ self._online_conn = None
40
+ self._chat_conn = None
41
+
42
+ self._message_handlers = []
43
+ self._ready_handlers = []
44
+
45
+ self._ready_event = asyncio.Event()
46
+
47
+ async def _authenticate(self) -> bool:
48
+ """Internal authentication process"""
49
+ try:
50
+ from .config import Config
51
+ if not Config._updated:
52
+
53
+ await Config.auto_update()
54
+
55
+
56
+ open_id, access_token = await generate_access_token(self.uid, self.password)
57
+ if not open_id or not access_token:
58
+ return False
59
+
60
+ print(f'LoginURL : {Config.LOGIN_URL}MajorLogin , Version {Config.VERSION} , OB: {Config.OB}')
61
+ major_response = await major_login(open_id, access_token)
62
+ if not major_response:
63
+ return False
64
+
65
+ login_data = await get_login_data(major_response, open_id, access_token)
66
+ if not login_data:
67
+ return False
68
+
69
+ self.account_uid = login_data['account_uid']
70
+ self.nickname = login_data['nickname']
71
+ self.region = login_data['region']
72
+ self.clan_id = login_data.get('clan_id')
73
+ self._clientbp = login_data['url']
74
+ self._key = login_data['key']
75
+ self._iv = login_data['iv']
76
+ self._token = login_data['token']
77
+ self._timestamp = login_data['timestamp']
78
+ self._online_conn = OnlineConnection(
79
+ login_data['online_ip'],
80
+ login_data['online_port'],
81
+ self._key,
82
+ self._iv
83
+ )
84
+
85
+ self._chat_conn = ChatConnection(
86
+ login_data['chat_ip'],
87
+ login_data['chat_port'],
88
+ self._key,
89
+ self._iv,
90
+ self._process_message
91
+ )
92
+
93
+ self._auth_packet = await create_auth_packet(
94
+ self.account_uid,
95
+ self._token,
96
+ self._timestamp,
97
+ self._key,
98
+ self._iv
99
+ )
100
+
101
+ self.is_connected = True
102
+ return True
103
+
104
+ except Exception as e:
105
+ print(f"Authentication error: {e}")
106
+ return False
107
+
108
+
109
+
110
+ async def add_friend(self, uid: int):
111
+ """
112
+ Add Friend Via UID.
113
+
114
+ Example:
115
+ await bot.add_friend(6728454010)
116
+ """
117
+
118
+
119
+ try:
120
+ user_id = int(uid)
121
+ except ValueError:
122
+ return "Only Uid In Numbers :/"
123
+
124
+
125
+ if not self._online_conn:
126
+ return "online connection not correctly started"
127
+
128
+ url = self._clientbp + "/RequestAddingFriend"
129
+
130
+ fields = {
131
+ 1: self.account_uid,
132
+ 2: user_id,
133
+ 3: 22
134
+ }
135
+
136
+ proto = await create_proto(fields)
137
+ pphex = proto.hex()
138
+ encrypted_payload = await E_AEs(pphex)
139
+
140
+
141
+ headers = {
142
+ "Accept-Encoding": "gzip",
143
+ "Authorization": f"Bearer {self._token}",
144
+ "Connection": "Keep-Alive",
145
+ "Content-Type": "application/octet-stream",
146
+ "Expect": "100-continue",
147
+ "Host": Config.HOST,
148
+ "ReleaseVersion": Config.OB,
149
+ "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 9; ASUS_I005DA Build/PI)",
150
+ "X-GA": "v1 1",
151
+ "X-Unity-Version": "2018.4.11f1"
152
+ }
153
+
154
+ response = requests.post(
155
+ url,
156
+ headers=headers,
157
+ data=encrypted_payload,
158
+ verify=False,
159
+ )
160
+
161
+ print(response.text)
162
+
163
+ if "BR_FRIEND_ALREADY_SENT_REQUEST" in response.text:
164
+ return "Already Sent The Friend Request"
165
+ elif "BR_FRIEND_DUPLICATE" in response.text:
166
+ return "User Is Already A Friend"
167
+ else:
168
+ return "Sent Invite!"
169
+
170
+
171
+
172
+
173
+
174
+
175
+
176
+ def message_handler(self, command: Optional[str] = None):
177
+ """
178
+ Decorator for message handlers.
179
+
180
+ Args:
181
+ command: Optional command to match (e.g., 'Hi', 'help')
182
+
183
+ Example:
184
+ @bot.message_handler(command='Hi')
185
+ async def handle_hi(msg):
186
+ await bot.send_dm('Hello!', msg.user_id)
187
+ """
188
+ def decorator(func: Callable):
189
+ self._message_handlers.append({
190
+ 'command': command.lower() if command else None,
191
+ 'handler': func
192
+ })
193
+ return func
194
+ return decorator
195
+
196
+ def online(self):
197
+ """
198
+ Decorator for ready/online event handler.
199
+
200
+ Example:
201
+ @bot.online()
202
+ def on_ready(bot):
203
+ if bot.is_connected:
204
+ print(f"Logged in as {bot.nickname}")
205
+ """
206
+ def decorator(func: Callable):
207
+ self._ready_handlers.append(func)
208
+ return func
209
+ return decorator
210
+
211
+ async def _process_message(self, msg_data: Dict[str, Any]):
212
+ """Internal message processor"""
213
+ try:
214
+ msg = Message(msg_data)
215
+
216
+ for handler_info in self._message_handlers:
217
+ command = handler_info['command']
218
+ handler = handler_info['handler']
219
+
220
+ if command is None or msg.text.lower().startswith(command):
221
+ if asyncio.iscoroutinefunction(handler):
222
+ await handler(msg)
223
+ else:
224
+ handler(msg)
225
+
226
+ except Exception as e:
227
+ print(f"Message processing error: {e}")
228
+
229
+ async def _trigger_ready_handlers(self):
230
+ """Trigger all ready handlers"""
231
+ for handler in self._ready_handlers:
232
+ try:
233
+ if asyncio.iscoroutinefunction(handler):
234
+ await handler(self)
235
+ else:
236
+ handler(self)
237
+ except Exception as e:
238
+ print(f"Ready handler error: {e}")
239
+
240
+ async def send_dm(self, message: str, user_id: int):
241
+ """
242
+ Send a direct message to a user.
243
+
244
+ Args:
245
+ message: Message text
246
+ user_id: Target user ID
247
+ """
248
+
249
+ if not self._chat_conn:
250
+ print("Chat connection not correctly started")
251
+ return
252
+
253
+ await self._chat_conn.send_dm(message, user_id, self._key, self._iv)
254
+
255
+ async def send_squad(self, message: str, chat_id: int):
256
+ """
257
+ Send a message to squad chat.
258
+
259
+ Args:
260
+ message: Message text
261
+ chat_id: Squad chat ID
262
+ """
263
+ if not self._chat_conn:
264
+ print("Chat connection not established")
265
+ return
266
+
267
+ await self._chat_conn.send_squad(message, chat_id, self._key, self._iv)
268
+
269
+ async def send_guild(self, message: str, chat_id: int):
270
+ """
271
+ Send a message to guild chat.
272
+
273
+ Args:
274
+ message: Message text
275
+ chat_id: Guild chat ID
276
+ """
277
+ if not self._chat_conn:
278
+ print("Chat connection not established")
279
+ return
280
+
281
+ await self._chat_conn.send_guild(message, chat_id, self._key, self._iv)
282
+
283
+ async def online_loop(self):
284
+ """
285
+ Main event loop - keeps the bot online and processing messages.
286
+ This is a blocking call that runs until interrupted.
287
+
288
+ Example:
289
+ await bot.online_loop()
290
+ """
291
+ try:
292
+ online_task = asyncio.create_task(
293
+ self._online_conn.connect(self._auth_packet)
294
+ )
295
+
296
+ chat_task = asyncio.create_task(
297
+ self._chat_conn.connect(self._auth_packet)
298
+ )
299
+
300
+ await asyncio.sleep(1)
301
+
302
+ self.online_connected = self._online_conn.is_connected
303
+ self.chat_connected = self._chat_conn.is_connected
304
+
305
+ await self._trigger_ready_handlers()
306
+
307
+ await asyncio.gather(online_task, chat_task)
308
+
309
+ except KeyboardInterrupt:
310
+ print("\nBot stopped by user")
311
+ except Exception as e:
312
+ print(f"Event loop error: {e}")
313
+ finally:
314
+ await self.disconnect()
315
+
316
+ async def disconnect(self):
317
+ """Disconnect all connections"""
318
+ if self._online_conn:
319
+ await self._online_conn.close()
320
+ await asyncio.sleep(0.5)
321
+ if self._chat_conn:
322
+ await self._chat_conn.close()
323
+
324
+ self.is_connected = False
325
+ self.chat_connected = False
326
+ self.online_connected = False
redzedbot/config.py ADDED
@@ -0,0 +1,53 @@
1
+ """
2
+ Configuration module - Auto-updates from Google Play Store
3
+ """
4
+
5
+ import asyncio
6
+ import aiohttp
7
+ import json
8
+ from google_play_scraper import app
9
+
10
+
11
+ class Config:
12
+ """Configuration settings - Auto-updated on first use"""
13
+
14
+ LOGIN_URL = None
15
+ OB = None
16
+ VERSION = None
17
+ HOST = None
18
+
19
+ AES_KEY = b'Yg&tc%DEuh6%Zc^8'
20
+ AES_IV = b'6oyZDr22E3ychjM%'
21
+
22
+ _updated = False
23
+
24
+ @classmethod
25
+ async def auto_update(cls):
26
+ """Auto-update configuration from game version"""
27
+ if cls._updated:
28
+ return True
29
+
30
+ try:
31
+ result = app('com.dts.freefireth', lang="fr", country='fr')
32
+ version = result['version']
33
+
34
+ url = f'https://bdversion.ggbluefox.com/live/ver.php?version={version}&lang=ar&device=android&channel=android&appstore=googleplay&region=ME&whitelist_version=1.3.0&whitelist_sp_version=1.0.0&device_name=google%20G011A&device_CPU=ARMv7%20VFPv3%20NEON%20VMH&device_GPU=Adreno%20(TM)%20640&device_mem=1993'
35
+
36
+ async with aiohttp.ClientSession() as session:
37
+ async with session.get(url) as res:
38
+ text = await res.text()
39
+ data = json.loads(text)
40
+
41
+ cls.LOGIN_URL = data['server_url']
42
+ cls.OB = data['latest_release_version']
43
+ cls.VERSION = version
44
+ cls.HOST = data['server_url'].split('//')[1].split('/')[0]
45
+
46
+ cls._updated = True
47
+ return True
48
+
49
+ except Exception as e:
50
+ print(f"⚠️ Auto-update failed: {e}")
51
+ print("Using fallback configuration...")
52
+
53
+ return False