-
Notifications
You must be signed in to change notification settings - Fork 0
/
bot.py
459 lines (351 loc) · 13.3 KB
/
bot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
import traceback
from ast import literal_eval as make_tuple
from queue import Empty
from threading import Thread
import re
from telebot import TeleBot, types
from telebot.types import InlineKeyboardButton, InlineKeyboardMarkup
import constants as cons
from packet import Packet
class Bot(Thread):
def __init__(self, config, queue_to_cli, queue_to_bot, queue_to_father):
Thread.__init__(self)
self.config = config
self.queue_to_bot = queue_to_bot
self.queue_to_cli = queue_to_cli
self.queue_to_father = queue_to_father
self.bot_token = None
self.api_id = None
self.api_hash = None
self.user_id = None
self.channels = None
self.keywords = None
self.msg_chat_id_fake = None
def run(self):
def load_conf():
print("Cargando conf bot")
conf_dict = self.config.conf_dict
self.bot_token = conf_dict['bot_token']
self.api_id = conf_dict['api_id']
self.api_hash = conf_dict['api_hash']
self.user_id = conf_dict['user_id']
self.channels = conf_dict['channels']
self.keywords = conf_dict['keywords']
return True
# Solicita al cliente que recargue la conf
# TODO comentarios metodos
def reload_conf_req():
try:
request = Packet(cons.RELOAD_CONF, None)
self.queue_to_cli.put(request)
# Espera bloqueante del cliente
try:
# TODO obsoleto
reply = self.queue_to_bot.get(True, 5)
if reply.reply_code is False:
print("reload conf true")
# Devolver motivo del error
# bot.send_message(msg.chat.id, reply.reply_data)
# bot.register_next_step_handler(msg, process_channel_id)
except Empty:
# bot.send_message(msg.chat.id, "El bot se ha cansado de esperar a Client")
print("Bot: resp no recibida 1")
except Exception as e:
print("Excepcion:", e)
bot.send_message(self.user_id, "Algo ha fallado...")
# Verifica que solo el usuario autorizado accede al bot
def check_user_auth(user_id):
if self.user_id is None:
# Guardar el id del usuario
self.user_id = user_id
success = self.config.save_var("Data", "user_id", self.user_id)
if success:
print("## user_id guardado ##")
load_conf()
else:
print("oops! algo ha ido mal check_user()")
return True
else:
# Verificar id usuario
if self.user_id == user_id:
return True
else:
print("Acceso no autorizado al bot")
bot.send_message(user_id, "No estas autorizado a usar el bot")
return False
# Crear msg.chat.id para posteriores peticiones de datos
def save_chat_id_fake(id):
self.msg_chat_id_fake = type('message_tmp', (object,), {
'chat': type('chat', (object,),{'id': id})(),
'procesar': False})()
#################################################
# EJECUCION BOT #
#################################################
print("Ejecutando Bot")
load_conf()
bot = TeleBot(self.bot_token, threaded=True, skip_pending=True)
if self.user_id:
# bot.send_message(self.user_id, "Bot iniciado", disable_notification=True)
save_chat_id_fake(self.user_id)
@bot.message_handler(commands=['start'])
def start(msg):
if not check_user_auth(msg.chat.id):
return
save_chat_id_fake(msg.chat.id)
username = msg.from_user.username
bot.send_message(msg.chat.id, "Bienvenido a telegramo @" + username)
bot.send_message(msg.chat.id, "En los siguientes pasos vamos a configurar la aplicacion.")
bot.send_message(msg.chat.id, "Si algun parametro no se configura bien, puedes volver a hacerlo con:\n"
"/set_api_id\n/set_api_hash\n/set_phone")
bot.send_message(msg.chat.id, "Para ejecutar el cliente manualmente: /client_launch")
markup = types.ForceReply(selective=False)
bot.send_message(msg.chat.id, "Introduce el API_ID:", reply_markup=markup)
bot.register_next_step_handler(msg, process_api_id)
def process_api_id(msg):
api_id = msg.text
self.config.save_var("Config", "api_id", api_id)
markup = types.ForceReply(selective=False)
bot.send_message(msg.chat.id, "Ahora introduce el API_HASH:", reply_markup=markup)
bot.register_next_step_handler(msg, process_api_hash)
def process_api_hash(msg):
api_hash = msg.text
self.config.save_var("Config", "api_hash", api_hash)
markup = types.ForceReply(selective=False)
bot.send_message(msg.chat.id, "Ahora introduce tu numero de telefono (+34 123 456 789): ", reply_markup=markup)
bot.register_next_step_handler(msg, process_phone)
def process_phone(msg):
phone = msg.text
self.config.save_var("Config", "phone", phone)
bot.send_message(msg.chat.id, "Vamos a intentar lanzar el cliente con los datos facilitados...")
request = Packet(cons.CLIENT_START, None)
self.queue_to_father.put(request)
@bot.message_handler(commands=['add_channel'])
def add_channel(msg):
if not check_user_auth(msg.chat.id):
return
markup = types.ForceReply(selective=False)
bot.send_message(msg.chat.id, "Para añadir un canal, introduce su id", reply_markup=markup)
bot.register_next_step_handler(msg, process_add_channel_id)
def process_add_channel_id(msg):
id_channel = msg.text
try:
request = Packet(cons.ADD_CHANNEL, id_channel)
self.queue_to_cli.put(request)
except Exception as e:
print("Excepcion 1:", e)
print(traceback.format_exc())
bot.send_message(msg.chat.id, "Algo ha fallado...")
@bot.message_handler(commands=['delete_channel'])
def delete_channel(msg):
if not check_user_auth(msg.chat.id):
return
if len(self.channels) == 0:
bot.send_message(msg.chat.id, "No hay canales guardados")
return
markup = InlineKeyboardMarkup()
for channel in self.channels:
markup.add(InlineKeyboardButton(channel.title, callback_data=str((
cons.DELETE_CHANNEL, channel.id, channel.title))))
bot.send_message(msg.chat.id, "Elige el canal a borrar", reply_markup=markup)
@bot.message_handler(commands=['add_keyword'])
def add_keyword(msg):
if not check_user_auth(msg.chat.id):
return
markup = types.ForceReply(selective=False)
bot.send_message(msg.chat.id, "Para añadir una palabra clave, introducela", reply_markup=markup)
bot.register_next_step_handler(msg, process_add_keyword)
def process_add_keyword(msg):
# TODO filtrar caracteres
regex = re.compile(r"(;)+", re.IGNORECASE)
keyword = re.sub(regex, '', msg.text)
# Ya existe en la conf?
exists = False
for k in self.keywords:
if k == keyword:
exists = True
if exists:
bot.send_message(msg.chat.id, "La palabra clave ya estaba guardada")
else:
self.keywords.append(keyword)
success = self.config.save_var("Config", "keywords", self.keywords)
if success is True:
bot.send_message(msg.chat.id, "Se ha añadido la palabra clave: " + keyword)
load_conf()
reload_conf_req()
else:
bot.send_message(msg.chat.id, "Error al guardar el fichero de conf")
@bot.message_handler(commands=['delete_keyword'])
def delete_keyword(msg):
if not check_user_auth(msg.chat.id):
return
if len(self.keywords) == 0:
bot.send_message(msg.chat.id, "No hay palabras clave guardadas")
return
markup = InlineKeyboardMarkup()
for key in self.keywords:
markup.add(InlineKeyboardButton(key, callback_data=str((
cons.DELETE_KEYWORD, key))))
bot.send_message(msg.chat.id, "Elige la palabra a borrar", reply_markup=markup)
@bot.message_handler(commands=['set_api_id'])
def set_api_id(msg):
if not check_user_auth(msg.chat.id):
return
markup = types.ForceReply(selective=False)
bot.send_message(msg.chat.id, "Introduce el API_ID:", reply_markup=markup)
bot.register_next_step_handler(msg, set_api_id_procesar)
def set_api_id_procesar(msg):
if not check_user_auth(msg.chat.id):
return
api_id = msg.text
success = self.config.save_var("Config", "api_id", api_id)
if not success:
bot.send_message(msg.chat.id, "Error al guardar el parametro")
@bot.message_handler(commands=['set_api_hash'])
def set_api_hash(msg):
if not check_user_auth(msg.chat.id):
return
markup = types.ForceReply(selective=False)
bot.send_message(msg.chat.id, "Introduce el API_HASH:", reply_markup=markup)
bot.register_next_step_handler(msg, set_api_hash_procesar)
def set_api_hash_procesar(msg):
if not check_user_auth(msg.chat.id):
return
api_hash = msg.text
success = self.config.save_var("Config", "api_hash", api_hash)
if not success:
bot.send_message(msg.chat.id, "Error al guardar el parametro")
@bot.message_handler(commands=['set_phone'])
def set_phone(msg):
if not check_user_auth(msg.chat.id):
return
markup = types.ForceReply(selective=False)
bot.send_message(msg.chat.id, "Introduce el numero de telefono (+34 123 456 789):", reply_markup=markup)
bot.register_next_step_handler(msg, set_phone_procesar)
def set_phone_procesar(msg):
if not check_user_auth(msg.chat.id):
return
phone = msg.text
success = self.config.save_var("Config", "phone", phone)
if not success:
bot.send_message(msg.chat.id, "Error al guardar el parametro")
@bot.message_handler(commands=['client_launch'])
def client_launch(msg):
if not check_user_auth(msg.chat.id):
return
request = Packet(cons.CLIENT_START, None)
self.queue_to_father.put(request)
@bot.message_handler(commands=['client_status'])
def client_status(msg):
if not check_user_auth(msg.chat.id):
return
request = Packet(cons.CLIENT_STATUS, None)
self.queue_to_father.put(request)
# Maneja los clicks de botones
@bot.callback_query_handler(func=lambda call: True)
def callback(call):
# print(call)
chat_id = call.from_user.id
if not check_user_auth(chat_id):
return
resp = make_tuple(call.data)
code = resp[0]
if code == cons.DELETE_CHANNEL:
channel_id = resp[1]
channel_title = resp[2]
self.channels = [ch_conf for ch_conf in self.channels if ch_conf.id != channel_id]
success = self.config.save_var("Config", "channels", self.channels)
if success is True:
bot.send_message(chat_id, channel_title + " borrado correctamente")
load_conf()
reload_conf_req()
else:
bot.send_message(chat_id, "Error al borrar el canal")
elif code == cons.DELETE_KEYWORD:
key = resp[1]
self.keywords = [x for x in self.keywords if x != key]
success = self.config.save_var("Config", "keywords", self.keywords)
if success is True:
bot.send_message(chat_id, key + ": borrada correctamente")
load_conf()
reload_conf_req()
else:
bot.send_message(chat_id, "Error al borrar la palabra")
def add_channel(req):
# Canal valido
if req.reply_code is True:
channel = req.reply_data
# Ya existe en la conf?
exists = False
for ch in self.channels:
if ch[0] == channel.id:
exists = True
if exists:
bot.send_message(self.user_id, "El canal ya estaba guardado")
else:
channel_new = (channel.id, channel.title)
self.channels.append(channel_new)
success = self.config.save_var("Config", "channels", self.channels)
if success is True:
bot.send_message(self.user_id, "Se ha añadido el canal: " + channel.title)
load_conf()
reload_conf_req()
else:
bot.send_message(self.user_id, "Error al guardar el fichero de conf")
# Canal invalido
else:
# Devolver motivo del error
bot.send_message(self.user_id, req.reply_data)
def ask_user_tl_code():
markup = types.ForceReply(selective=False)
bot.send_message(self.user_id, "Introduce el codigo de autenticacion recibido de "
"telegram via sms/telegram app, sumandole 1 al número:", reply_markup=markup)
bot.register_next_step_handler(self.msg_chat_id_fake, ask_user_tl_code_procesar)
def ask_user_tl_code_procesar(msg):
if not check_user_auth(msg.chat.id):
return
try:
# Para evitar que tl nos invalide el codigo de autorizacion:
code = int(msg.text) - 1
req = Packet(cons.ASK_TL_AUTH_CODE_REPLY, code)
self.queue_to_cli.put(req)
except Exception:
# TODO especificar except
bot.send_message(self.user_id, "El codigo introducido es invalido")
def queue_check():
while True:
try:
req = self.queue_to_bot.get(block=True)
if req.request_code == cons.CHANNEL_EXISTS:
add_channel(req)
elif req.request_code == cons.RELOAD_CONF:
load_conf()
req.reply_code = True
self.queue_to_cli.put(req)
elif req.request_code == cons.ADD_CHANNEL:
bot.send_message(self.user_id, req.reply_data)
elif req.request_code == cons.SEND_MSG:
if self.user_id is not None:
bot.send_message(self.user_id, req.request_data)
else:
print("WARNING: Se ha intentado enviar msg al user sin setear user_id antes")
elif req.request_code == cons.ASK_TL_AUTH_CODE:
ask_user_tl_code()
elif req.request_code == cons.CLIENT_STATUS:
if req.reply_code is True:
bot.send_message(self.user_id, "El cliente esta ejecutandose")
else:
bot.send_message(self.user_id, "El cliente esta detenido")
else:
print("WARNING Bot receives unkown code: ", req)
except Empty:
pass
thread_queue = Thread(target=queue_check)
thread_queue.daemon = True
thread_queue.start()
# Bucle polling updates telegram
while True:
try:
#bot.polling(none_stop=True, interval=3, timeout=5)
bot.polling()
except Exception:
print("Bot: error polling tl updates")