Skip to content
This repository has been archived by the owner on Sep 7, 2024. It is now read-only.

Commit

Permalink
v1.4: Osintracker export, bug fixes and Surveillance experimental fea…
Browse files Browse the repository at this point in the history
…ture
  • Loading branch information
Alb-310 committed Oct 24, 2023
1 parent 38e93a8 commit 711dadf
Show file tree
Hide file tree
Showing 13 changed files with 524 additions and 46 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ dist
appfiles/config.ini
*.spec
*.session
*.ini
cache
cache_telegram/*
venv/*
utils/__pycache__
geckodriver.log
*/__pycache__/
reportlab/
reportlab/
Geogramint.spec
Geogramint-compiler.iss
10 changes: 4 additions & 6 deletions CLI/TelegramAPIRequests_CLI.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import os
import typer


from rich.progress import Progress
from datetime import datetime
from telethon.errors import SessionPasswordNeededError
from telethon.sync import TelegramClient
from telethon import functions, types
from rich import print

from CLI import ressources_cli

Expand All @@ -23,7 +20,8 @@ def geolocate_AllEntities_Nearby(api_id, api_hash, latitude, longitude, pictures
except OSError:
typer.echo(
typer.style("[WARNING] cache_telegram folder already exist", fg=typer.colors.YELLOW, bold=True))
with TelegramClient("Geogramint", api_id, api_hash) as client:
with TelegramClient("Geogramint", api_id, api_hash, device_model="A320MH", app_version="2.1.4a",
system_version="Windows 10", lang_code="en", system_lang_code="fr-FR") as client:
client.connect()

# datetime object containing current date and time
Expand All @@ -40,12 +38,12 @@ def geolocate_AllEntities_Nearby(api_id, api_hash, latitude, longitude, pictures
))
res = result.stringify()

# parse the result of the API request and Isolate important components
# parse the result of the API request and Isolate important components
usersList = ressources_cli.isolation_Users(res)
peersList = ressources_cli.isolation_Peers(res)
channelsList = ressources_cli.isolation_Channels(res)

# Create List of Objects from the isolated components
# Create List of Objects from the isolated components
ListofGroup = ressources_cli.generate_ListOfGroups(channelsList, peersList)
ListofUser = ressources_cli.generate_ListOfUsers(usersList, peersList)
if pictures:
Expand Down
81 changes: 76 additions & 5 deletions CLI/geogramint_cli.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
__version__ = "v1.3"

import codecs
import json
import os
import shutil
import typer
import rich
import pandas as pd

from rich.console import Console
from rich.table import Table
from CLI import settings_cli, ressources_cli
from CLI.TelegramAPIRequests_CLI import geolocate_AllEntities_Nearby
from CLI import surveillance_cli
import json
import time
import difflib
from datetime import datetime, timedelta
import random

