from colorama import Fore, Style
from googletrans import Translator
from src.telepathy.const import __version__, user_agent
import requests
import textwrap
from bs4 import BeautifulSoup
import random
import os
def createPlaceholdeCls():
class Object(object):
pass
a = Object()
return a
def print_banner():
print(
Fore.GREEN
+ """
______ __ __ __
/_ __/__ / /__ ____ ____ _/ /_/ /_ __ __
/ / / _ \/ / _ \/ __ \/ __ `/ __/ __ \/ / / /
/ / / __/ / __/ /_/ / /_/ / /_/ / / / /_/ /
/_/ \___/_/\___/ .___/\__,_/\__/_/ /_/\__, /
/_/ /____/
-- An OSINT toolkit for investigating Telegram chats.
-- Developed by @jordanwildon | Version """
+ __version__
+ """.
"""
+ Style.RESET_ALL
)
def parse_tg_date(dd):
year = str(format(dd.year, "02d"))
month = str(format(dd.month, "02d"))
day = str(format(dd.day, "02d"))
hour = str(format(dd.hour, "02d"))
minute = str(format(dd.minute, "02d"))
second = str(format(dd.second, "02d"))
date = year + "-" + month + "-" + day
mtime = hour + ":" + minute + ":" + second
timestamp = date + "T" + mtime + "+00:00"
return {"timestamp": timestamp, "date": date, "mtime": mtime}
def populate_user(user, group_or_chat):
if user.username:
username = user.username
else:
username = "N/A"
if user.first_name:
first_name = user.first_name
else:
first_name = ""
if user.last_name:
last_name = user.last_name
else:
last_name = ""
if user.phone:
phone = user.phone
else:
phone = "N/A"
if user.id:
user_id = user.id
else:
user_id = "N/A"
full_name = (first_name + " " + last_name).strip()
return [username, full_name, user_id, phone, group_or_chat]
def process_message(mess, user_lang):
if mess is not None:
mess_txt = '"' + mess + '"'
else:
mess_txt = "None"
if mess_txt != "None":
translator = Translator()
detection = translator.detect(mess_txt)
translation_confidence = detection.confidence
translation = translator.translate(mess_txt, dest=user_lang)
original_language = translation.src
translated_text = translation.text
else:
original_language = user_lang
translated_text = "N/A"
translation_confidence = "N/A"
return {
"original_language": original_language,
"translated_text": translated_text,
"translation_confidence": translation_confidence,
"message_text": mess_txt,
}
def process_description(desc, user_lang):
if desc is not None:
desc_txt = '"' + desc + '"'
else:
desc_txt = "None"
if desc_txt != "None":
translator = Translator()
detection = translator.detect(desc_txt)
translation_confidence = detection.confidence
translation = translator.translate(desc_txt, dest=user_lang)
original_language = translation.src
translated_text = translation.text
else:
original_language = user_lang
translated_text = "N/A"
translation_confidence = "N/A"
return {
"original_language": original_language,
"translated_text": translated_text,
"translation_confidence": translation_confidence,
"description_text": desc_txt,
}
def color_print_green(first_string, second_string):
print(Fore.GREEN + first_string + Style.RESET_ALL + second_string)
def parse_html_page(url):
s = requests.Session()
s.max_redirects = 10
s.headers["User-Agent"] = random.choice(user_agent)
URL = s.get(url)
URL.encoding = "utf-8"
html_content = URL.text
soup = BeautifulSoup(html_content, "html.parser")
name = ""
group_description = ""
total_participants = ""
try:
name = soup.find("div", {"class": ["tgme_page_title"]}).text
except:
name = "Not found"
try:
group_description = (
soup.find("div", {"class": ["tgme_page_description"]})
.getText(separator="\n")
.replace("\n", " ")
)
except:
group_description = "None"
try:
group_participants = soup.find("div", {"class": ["tgme_page_extra"]}).text
sep = "members"
stripped = group_participants.split(sep, 1)[0]
total_participants = (
stripped.replace(" ", "")
.replace("members", "")
.replace("subscribers", "")
.replace("member", "")
)
except:
total_participants = "Not found"
return {
"name": name,
"group_description": group_description,
"total_participants": total_participants,
}
def generate_textwrap(text_string, size=70):
trans_descript = Fore.GREEN + f"{text_string} " + Style.RESET_ALL
prefix = trans_descript
return textwrap.TextWrapper(
initial_indent=prefix,
width=size,
subsequent_indent=" ",
)
def print_shell(type, obj):
if type == "bot":
color_print_green(" [+] ", "Bot details for " + str(obj.id))
color_print_green(f" ├ Username: @{str(obj.username)}")
color_print_green(f" ├ Name: {str(obj.first_name)}")
color_print_green(f" └ Link: https://t.me/{str(obj.username)}")
print("\n")
color_print_green(" [+] ", "User related details for bot " + str(obj.id))
color_print_green(f" ├ User id: @{str(obj.user_id)}")
color_print_green(f" ├ User username: @{str(obj.user_username)}")
color_print_green(f" ├ User name: {str(obj.user_first_name)}")
color_print_green(f" └ Link: https://t.me/{str(obj.user_username)}")
if type == "user":
color_print_green(" [+] ", "User details for " + obj.target)
color_print_green(" ├ Id: ", str(obj.id))
color_print_green(" ├ Username: ", str(obj.username))
color_print_green(" ├ Name: ", str(obj.user_full_name))
color_print_green(" ├ Verification: ", str(obj.verified))
color_print_green(" ├ Photo ID: ", str(obj.user_photo))
color_print_green(" ├ Phone number: ", str(obj.phone))
color_print_green(" ├ Access hash: ", str(obj.access_hash))
color_print_green(" ├ Language: ", str(obj.lang_code))
color_print_green(" ├ Bot: ", str(obj.bot))
color_print_green(" ├ Scam: ", str(obj.scam))
color_print_green(" ├ Last seen: ", str(obj.user_status))
color_print_green(" └ Restrictions: ", str(obj.user_restrictions))
if type == "location_report":
color_print_green(" [+] Users located", "")
color_print_green(" ├ Users within 500m: ", str(obj.d500))
color_print_green(" ├ Users within 1000m: ", str(obj.d1000))
color_print_green(" ├ Users within 2000m: ", str(obj.d2000))
color_print_green(" ├ Users within 3000m: ", str(obj.d3000))
color_print_green(" ├ Total users found: ", str(obj.total))
color_print_green(" └ Location list saved to: ", obj.save_file)
if type == "channel_recap" or type == "group_recap":
d_wrapper = generate_textwrap("Description:")
td_wrapper = generate_textwrap("Translated Description:")
color_print_green(" ┬ Chat details", "")
color_print_green(" ├ Title: ", str(obj.title))
color_print_green(" ├ ", d_wrapper.fill(obj.group_description))
if obj.translated_description != obj.group_description:
color_print_green(" ├ ", td_wrapper.fill(obj.translated_description))
color_print_green(" ├ Total participants: ", str(obj.total_participants))
if type == "group_recap":
color_print_green(
" ├ Participants found: ",
str(obj.found_participants)
+ " ("
+ str(format(obj.found_percentage, ".2f"))
+ "%)",
)
color_print_green(" ├ Username: ", str(obj.group_username))
color_print_green(" ├ URL: ", str(obj.group_url))
color_print_green(" ├ Chat type: ", str(obj.chat_type))
color_print_green(" ├ Chat id: ", str(obj.id))
color_print_green(" ├ Access hash: ", str(obj.access_hash))
if type == "channel_recap":
scam_status = str(obj.scam)
color_print_green(" ├ Scam: ", str(scam_status))
color_print_green(" ├ First post date: ", str(obj.first_post))
if type == "group_recap":
color_print_green(" ├ Memberlist saved to: ", obj.memberlist_filename)
color_print_green(" └ Restrictions: ", (str(obj.group_status)))
if type == "group_stat":
color_print_green(" [+] Chat archive saved", "")
color_print_green(" ┬ Chat statistics", "")
color_print_green(" ├ Number of messages found: ", str(obj.messages_found))
color_print_green(" ├ Top poster 1: ", str(obj.poster_one))
color_print_green(" ├ Top poster 2: ", str(obj.poster_two))
color_print_green(" ├ Top poster 3: ", str(obj.poster_three))
color_print_green(" ├ Top poster 4: ", str(obj.poster_four))
color_print_green(" ├ Top poster 5: ", str(obj.poster_five))
color_print_green(" ├ Total unique posters: ", str(obj.unique_active))
color_print_green(" └ Archive saved to: ", str(obj.file_archive))
return
if type == "channel_stat":
color_print_green(" [+] Channel archive saved", "")
color_print_green(" ┬ Channel statistics", "")
color_print_green(" ├ Number of messages found: ", str(obj.messages_found))
color_print_green(" └ Archive saved to: ", str(obj.file_archive))
return
if type == "reply_stat":
middle_char = "├"
if obj.user_replier_list_len == 0:
middle_char = "└"
color_print_green(" [+] Replies analysis ", "")
color_print_green(" ┬ Chat statistics", "")
color_print_green(
f" {middle_char} Archive of replies saved to: ",
str(obj.reply_file_archive),
)
if obj.user_replier_list_len > 0:
color_print_green(
" └ Active members list who replied to messages, saved to: ",
str(obj.reply_memberlist_filename),
)
color_print_green(" ┬ Top replier 1: ", str(obj.replier_one))
color_print_green(" ├ Top replier 2: ", str(obj.replier_two))
color_print_green(" ├ Top replier 3: ", str(obj.replier_three))
color_print_green(" ├ Top replier 4: ", str(obj.replier_four))
color_print_green(" ├ Top replier 5: ", str(obj.replier_five))
color_print_green(" └ Total unique repliers: ", str(obj.replier_unique))
if type == "forwarder_stat":
color_print_green(" [+] Forward scrape complete", "")
color_print_green(" ┬ Statistics", "")
color_print_green(" ├ Unique forward sources: ", str(obj.unique_forwards))
color_print_green(" ├ Top forward source 1: ", str(obj.forward_one))
color_print_green(" ├ Top forward source 2: ", str(obj.forward_two))
color_print_green(" ├ Top forward source 3: ", str(obj.forward_three))
color_print_green(" ├ Top forward source 4: ", str(obj.forward_four))
color_print_green(" ├ Top forward source 5: ", str(obj.forward_five))
color_print_green(" └ Edgelist saved to: ", obj.edgelist_file)
def create_path(path_d):
if not os.path.exists(path_d):
os.makedirs(path_d)
return path_d
def create_file_report(save_dir, name, type, extension, file_time, append_time=True):
_time_append = ""
if append_time:
_time_append = "_" + file_time
return os.path.join(
"{}".format(save_dir), "{}{}_{}.{}".format(name, _time_append, type, extension)
)
def clean_private_invite(url):
if type(url) is not int:
if "https://t.me/+" in url:
return url.replace("https://t.me/+", "https://t.me/joinchat/")
return url
def evaluate_reactions(message, create=False):
total_reactions = 0
reactions = {}
if not create and message.reactions:
reactions_l = message.reactions.results
for idx, i in enumerate(reactions_l):
total_reactions = total_reactions + i.count
reactions["thumbs_up"] = i.count if i.reaction == "👍" else 0
reactions["thumbs_down"] = i.count if i.reaction == "👎" else 0
reactions["heart"] = i.count if i.reaction == "❤️" else 0
reactions["fire"] = i.count if i.reaction == "🔥" else 0
reactions["smile_with_hearts"] = i.count if i.reaction == "🥰" else 0
reactions["clap"] = i.count if i.reaction == "👏" else 0
reactions["smile"] = i.count if i.reaction == "😁" else 0
reactions["thinking"] = i.count if i.reaction == "🤔" else 0
reactions["exploding_head"] = i.count if i.reaction == "🤯" else 0
reactions["scream"] = i.count if i.reaction == "😱" else 0
reactions["angry"] = i.count if i.reaction == "🤬" else 0
reactions["single_tear"] = i.count if i.reaction == "😢" else 0
reactions["party_popper"] = i.count if i.reaction == "🎉" else 0
reactions["starstruck"] = i.count if i.reaction == "🤩" else 0
reactions["vomiting"] = i.count if i.reaction == "🤮" else 0
reactions["poop"] = i.count if i.reaction == "💩" else 0
reactions["praying"] = i.count if i.reaction == "🙏" else 0
else:
reactions["total_reactions"] = "N/A"
reactions["thumbs_up"] = "N/A"
reactions["thumbs_down"] = "N/A"
reactions["heart"] = "N/A"
reactions["fire"] = "N/A"
reactions["smile_with_hearts"] = "N/A"
reactions["clap"] = "N/A"
reactions["smile"] = "N/A"
reactions["thinking"] = "N/A"
reactions["exploding_head"] = "N/A"
reactions["scream"] = "N/A"
reactions["angry"] = "N/A"
reactions["single_tear"] = "N/A"
reactions["party_popper"] = "N/A"
reactions["starstruck"] = "N/A"
reactions["vomiting"] = "N/A"
reactions["poop"] = "N/A"
reactions["praying"] = "N/A"
return total_reactions, reactions