├── .env.example ├── .gitignore ├── .vscode └── settings.json ├── LICENSE.txt ├── README.md ├── change.log ├── main.py ├── modules ├── __init__.py ├── cars │ ├── __init__.py │ └── lookup.py ├── message │ ├── __init__.py │ └── sendmessage.py └── person │ ├── __init__.py │ └── lookup.py └── requirements.txt /.env.example: -------------------------------------------------------------------------------- 1 | BOT_TOKEN="Insert your telegram bot token here" 2 | MONGODB_URL="Insert your mongo db url here" 3 | DB_NAME="Insert your mongo db name here" 4 | COLLECTION_NAME="Insert your mongo db collection name here" 5 | # Insert your telegram user id/s separated by pipe 6 | USERS="123456789|123456789" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | __pycache__ -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.pylintEnabled": true, 3 | "python.linting.enabled": true 4 | } 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) runtimeterrorist 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tgsint-bot 2 | 3 | [![GitHub stars](https://img.shields.io/github/stars/runtimeterrorist/tgsint-bot.svg)](https://github.com/runtimeterrorist/tgsint-bot/stargazers) 4 | [![GitHub license](https://img.shields.io/github/license/runtimeterrorist/tgsint-bot.svg)](https://github.com/runtimeterrorist/tgsint-bot/blob/master/LICENSE) 5 | [![GitHub forks](https://img.shields.io/github/forks/runtimeterrorist/tgsint-bot.svg)](https://github.com/runtimeterrorist/tgsint-bot/network/members) 6 | [![GitHub issues](https://img.shields.io/github/issues/runtimeterrorist/tgsint-bot.svg)](https://github.com/runtimeterrorist/tgsint-bot/issues) 7 | [![GitHub pull requests](https://img.shields.io/github/issues-pr/runtimeterrorist/tgsint-bot.svg)](https://github.com/runtimeterrorist/tgsint-bot/pulls) 8 | [![GitHub last commit](https://img.shields.io/github/last-commit/runtimeterrorist/tgsint-bot.svg)](https://github.com/runtimeterrorist/tgsint-bot/commits/master) 9 | 10 | tgsint is a OSINT telegram bot written in python. 11 | 12 | ## Installation 13 | 14 | Install necessary dependencies via pip 15 | Install necessary dependencies. 16 | 17 | ```python 18 | pip install -r requirements.txt 19 | ``` 20 | 21 | ## Configuration 22 | 23 | #### Open `.env` file and add required keys/tokens... 24 | 25 | Create a Telegram bot using `@botfather` and get your bot token. 26 | 27 | Change USERS `"1234567890|123456789"` to your own telegram account id/s or simply remove user filter at the dispatcher if you want your bot to be accessible by everyone. 28 | This part filters incoming messages (commands) from users with above specified IDs. 29 | 30 | Check [tgsint-scripts](https://github.com/runtimeterrorist/tgsint-scripts/) for data format. 31 | 32 | ## Usage 33 | 34 | ```bash 35 | Execute main.py 36 | 37 | TELEGRAM BOT: 38 | /help to show available commands 39 | ``` 40 | 41 | ## Features 42 | 43 | 1. Phone number lookup. 44 | 2. Name & Surname lookup. 45 | 3. Lookup information on croatian car licence plates. 46 | 47 | ## Changelog 48 | 49 | Check the changelog file 50 | 51 | ## NOTES: 52 | 53 | In some cases people have their middle name set on their profile page. 54 | Finding them works the same way as for other people , middle name is excluded in the search query. 55 | 56 | ## Contributing 57 | 58 | Pull requests are welcome. 59 | If you have a suggestion open an issue with the tag "enhancement". 60 | 61 | ## Legal disclaimer: 62 | 63 | Developers assume no liability and are not responsible for any misuse or damage caused by this program. 64 | This program is for educational purposes. 65 | 66 | ## License 67 | 68 | [MIT](https://choosealicense.com/licenses/mit/) 69 | -------------------------------------------------------------------------------- /change.log: -------------------------------------------------------------------------------- 1 | 4/22/2022 2 | 3 | - minor phone lookup function update 4 | - updated bihreg param 5 | - replaced whois package with whois backend API on tgsint-api 6 | - new command , nmap quick scan (-sP) , api hosted on tgsint-api 7 | - [!] experimental, nmap scan with custom command parameters (e.g /nmap 8 | - code cleanup and improvements 9 | 10 | 04/29/2022 11 | 12 | - minor changes 13 | - removed nmap quick scan 14 | - replaced zoomeye subdomain scan with nmap hostmap-crtsh script (tgsint-api) 15 | - updated packages 16 | 17 | 05/13/2022 18 | - adjustments to new API format 19 | - minor fixes & formatting 20 | - temporary disabled subdomain scan until dedicated api is completed 21 | 22 | 05/16/2022 23 | - minor adjustments 24 | - enabled subdomain scan 25 | 26 | 05/21/2022 27 | - added missing package in requirements.txt 28 | 29 | 06/12/2022 30 | - command description change 31 | 32 | 07/16/2022 33 | - project structure rework 34 | - updated lookup find by name 35 | - updated readme 36 | - updated packages 37 | 38 | 07/24/2022 39 | - modules rework 40 | - whois rework 41 | - minor improvements 42 | 43 | 09/11/2022 44 | - croreg bugfix / edge case with PP plates 45 | 46 | 04/14/2023 47 | - removed shodan/nmap/whois commands 48 | - code cleanup & improvements 49 | 50 | 09/20/2023 51 | - add logger 52 | - minor code improvements 53 | 54 | 11/26/2023 55 | - removed the need for tgsint-api,requests are sent directly from the bot 56 | - disabled checking for car tech inspection data due to api changes(captcha required) -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | from telegram.ext import Updater, CommandHandler, Filters 4 | from dotenv import load_dotenv 5 | import modules.person.lookup as person 6 | import modules.cars.lookup as cars 7 | 8 | logging.basicConfig( 9 | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) 10 | logger = logging.getLogger(__name__) 11 | 12 | load_dotenv() 13 | bot_token = os.environ.get("BOT_TOKEN") 14 | allowed_users = os.environ.get("USERS").split('|') 15 | 16 | def error(update, context): 17 | """error logger""" 18 | logger.error("%s caused error: %s", update, context.error) 19 | 20 | 21 | def helpmsg(update, context): 22 | """Bot help function,displays help message when called""" 23 | update.message.reply_text(""" 24 | *Available bot commands:*\n 25 | /find - Person lookup by name. 26 | /phone - Person lookup by phone number. 27 | /croreg - Lookup croatian car license plates. 28 | """, parse_mode='Markdown') 29 | 30 | 31 | def main() -> None: 32 | """Main bot function, creates the updater and registers command handlers""" 33 | bot = Updater(bot_token) 34 | users = list(map(int, allowed_users)) 35 | 36 | dispatcher = bot.dispatcher 37 | dispatcher.add_error_handler(error) 38 | dispatcher.add_handler(CommandHandler( 39 | "phone", person.phone, Filters.user(user_id=users))) 40 | dispatcher.add_handler(CommandHandler( 41 | "find", person.find, Filters.user(user_id=users))) 42 | dispatcher.add_handler(CommandHandler( 43 | "croreg", cars.croreg, Filters.user(user_id=users))) 44 | dispatcher.add_handler(CommandHandler( 45 | "help", helpmsg, Filters.user(user_id=users))) 46 | 47 | bot.start_polling() 48 | bot.idle() 49 | 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugourmet/tgsint-bot/85d88608e671d1284082cbe745aaaa00331fc3e9/modules/__init__.py -------------------------------------------------------------------------------- /modules/cars/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugourmet/tgsint-bot/85d88608e671d1284082cbe745aaaa00331fc3e9/modules/cars/__init__.py -------------------------------------------------------------------------------- /modules/cars/lookup.py: -------------------------------------------------------------------------------- 1 | from telegram import Update 2 | from telegram.ext import CallbackContext 3 | import requests 4 | import modules.message.sendmessage as message 5 | import logging 6 | 7 | # def checkvin(vin, month,update: Update): 8 | # """Function used for fetching vehicle inspection data""" 9 | # try: 10 | # url = "https://www.cvh.hr/Umbraco/Surface/TabsSurface/mot" 11 | # data = {"VIN": vin, "month": month} 12 | # headers = { 13 | # "content-type": "application/x-www-form-urlencoded; charset=UTF-8" 14 | # } 15 | # encoded_data = urlencode(data) 16 | 17 | # response = requests.post(url, data=encoded_data, headers=headers, verify=False,timeout=5) 18 | # if response.ok: 19 | # data = response.json() 20 | # return data 21 | # else: 22 | # response.raise_for_status() 23 | # except requests.exceptions.RequestException: 24 | # message.sendmessage( 25 | # "Request timed out. Server is not responding.", update) 26 | # return None 27 | 28 | def croreg(update: Update, context: CallbackContext) -> None: 29 | """Function used for fetching croatian plates info and vehicle inspection data""" 30 | try: 31 | if len(context.args) == 0: 32 | message.sendmessage("Usage: /croreg ZGXXXXX", update) 33 | else: 34 | if len(context.args[0]) < 5: 35 | message.sendmessage( 36 | "Please enter a query longer than 5 chars.", update) 37 | else: 38 | api_url = f"https://api.laqo.hr/webshop/backend/vehicle-api/v2/vehicles?plateNumber={context.args[0]}" 39 | response = requests.get(api_url,timeout=5) 40 | 41 | if response.ok: 42 | data = response.json() 43 | formatted_message = ( 44 | f"*Istek Police: * {data.get('policyExpirationDate')}\n" 45 | f"*Broj Police: * {data.get('policyNumber')}\n" 46 | f"*VIN: * {data.get('vin')}\n" 47 | f"*Tip Automobila: * {data.get('type')}\n" 48 | f"*Marka: * {data.get('manufacturer')}\n" 49 | f"*Model: * {data.get('model')}\n" 50 | f"*Linija: * {data.get('line')}\n" 51 | f"*Tip Goriva: * {data.get('fuelType')}\n" 52 | f"*Godina Proizvodnje: * {data.get('year')}\n" 53 | f"*Boja: * {data.get('color')}\n" 54 | f"*Snaga(kW): * {data.get('kw')}\n" 55 | ) 56 | message.sendmessage(formatted_message, update) 57 | 58 | else: 59 | message.sendmessage( 60 | "Failed to retrieve data from the API.", update) 61 | except requests.exceptions.RequestException: 62 | message.sendmessage( 63 | "Request timed out. Server is not responding.", update) 64 | except KeyError as err: 65 | logging.error(err) 66 | except IndexError: 67 | message.sendmessage("Missing argument!", update) 68 | except TypeError: 69 | message.sendmessage("TypeError!", update) 70 | -------------------------------------------------------------------------------- /modules/message/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugourmet/tgsint-bot/85d88608e671d1284082cbe745aaaa00331fc3e9/modules/message/__init__.py -------------------------------------------------------------------------------- /modules/message/sendmessage.py: -------------------------------------------------------------------------------- 1 | def splitmessage(message): 2 | """Function used for splitting long messages (4096 char/message limit)""" 3 | message_list = [] 4 | if len(message) > 4096: 5 | for num in range(0, len(message), 4096): 6 | message_list.append(message[num:num+4096]) 7 | else: 8 | message_list.append(message) 9 | return message_list 10 | 11 | 12 | def sendmessage(reply, update): 13 | """Send telegram message function""" 14 | messages = splitmessage(reply) 15 | for message in messages: 16 | update.message.reply_text(message, parse_mode='Markdown') 17 | -------------------------------------------------------------------------------- /modules/person/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugourmet/tgsint-bot/85d88608e671d1284082cbe745aaaa00331fc3e9/modules/person/__init__.py -------------------------------------------------------------------------------- /modules/person/lookup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | from telegram import Update 4 | from telegram.ext import CallbackContext 5 | import modules.message.sendmessage as message 6 | import pymongo 7 | 8 | mongo_url = os.environ.get('MONGODB_URL') 9 | database_name = os.environ.get("DB_NAME") 10 | collection_name = os.environ.get("COLLECTION_NAME") 11 | client = pymongo.MongoClient(mongo_url) 12 | database = client[database_name] 13 | collection = database[collection_name] 14 | 15 | def find(update: Update, context: CallbackContext) -> None: 16 | """Function used for finding people by name and surname""" 17 | try: 18 | if len(context.args) < 2: 19 | message.sendmessage("Usage: /find Name Surname", update) 20 | return 21 | 22 | query = { 23 | "name": {"$regex": context.args[0], "$options": "i"}, 24 | "surname": {"$regex": context.args[1], "$options": "i"} 25 | } 26 | results = list(collection.find(query)) 27 | 28 | if not results: 29 | message.sendmessage("User not found", update) 30 | return 31 | 32 | data = [] 33 | for result in results: 34 | data.append(f"\n*Phone Number: * {result.get('phonenum')}") 35 | data.append(f"*Facebook ID: * {result.get('fbid')}") 36 | data.append(f"*Name: * {result.get('name')} {result.get('surname')}") 37 | data.append(f"*Sex: * {result.get('sex')}") 38 | data.append(f"*Location: * {result.get('location')}") 39 | data.append(f"*Extra: * {result.get('extra')}") 40 | 41 | reply = '\n'.join(data) 42 | message.sendmessage(reply, update) 43 | 44 | except KeyError as err: 45 | logging.error("KeyError: %s", err) 46 | message.sendmessage("An error occurred while processing your request.", update) 47 | except IndexError: 48 | message.sendmessage("Missing argument!", update) 49 | 50 | 51 | def phone(update: Update, context: CallbackContext) -> None: 52 | """Function used for finding people by phone number""" 53 | try: 54 | if len(context.args) == 0: 55 | message.sendmessage("Usage: /phone 385123456789", update) 56 | return 57 | 58 | phone_number = context.args[0].replace("+", "") 59 | 60 | query = {"phonenum": phone_number} 61 | results = list(collection.find(query)) 62 | 63 | if not results: 64 | message.sendmessage("User not found", update) 65 | return 66 | 67 | data = [] 68 | for result in results: 69 | data.append(f"\n*Phone Number: * {result.get('phonenum')}") 70 | data.append(f"*Facebook ID: * {result.get('fbid')}") 71 | data.append(f"*Name: * {result.get('name')} {result.get('surname')}") 72 | data.append(f"*Sex: * {result.get('sex')}") 73 | data.append(f"*Location: * {result.get('location')}") 74 | data.append(f"*Extra: * {result.get('extra')}") 75 | 76 | reply = '\n'.join(data) 77 | message.sendmessage(reply, update) 78 | 79 | except KeyError as err: 80 | logging.error("KeyError: %s", err) 81 | message.sendmessage("An error occurred while processing your request.", update) 82 | except IndexError: 83 | message.sendmessage("Missing argument!", update) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | python-dotenv==0.20.0 2 | requests==2.32.0 3 | python-telegram-bot==13.13 4 | pymongo==4.6.3 --------------------------------------------------------------------------------