Keeps pedophiles and CP spammers away from telegram groups by checking if member or media hash is blacklisted.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

antipedo.py 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. from magic import Magic
  2. from os import remove,linesep
  3. import logging
  4. from imagehash import average_hash
  5. from PIL import Image
  6. from telegram.error import (
  7. BadRequest,
  8. TimedOut,
  9. Unauthorized,
  10. InvalidToken
  11. )
  12. from telegram import (
  13. ReplyKeyboardMarkup,
  14. ReplyKeyboardRemove,
  15. Update, ReplyKeyboardMarkup,
  16. ReplyKeyboardRemove
  17. )
  18. from telegram.ext import (
  19. Updater,
  20. CommandHandler,
  21. MessageHandler,
  22. Filters,
  23. ConversationHandler
  24. )
  25. from tools import (
  26. GREETING_MESSAGE,
  27. BOT_ADDED_MESSAGE,
  28. dump_json,
  29. load_json
  30. )
  31. # Will log only banned users.
  32. logging.basicConfig(
  33. level=logging.WARN,
  34. format='%(asctime)s - %(message)s',
  35. handlers=[
  36. logging.FileHandler("debug.log"),
  37. logging.StreamHandler()
  38. ]
  39. )
  40. debug =logging.getLogger("AntiPedo")
  41. filter_list = load_json("filter.json")
  42. chan_list = load_json("chats.json")
  43. meta =load_json("meta.json")
  44. admins = meta["admins"]
  45. TOKEN = meta["token"]
  46. REPORT_CH = meta["report_ch"]
  47. updater = Updater(TOKEN)
  48. dispatcher = updater.dispatcher
  49. filetype = Magic(mime=True)
  50. def checkNewMember(update, context):
  51. chat = update.effective_chat
  52. blacklist = load_json("blacklist.json")
  53. for member in update.message.new_chat_members:
  54. if member.id == updater.bot.id:
  55. trackPublicChats(update,context)
  56. try:update.message.reply_text(BOT_ADDED_MESSAGE,quote=False)
  57. except Unauthorized as error: debug.warning(f"[ERROR] {repr(error)} - {str(error)}")
  58. return
  59. if not str(member.id) in blacklist:
  60. continue
  61. meta = load_json("meta.json")
  62. meta["banned"] = meta["banned"]+1
  63. dump_json(meta,"meta.json")
  64. mods=0
  65. debug.warning(f"Black-listed user {member.username or member.full_name} joined"
  66. f" to {'@'+chat.username if chat.username else chat.title} CID:{chat.id}.")
  67. reason = blacklist[str(member.id)]
  68. if reason.replace("+","").isnumeric():
  69. reason = "\n".join([ blacklist["CODES"][i] for i in reason.split("+") ])
  70. if updater.bot.getChatMember( chat.id,updater.bot.id ).can_restrict_members:
  71. updater.bot.kick_chat_member(chat.id, member.id)
  72. action='Automatically banned.'
  73. else:
  74. # If the bot doesn't have admin previleges, send a warning message to the admins of group instead.
  75. action='Reported to group moderators.'
  76. for op in [ i.user for i in update.effective_chat.get_administrators() if not i.user.is_bot]:
  77. try:
  78. op.send_message(
  79. f"🚨 KNOWN PEDO ALERT @ {str(update.effective_chat.title).upper()} 🚨\n"
  80. f"username: {member.username}\n"
  81. f"fullname: {member.full_name}\n"
  82. f"reason: {reason}")
  83. except Exception as error:
  84. if not "initiate" in str(error):
  85. debug.warning(f"[ERROR] {repr(error)} - {str(error)}")
  86. else:
  87. mods+=1
  88. debug.warning(f"[ACTION] {action.replace(' mod',f' {mods} mod')} ID:{member.id} \n{' '*26}Guilt: {reason.replace(linesep,' ')}")
  89. try:update.message.reply_text(
  90. f'Known pedo <a href="tg://user?id={member.id}">{member.full_name}</a> joined to group. {action}\n\n'
  91. f'<b>Reason:</b> {reason}', quote=True, parse_mode="html")
  92. except BadRequest as error: debug.warning(f"[ERROR] {repr(error)} - {str(error)}")
  93. def updateBlacklist(update,context):
  94. user = update.effective_user
  95. if not user.id in admins:
  96. debug.warning(f"Non-operator user {user.username or user.full_name} tried to use /add. ID:{user.id}")
  97. update.message.reply_text("You are not a bot operator.")
  98. return ConversationHandler.END
  99. try:
  100. uid = update.message.text.split(" ")[1]
  101. int(uid)
  102. except (ValueError,IndexError):
  103. update.message.reply_text("Incorrect User ID.")
  104. return ConversationHandler.END
  105. blacklist = load_json("blacklist.json")
  106. if uid in blacklist:
  107. update.message.reply_text("This user is already black-listed.")
  108. return ConversationHandler.END
  109. context.user_data["uids"]=[uid]
  110. blacklist = load_json("blacklist.json")
  111. update.message.reply_text("Now please send me either a reason number from below or send a new reason message. Send 'cancel' to abort.")
  112. update.message.reply_text("\n".join([ f"{i}. {t}" for i,t in blacklist["CODES"].items()]))
  113. return 1
  114. def setReason(update,context):
  115. reason = update.message.text
  116. uids = context.user_data["uids"]
  117. blacklist = load_json("blacklist.json")
  118. for uid in uids:
  119. blacklist[uid]=reason
  120. dump_json(blacklist,"blacklist.json")
  121. update.message.reply_text("Success.")
  122. return ConversationHandler.END
  123. add_blacklist_convo = lambda command,func:ConversationHandler(
  124. entry_points=[CommandHandler(command, func)],
  125. states={
  126. 1:[MessageHandler(Filters.text & ~Filters.regex("^[Cc]ancel\.*$"),setReason)],
  127. -2:[MessageHandler(Filters.all, Report.timeout)]
  128. },
  129. fallbacks=[MessageHandler(Filters.regex("^[Cc]ancel\.*$"), Report.cancel)],
  130. conversation_timeout=120
  131. )
  132. def updatePicBlacklist(update,context):
  133. if not update.message.from_user.id in admins:
  134. return update.message.reply_text("You are not a bot operator.")
  135. m = update.message.reply_to_message
  136. if not m:
  137. return update.message.reply_text("Reply to a media.")
  138. for method in [m.video,m.animation,m.photo]:
  139. if not method:
  140. continue
  141. elif "thumb" in dir(method) and method.thumb:
  142. file = method.thumb
  143. elif m.photo:
  144. file = m.photo[0]
  145. else:
  146. return
  147. break
  148. path = file.get_file().download(f"/tmp/{file.file_unique_id}")
  149. phash = str(average_hash(Image.open(path)))
  150. remove(path)
  151. if not phash in filter_list:
  152. filter_list.append(phash)
  153. dump_json(filter_list,"filter.json")
  154. update.message.reply_text("Sucessfully added.")
  155. else:
  156. update.message.reply_text("This media is already filtered.")
  157. def batchBlacklist(update,context):
  158. if not update.message.from_user.id in admins:
  159. update.message.reply_text("You are not a bot operator.")
  160. return ConversationHandler.END
  161. message = update.message.reply_to_message
  162. if not message:
  163. update.message.reply_text("Usage: reply to an ID list file or a message containing list.")
  164. return ConversationHandler.END
  165. if message.document:
  166. # Check if list file is valid.
  167. message.document.get_file().download("batch_list")
  168. if filetype.from_file("batch_list") != "text/plain":
  169. remove("batch_list")
  170. update.message.reply_text("File type unsupported.")
  171. return ConversationHandler.END
  172. with open("batch_list") as ro:
  173. batch_list_raw = ro.read().replace(" ","")
  174. remove("batch_list")
  175. elif message.text:
  176. batch_list_raw = message.text.replace(" ","")
  177. else:
  178. update.message.reply_text("Unsupported batch adding method.")
  179. return ConversationHandler.END
  180. if False in [i.isdigit() for i in batch_list_raw if not '\n' in i]:
  181. update.message.reply_text("Unsupported characters in list, you should send the IDs in newlines as integers with no comma or dots.")
  182. return ConversationHandler.END
  183. batch_list = [ int(i) for i in batch_list_raw.split("\n") if i ]
  184. # Finally add new IDs to the black list.
  185. blacklist = load_json("blacklist.json")
  186. new,uids = 0,[]
  187. for i in batch_list:
  188. if not str(i) in blacklist:
  189. new += 1
  190. uids.append(i)
  191. text = f"{new} new IDs selected."
  192. update.message.reply_text(f"{text} Now please send me either a reason number from below or send a new reason message. Send 'cancel' to abort.")
  193. update.message.reply_text("\n".join([ f"{i}. {t}" for i,t in blacklist["CODES"].items()]))
  194. debug.warning(text)
  195. context.user_data["uids"]=uids
  196. return 1
  197. def metaInformation(update,context):
  198. blacklist = load_json("blacklist.json")
  199. meta = load_json("meta.json")
  200. filtre = load_json("filter.json")
  201. update.message.reply_text(
  202. f"Currently {len(blacklist)-1} pedos on blacklist. "
  203. f"{meta['banned']} pedophiles were banned "
  204. f"and {meta['reported']} reports received. "
  205. f"Protecting {len(chan_list)} groups. {len(filtre)} CP media on filter so far."
  206. )
  207. def giveOP(update,context):
  208. if not update.message.from_user.id in admins:
  209. debug.warning(f"[DETECT] Black-listed user {user.username or user.full_name} tried to /OP. ID:{user.id}")
  210. return update.message.reply_text("You are not a bot operator.")
  211. try:
  212. uid = update.message.text.split("/op ")[1]
  213. uid = int(uid)
  214. except (ValueError,IndexError):
  215. return update.message.reply_text("Incorrect User ID.")
  216. if uid in admins:
  217. return update.message.reply_text("This user is already bot operator.")
  218. admins.append(uid)
  219. meta = load_json("meta.json")
  220. meta["admins"]=admins
  221. dump_json(meta,"meta.json")
  222. return update.message.reply_text("Successfully added new bot operator.")
  223. class Report:
  224. def start(update,context):
  225. if "private" != update.effective_chat.type:
  226. try:update.message.reply_text("You must /report trough private chat.")
  227. except Exception as error: debug.warning(f"[ERROR] {repr(error)} - {str(error)}")
  228. return ConversationHandler.END
  229. context.user_data["messages"] = []
  230. update.message.reply_text(
  231. "Send me up to 5 messages and then press \"Forward\" button.",
  232. reply_markup=ReplyKeyboardMarkup([['Forward 🟢','Cancel 🔴']], one_time_keyboard=True)
  233. )
  234. return 1
  235. def cancel(update,context):
  236. update.message.reply_text("Cancelled.",reply_markup=ReplyKeyboardRemove())
  237. return ConversationHandler.END
  238. def handle(update,context):
  239. if len(context.user_data["messages"]) < 5:
  240. context.user_data["messages"].append( update.message )
  241. return 1
  242. update.message.reply_text("You can send maximum 5 messages.")
  243. def send(update,context):
  244. if not context.user_data["messages"]:
  245. update.message.reply_text(
  246. "No messages were sent.",
  247. reply_markup=ReplyKeyboardRemove()
  248. )
  249. return ConversationHandler.END
  250. user = update.effective_user
  251. updater.bot.sendMessage(REPORT_CH,
  252. f"🚨🚨 NEW PEDO REPORT 🚨🚨\n"
  253. f"<code>from User ID: {user.id}</code>\n"
  254. f"<code>from UserName: </code>@{user.username}",
  255. parse_mode="html")
  256. for message in context.user_data["messages"]:
  257. message.forward(REPORT_CH)
  258. update.message.reply_text(
  259. "Your report has been sent.",
  260. reply_markup=ReplyKeyboardRemove()
  261. )
  262. meta = load_json("meta.json")
  263. meta["reported"]=meta["reported"]+1
  264. dump_json(meta,"meta.json")
  265. return ConversationHandler.END
  266. def timeout(update,context):
  267. update.message.reply_text("Timeout.",reply_markup=ReplyKeyboardRemove())
  268. def reply(update,context):
  269. if not update.effective_user.id in admins:
  270. return
  271. forwarded = update.message.reply_to_message
  272. if not forwarded or not "ID:" in forwarded.text:
  273. return update.message.reply_text("Reply to the bot's alert message.")
  274. try:
  275. user_id = int(forwarded.text.split("ID: ")[1].split("\n")[0])
  276. except Exception as error:
  277. debug.warning(f"[ERROR] {repr(error)} - {str(error)}")
  278. return
  279. updater.bot.send_message(
  280. user_id,
  281. update.message.text.split("[FORWARD]\n")[1]
  282. )
  283. return update.message.reply_text("Message sent.")
  284. reporter = ConversationHandler(
  285. entry_points=[CommandHandler('report', Report.start)],
  286. states={
  287. 1: [
  288. MessageHandler(Filters.regex("^Forward 🟢$"), Report.send),
  289. MessageHandler(Filters.regex("^Cancel 🔴$") | Filters.command , Report.cancel),
  290. MessageHandler(Filters.text | Filters.photo, Report.handle)],
  291. -2: [MessageHandler(Filters.all, Report.timeout) ]
  292. },
  293. fallbacks=[MessageHandler(Filters.regex("^Cancel 🔴$"), Report.cancel)],
  294. conversation_timeout=120
  295. )
  296. def start(update,context):
  297. if "private" != update.effective_chat.type:
  298. return
  299. debug.warning(f"{update.effective_user.id} started bot.")
  300. update.message.reply_text(GREETING_MESSAGE,parse_mode="html")
  301. def checkMedia(update,context):
  302. if update.effective_user and update.effective_user.id in admins:
  303. # Skip bot operators to avoid getting them banned while adding media to blacklist.
  304. return
  305. m = update.effective_message
  306. for method in [m.video,m.animation,m.photo]:
  307. if not method:
  308. continue
  309. elif "thumb" in dir(method) and method.thumb:
  310. file = method.thumb
  311. elif m.photo:
  312. file = m.photo[0]
  313. else:
  314. return
  315. break
  316. try:
  317. path = file.get_file().download(f"/tmp/{file.file_unique_id}")
  318. except (TimedOut,InvalidToken):
  319. return
  320. phash = str(average_hash( Image.open(path) ))
  321. remove(path)
  322. if not phash in filter_list:
  323. return
  324. # Add this user to blacklist
  325. chat = update.effective_chat
  326. member = update.effective_user
  327. debug.warning(f"[DETECT] User {member.username or member.full_name} posted CP "
  328. f"at {'@'+chat.username if chat.username else chat.title}.")
  329. blacklist = load_json("blacklist.json")
  330. if not str(member.id) in blacklist:
  331. blacklist[str(member.id)]="3"
  332. dump_json(blacklist,"blacklist.json")
  333. meta = load_json("meta.json")
  334. meta["banned"] = meta["banned"]+1
  335. dump_json(meta,"meta.json")
  336. # Delete his message and ban him
  337. bot = updater.bot.getChatMember( m.chat_id,updater.bot.id )
  338. text = "CP image detected and informed moderators. Can't delete since no permissions."
  339. if bot.can_delete_messages:
  340. try:
  341. m.delete()
  342. except Unauthorized as error:
  343. debug.warning(f"[ERROR] {repr(error)} - {str(error)}")
  344. else:
  345. text = "Automatically deleted CP image and informed moderators."
  346. if bot.can_restrict_members:
  347. updater.bot.kick_chat_member(m.chat_id, member.id)
  348. text = "Automatically deleted CP image and banned the CP poster."
  349. else:
  350. # If the bot doesn't have admin previleges, send a warning message to the admins of group instead.
  351. for op in [ i.user for i in update.effective_chat.get_administrators() if not i.user.is_bot]:
  352. try:
  353. op.send_message(
  354. f"🚨 CP SPAM ALERT @ {str(update.effective_chat.title).upper()} 🚨\n"
  355. f"username: {member.username}\n"
  356. f"fullname: {member.full_name}")
  357. except Exception as error:
  358. if not "initiate" in str(error):
  359. debug.warning(f"[ERROR] {repr(error)} - {str(error)}")
  360. debug.warning(f"[ACTION] {text} ID:{member.id}")
  361. return update.message.bot.send_message(chat.id,text)
  362. def trackPublicChats(update,context):
  363. chat = update.effective_chat
  364. if chat.type=="private" or str(chat.id) in chan_list:
  365. return
  366. debug.warning(f"Bot was added to {chat.title}")
  367. try:
  368. chan_list[chat.id] = {
  369. "full_name": chat.full_name or chat.title,
  370. "username" : chat.username or chat.invite_link,
  371. "type" : chat.type,
  372. "admin" : updater.bot.getChatMember( chat.id,updater.bot.id ).can_restrict_members,
  373. "members" : chat.get_members_count()
  374. }
  375. except Unauthorized:
  376. return
  377. dump_json(chan_list,"chats.json")
  378. dispatcher.add_handler(reporter)
  379. dispatcher.add_handler(add_blacklist_convo("add",updateBlacklist))
  380. dispatcher.add_handler(add_blacklist_convo("batch_add",batchBlacklist))
  381. dispatcher.add_handler(MessageHandler(Filters.regex("^\[FORWARD\]\\n"), Report.reply))
  382. dispatcher.add_handler(MessageHandler(Filters.status_update.new_chat_members, checkNewMember))
  383. dispatcher.add_handler(MessageHandler(Filters.photo | Filters.animation | Filters.video, checkMedia))
  384. dispatcher.add_handler(CommandHandler("add_filter", updatePicBlacklist))
  385. dispatcher.add_handler(CommandHandler("meta", metaInformation))
  386. dispatcher.add_handler(CommandHandler("op", giveOP))
  387. dispatcher.add_handler(CommandHandler(["help","start"] , start))
  388. updater.start_polling()