logo_ascii = """
\033[38;5;172;49m___________________________________________________\033[1;0m\n
Expand Down Expand Up @@ -45,14 +50,16 @@ def version_callback(value: bool):
typer.echo(f"{__version__}")
raise typer.Exit()


@CLI.callback()
def version(
version: bool = typer.Option(
False, "--version", help="Show the version", callback=version_callback
)
version: bool = typer.Option(
False, "--version", help="Show the version", callback=version_callback
)
):
pass


@CLI.command(rich_help_panel='Config Commands')
def set_hash(hash: str):
api_id, api_hash, phone_number, extended_report = settings_cli.loadConfig()
Expand Down Expand Up @@ -95,6 +102,7 @@ def set_config(id: int, hash: str, phone: str, extended_report: bool = typer.Opt
def start_scan(lat: float, lon: float, output_json: str = typer.Option("cache_telegram", help="Directory Path"),
output_csv: str = typer.Option("", help="Directory Path"),
output_pdf: str = typer.Option("", help="Directory Path"),
output_osintracker: str = typer.Option("", help="Directory Path"),
profile_pictures: bool = typer.Option(True, help="enable or disable profile pictures download")):
print(logo_ascii)
api_id, api_hash, phone_number, extended_report = settings_cli.loadConfig()
Expand Down Expand Up @@ -165,6 +173,11 @@ def start_scan(lat: float, lon: float, output_json: str = typer.Option("cache_te
output_pdf = output_pdf[:-1]
ressources_cli.generate_pdf_report(users, groups, lat, lon, dt_string, output_pdf, extended_report)

if output_osintracker != "":
if output_osintracker[-1] == '/':
output_osintracker = output_osintracker[:-1]
ressources_cli.generate_osintracker_investigation(users, groups, lat, lon, output_osintracker, extended_report)


@CLI.command(rich_help_panel='Actions Commands')
def reset_scan():
Expand All @@ -173,3 +186,61 @@ def reset_scan():
if os.path.exists("geckodriver.log"):
os.remove("geckodriver.log")
typer.echo(typer.style("cache_telegram deleted", fg=typer.colors.RED, bold=True))


@CLI.command(rich_help_panel='Actions Commands')
def surveillance(lat: float, lon: float, num_days: int = typer.Argument(help="Days of Active Surveillance"),
webhook: str = typer.Argument(help="Discord Webhook url")):
"""
EXPERIMENTAL FEATURE : Work In Progress
This command aims to permit its user to establish a surveillance on an area using Geogramint.
The tool will launch scan every ~1h and retrieve all users and compare it with its previous scan.
If changes are detected, the results will be sent to through the discord webhook.
"""
print(logo_ascii)
api_id, api_hash, phone_number, extended_report = settings_cli.loadConfig()
typer.echo(typer.style("Config Loaded !", fg=typer.colors.GREEN, bold=True))

end_date = datetime.now() + timedelta(days=num_days)
previous_output = ""

while datetime.now() < end_date:

users, groups, dt_string = geolocate_AllEntities_Nearby(api_id, api_hash, lat, lon, True)
ressources_cli.generate_pdf_report(users, groups, lat, lon, dt_string, "cache_telegram", False)

json_string_user = json.dumps([ob.__dict__() for ob in users], ensure_ascii=False)
with codecs.open('cache_telegram/users.json', 'w', 'utf-8') as f:
f.write(json_string_user)

timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
new_output_filename = f"cache_telegram/sorted_users_{timestamp}.txt"

surveillance_cli.process_users("cache_telegram/users.json", new_output_filename)

with open(new_output_filename, "r", encoding="utf-8") as new_output_file:
new_output = new_output_file.readlines()

diff = difflib.unified_diff(previous_output, new_output, lineterm="")
diff_text = "\n".join(diff)
if diff_text:
notification = f"Movement found at {timestamp}:\n{diff_text}"
print(notification)
surveillance_cli.send_webhook_notification(webhook, notification, None)
with open(f"cache_telegram/Report_{str(lat)},{str(lon)}.pdf", "rb") as pdf_file:
files = {"file": ("Report.pdf", pdf_file)}
surveillance_cli.send_webhook_notification(webhook, notification, files)
else:
print(f"No Movement at {timestamp}")

previous_output = new_output

shutil.rmtree("cache_telegram/users/", ignore_errors=True)
shutil.rmtree("cache_telegram/groups/", ignore_errors=True)
shutil.rmtree("cache_telegram/reportfiles/", ignore_errors=True)
shutil.rmtree("cache", ignore_errors=True)
time.sleep(3600 + random.randint(0, 60)) # Sleep for an hour with random seconds to diminish the risks of
# ban by Telegram

shutil.rmtree("cache_telegram", ignore_errors=True)
shutil.rmtree("cache", ignore_errors=True)
48 changes: 40 additions & 8 deletions CLI/ressources_cli.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import codecs
import json
import time
import os
import folium

from io import BytesIO
from rich.progress import Progress
from webdriver_manager.chrome import ChromeDriverManager
from selenium import webdriver
from xhtml2pdf import pisa, default
from xhtml2pdf.default import DEFAULT_CSS
from xhtml2pdf.files import pisaFileObject

from utils.osintracker_export import generate_empty_dexie_json, fill_dexie_json
from utils import User
from utils import Group
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.edge.service import Service as EdgeService
from selenium.webdriver.firefox.service import Service as FirefoxService

global_template = '''
<meta charset="UTF-8">
Expand Down Expand Up @@ -315,7 +322,28 @@ def generate_pdf_report(userlist, grouplist, lat, lon, timestamp, path, extended

with Progress() as progress:
task3 = progress.add_task("[red] Generating report...", total=5)
service = ChromeDriverManager(path="appfiles").install()
try:
service = ChromeService(ChromeDriverManager().install())
options = webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches", ["enable-logging"])
options.add_argument('--headless')
options.add_argument('window-size=1920x1080')
driver = webdriver.Chrome(service=service, options=options)
except:
try:
service = EdgeService(EdgeChromiumDriverManager().install())
options = webdriver.EdgeOptions()
options.use_chromium = True
options.add_argument("disable-logging")
options.add_argument('--headless')
options.add_argument('window-size=1920x1080')
driver = webdriver.Edge(service=service, options=options)
except:
service = FirefoxService(GeckoDriverManager().install())
options = webdriver.FirefoxOptions()
options.add_argument('--headless')
options.add_argument('window-size=1920x1080')
driver = webdriver.Firefox(service=service, options=options)
m = folium.Map(location=[lat, lon], zoom_start=zoom)
folium.Marker(
[lat, lon]
Expand Down Expand Up @@ -363,11 +391,6 @@ def generate_pdf_report(userlist, grouplist, lat, lon, timestamp, path, extended

temp_name = "file://" + os.path.abspath('cache_telegram/reportfiles/map.html')

options = webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches", ["enable-logging"])
options.add_argument('--headless')
options.add_argument('window-size=1920x1080')
driver = webdriver.Chrome(executable_path=service, chrome_options=options)
driver.maximize_window()
driver.get(temp_name)
time.sleep(5)
Expand Down Expand Up @@ -449,3 +472,12 @@ def generate_pdf_report(userlist, grouplist, lat, lon, timestamp, path, extended
pdf = pisa.pisaDocument(BytesIO(template.encode("UTF-8")), result_file, encoding='UTF-8')
progress.update(task3, advance=1)

def generate_osintracker_investigation(users, groups, lat, lon, path, extended_report):

dexie = generate_empty_dexie_json()

osintracker_investigation = fill_dexie_json(users, groups, f"{lat}, {lon}", dexie, extended_report)

json_osintracker = json.dumps(osintracker_investigation, ensure_ascii=False, indent=4)
with codecs.open(path + '/Investigation_Geogramint_' + str(lat) + ',' + str(lon) + '.json', 'w', 'utf-8') as f:
f.write(json_osintracker)
64 changes: 64 additions & 0 deletions CLI/surveillance_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import json
import requests

"""
EXPERIMENTAL FEATURE
"""

def process_users(json_filename, output_filename):
with open(json_filename, "r", encoding="utf-8") as json_file:
data = json.load(json_file)

# Filter users with distances of 500 and 1000
users_500 = [user for user in data if user["distance"] == "500"]
users_1000 = [user for user in data if user["distance"] == "1000"]

# Sort users alphabetically based on their first name
sorted_users_500 = sorted(users_500, key=lambda user: user["id"])
sorted_users_1000 = sorted(users_1000, key=lambda user: user["id"])

def write_users_to_file(users, file):
for user in users:
file.write("ID: {}\n".format(user["id"]))
file.write("First Name: {}\n".format(user["firstname"]))
if user.get("lastname"):
file.write("Last Name: {}\n".format(user["lastname"]))
if user.get("username"):
file.write("Username: {}\n".format(user["username"]))
if user.get("phone"):
file.write("Phone: {}\n".format(user["phone"]))
file.write("Distance: {}m\n\n".format(user["distance"]))
file.write("-" * 40 + "\n") # Add a separator

with open(output_filename, "w", encoding="utf-8") as output_file:
output_file.write("Users within Distance of 500m:\n")
output_file.write("=" * 40 + "\n")
write_users_to_file(sorted_users_500, output_file)

output_file.write("\n\n")

output_file.write("Users within Distance of 1000m:\n")
output_file.write("=" * 40 + "\n")
write_users_to_file(sorted_users_1000, output_file)


def send_webhook_notification(webhook_url, message, files):
while message:
current_message = message[:1500]
message = message[1500:]
payload = {
"content": current_message,
"username": "Geogramint",
"avatar_url": "https://github.com/Alb-310/Geogramint/blob/master/appfiles/Geogramint.png?raw=true"
}

if files is not None:
response = requests.post(webhook_url, files=files)
else:
response = requests.post(webhook_url, json=payload)
if response.status_code == 200 or response.status_code == 204:
print("Webhook notification sent successfully.")
else:
print("Failed to send webhook notification.")


3 changes: 2 additions & 1 deletion api/TelegramAPIRequests.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ def geolocate_AllEntities_Nearby(api_id, api_hash, phone_number, latitude, longi
os.mkdir("cache_telegram")
except OSError:
Logger.warning("Geogramint Files: cache_telegram folder already exist")
client = TelegramClient("Geogramint", api_id, api_hash, loop=loop)
client = TelegramClient("Geogramint", api_id, api_hash, device_model="A320MH", app_version="2.1.4a",
system_version="Windows 10", lang_code="en", system_lang_code="fr-FR", loop=loop)
client.connect()
if not client.is_user_authorized():
client.send_code_request(phone_number) # message send by Telegram with verification code
Expand Down
5 changes: 2 additions & 3 deletions appfiles/config.ini
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
[API]
id = 0
hash =
phone =
hash =
phone =

[REPORT]
extended = True

Binary file added appfiles/osintracker.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 711dadf

Please sign in to comment.