Repository: Alikhalkhali/programs-watcher Branch: main Commit: 0651949dd5bf Files: 16 Total size: 46.5 KB Directory structure: gitextract_cqcphwt2/ ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── config.yml ├── crontab ├── docker-compose.yml ├── main.py ├── modules/ │ ├── notifier/ │ │ ├── discord.py │ │ └── functions.py │ └── platforms/ │ ├── bugcrowd.py │ ├── functions.py │ ├── hackerone.py │ ├── intigriti.py │ └── yeswehack.py └── requirements.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: # .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # poetry # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control #poetry.lock # pdm # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. #pdm.lock # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it # in version control. # https://pdm.fming.dev/#use-with-ide .pdm.toml # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # PyCharm # JetBrains specific template is maintained in a separate JetBrains.gitignore that can # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ ================================================ FILE: Dockerfile ================================================ FROM python:3.9 RUN apt-get update && apt-get -y install cron WORKDIR /app COPY . . RUN pip install -r requirements.txt COPY crontab /etc/cron.d/crontab RUN touch /var/log/cron.log RUN chmod 0644 /etc/cron.d/crontab RUN crontab /etc/cron.d/crontab CMD cron && tail -f /var/log/cron.log ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2023 Ali Khalkhali Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================

Table of Contents

InstallationConfiguring Programs WatcherContributingLicenseContact

# Programs Watcher Programs Watcher is a Python program that monitors and notifies you of new updates from various bug bounty platforms. It uses MongoDB for data storage and Discord webhooks for notifications.

## Youtube Video [![Video Thumbnail](https://github.com/Alikhalkhali/programs-watcher/blob/main/img/Thumbnail.jpg)](https://www.youtube.com/watch?v=V6d6_YVUSR8) # Installation To install Programs Watcher, you have two options depending on your needs. ## Option 1: Docker Installation (Recommended for server environments) 1. Clone the repository to your local machine: ```bash git clone https://github.com/Alikhalkhali/programs-watcher.git ``` 2. Change directory to the project folder: ```bash cd programs-watcher ``` 3. In the `config.yml` file, replace `` with your Discord webhook URL. 4. Run: ```bash docker-compose up -d ``` ## Option 2: Manual Installation (Recommended for desktop and laptop usage) This option is suitable for users who want to run Programs Watcher on their local machines and manually trigger updates and notifications. 1. Install MongoDB: - Download and install MongoDB from the official website: [MongoDB Download](https://www.mongodb.com/try/download/community) - Follow the installation instructions for your operating system. 2. Clone the repository to your local machine: ‍‍‍ ```bash git clone https://github.com/Alikhalkhali/programs-watcher.git ``` 3. Change directory to the project folder: ```bash cd programs-watcher ``` 4. In the `config.yml` file, replace `` with your Discord webhook URL and update the MongoDB connection URL to `mongodb://localhost:27017/`. 5. Install the required dependencies: ```bash pip3 install -r requirements.txt ``` 6. Run the program: ```bash python3 main.py ``` Remember to manually run the program whenever you want to check for updates and receive notifications. This option is recommended for desktop and laptop installations. # Configuring Programs Watcher The Programs Watcher program uses a configuration file named `config.yml` to store information about the bug bounty platforms to monitor and the notification options to use. ## Discord Webhook To use the Discord webhook, replace `` with the actual URL of your webhook in the following line: ```yaml discordWebhook: programs_watcher: ``` ## MongoDB - `uri`: This is the URI of the MongoDB database that the application will use to store data. - `database`: This is the name of the database that the application will use to store data. ## Platforms This section contains a list of bug bounty platforms to monitor. For each platform, provide the name, URL, and a set of notification options. The notification options specify which types of changes should trigger notifications. ### Monitor: Specify the monitoring options for the platform. - `rdp`: Set to true if you want to monitor RDP programs. - `vdp`: Set to true if you want to monitor VDP programs. - `excluded_programs`: List the URLs of the programs you wish to exclude from monitoring. Please note that this applies only to public programs. - `specific_programs`: List the specific program URLs you want to monitor. Note that it only monitors public programs. For example: - bugcrowd: ```yml specific_programs: - https://bugcrowd.com/rarible-ogmbb - https://bugcrowd.com/smartthings ``` - hackerone: ```yml specific_programs: - https://hackerone.com/phabricator?type=team - https://hackerone.com/yahoo?type=team ``` - intigriti: ```yml specific_programs: - https://app.intigriti.com/programs/portofantwerp/nxtport - https://app.intigriti.com/programs/intergamma/intergamma ``` - yeswehack: ```yml specific_programs: - https://yeswehack.com/programs/swiss-post-evoting - https://yeswehack.com/programs/dana-bug-bounty-programd ``` ### Notifications To receive notifications for a specific type of change, set the corresponding notification option to `true`. The available notification options are: - `new_program`: Notify when a new program is added. - `removed_program`: Notify when a program is removed. - `new_inscope`: Notify when a new scope is added. - `removed_inscope`: Notify when a scope is removed. - `new_out_of_scope`: Notify when a new out-of-scope item is added. - `removed_out_of_scope`: Notify when an out-of-scope item is removed. - `new_scope`: Notify when a scope is added or removed. - `changed_scope`: Notify when a scope is modified. - `new_type`: Notify when a new program type is added. - `new_bounty_table`: Notify when a new bounty table is added. Fill in the necessary information for each platform that you want to monitor. # Contributing If you would like to contribute to this project, please fork the repository and submit a pull request. # License This project is licensed under the MIT license. See the LICENSE file for details. # Contact If you have any questions or concerns, please feel free to contact me directly on social media: - Twitter: [ali_khalkhali0](https://twitter.com/ali_khalkhali0) - Instagram: [ali_khalkhali0](https://instagram.com/ali_khalkhali0) I am always happy to hear from you and will do my best to respond to your questions as soon as possible.
#### For Support: [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/alikhalkhali) ================================================ FILE: config.yml ================================================ discordWebhook: programs_watcher: mongoDB: uri: mongodb://db:27017/ database: programs_watcher platforms: - name: bugcrowd url: https://raw.githubusercontent.com/Osb0rn3/bugbounty-targets/main/programs/bugcrowd.json monitor: rdp: true vdp: true specific_programs: [] excluded_programs: [] notifications: new_program: true removed_program: true new_inscope: true removed_inscope: true new_out_of_scope: true removed_out_of_scope: true new_type: true new_bounty_table: true - name: hackerone url: https://raw.githubusercontent.com/Osb0rn3/bugbounty-targets/main/programs/hackerone.json monitor: rdp: true vdp: true specific_programs: [] excluded_programs: - https://hackerone.com/alshaya?type=team - https://hackerone.com/gsa_vdp?type=team - https://hackerone.com/clarivate?type=team notifications: new_program: true removed_program: true new_scope: true removed_scope: true changed_scope: true new_type: true - name: intigriti url: https://raw.githubusercontent.com/Osb0rn3/bugbounty-targets/main/programs/intigriti.json monitor: rdp: true vdp: true specific_programs: [] excluded_programs: [] notifications: new_program: true removed_program: true new_scope: true removed_scope: true changed_scope: true new_type: true new_bounty_table: true - name: yeswehack url: https://raw.githubusercontent.com/Osb0rn3/bugbounty-targets/main/programs/yeswehack.json monitor: rdp: true vdp: true specific_programs: [] excluded_programs: [] notifications: new_program: true removed_program: true new_inscope: true removed_inscope: true new_type: true new_bounty_table: true ================================================ FILE: crontab ================================================ */30 * * * * root cd /app && /usr/local/bin/python main.py >> /var/log/cron.log 2>&1 ================================================ FILE: docker-compose.yml ================================================ version: "3" services: app: build: . volumes: - ./config.yml:/app/config.yml db: image: mongo:4.0-xenial volumes: - mongo_data:/data/db volumes: mongo_data: ================================================ FILE: main.py ================================================ import yaml from pymongo import MongoClient import os import shutil from modules.platforms.bugcrowd import check_bugcrowd from modules.platforms.hackerone import check_hackerone from modules.platforms.intigriti import check_intigriti from modules.platforms.yeswehack import check_yeswehack from modules.notifier.discord import send_startup_message # load config file with open("config.yml", "r") as ymlfile: cfg = yaml.full_load(ymlfile) discord_webhook = cfg['discordWebhook']['programs_watcher'] platforms = {} for platform in cfg['platforms']: platforms[platform['name']] = { 'url': platform['url'], 'notifications': platform['notifications'], 'monitor': platform['monitor'] } # connect to MongoDB client = MongoClient(cfg['mongoDB']['uri']) dbName = cfg['mongoDB']['database'] db = client[dbName] first_time = False if dbName not in client.list_database_names(): first_time = True # Check ./tmp directory exists tmp_dir = f"./tmp/" if os.path.exists(tmp_dir): shutil.rmtree(tmp_dir) os.mkdir(tmp_dir) else: os.mkdir(tmp_dir) # checking bugcrowd check_bugcrowd(tmp_dir, discord_webhook, first_time, db, platforms['bugcrowd']) # checking hackerone check_hackerone(tmp_dir, discord_webhook, first_time, db, platforms['hackerone']) # checking intigriti check_intigriti(tmp_dir, discord_webhook, first_time, db, platforms['intigriti']) # checking yeswehack check_yeswehack(tmp_dir, discord_webhook, first_time, db, platforms['yeswehack']) # Clean up resources and remove tmp_dir client.close() shutil.rmtree(tmp_dir) if first_time: send_startup_message(discord_webhook) ================================================ FILE: modules/notifier/discord.py ================================================ from discord_webhook import DiscordWebhook, DiscordEmbed from modules.notifier.functions import generate_diff, split_text, get_platform_profile, shorten_string def add_field(embed, data, message, diff=False): texts = split_text(data) isFirstTime = 0 type = "" if diff: type = "diff\n" for text in texts: if isFirstTime == 0: embed.add_embed_field( name=message, value=f"```{type}{text}```", inline=False) isFirstTime = 1 else: embed.add_embed_field( name=" ", value=f"```{type}{text}```", inline=False) def changed_program_message(data): embed = DiscordEmbed(title=f"{data['programName']}", description=f"** {data['programName']} ** has changed!\n** Program type: ** {data['programType']}\n\n** Program page: ** [Click here]({data['programURL']})", color=data['color']) embed.set_thumbnail(url=data['logo']) embed.set_footer(text='Powered by Ali Khalkhali', icon_url='https://cdn.discordapp.com/avatars/941457826662985808/488f3bcab0de041de57860b4e05e2e9f.webp') if data["platformName"] in ["HackerOne", "Intigriti"]: if data["newProgramType"]: embed.add_embed_field(name="Program type changed:", value=f"```changed to {data['newProgramType']}```", inline=False) if data["platformName"] == "Intigriti": if data['newReward']: embed.add_embed_field( name="Bounty Table changed:", value=f"```{data['newReward']['min']} -- {data['newReward']['max']}```", inline=False) if data["newScope"]: scope = '\n'.join(data['newScope']) add_field(embed, scope, "Following scope added:") if data["removedScope"]: removedScope = '\n'.join(data['removedScope']) add_field(embed, removedScope, "Following Scope removed:") if data["changedScope"]: for scope in data["changedScope"]: old = scope["old"] new = scope["new"] diff = generate_diff(old, new) add_field(embed, diff, "Following scope changed:", True) if data["platformName"] in ["Bugcrowd", "YesWeHack"]: if data['newType']: embed.add_embed_field( name="Program Type changed", value=f"```New Type: {data['newType']}```", inline=False) if data['reward']: embed.add_embed_field(name="Bounty Table changed:", value=f"```{data['reward']['min']} -- {data['reward']['max']}```", inline=False) if data['newInScope']: inscope = '\n'.join(data['newInScope']) add_field(embed, inscope, "Following inScope added:") if data['removeInScope']: removeInScope = '\n'.join(data['removeInScope']) add_field(embed, removeInScope, "Following Inscope removed:") if data["platformName"] == "Bugcrowd": if data['newOutOfScope']: newOutOfScope = '\n'.join(data['newOutOfScope']) add_field(embed, newOutOfScope, "Following out of scope added:") if data['removeOutOfScope']: removeOutOfScope = '\n'.join(data['removeOutOfScope']) add_field(embed, removeOutOfScope, "Following out of scope removed:") embed.add_embed_field(name=" ", value= "[Click here to Buy me a coffee ☕](https://www.buymeacoffee.com/alikhalkhali)", inline=False) return embed def new_program_message(data): embed = DiscordEmbed(title=f"{data['programName']}", description=f"** New program ** named** {data['programName']} ** added to platform!\n** Program type: ** {data['programType']}\n\n** Program page: ** [Click here]({data['programURL']})", color=data['color']) embed.set_thumbnail(url=data['logo']) embed.set_footer(text='Powered by Ali Khalkhali', icon_url='https://cdn.discordapp.com/avatars/941457826662985808/488f3bcab0de041de57860b4e05e2e9f.webp') if data["platformName"] in ["HackerOne", "Intigriti"]: if data["platformName"] == "Intigriti": if data['newReward']: embed.add_embed_field( name="Bounty Table:", value=f"```{data['newReward']['min']} -- {data['newReward']['max']}```", inline=False) if data["newScope"]: scope = "" for newScope in data["newScope"]: scope += f"{shorten_string(newScope)}\n" add_field(embed, scope, "Scope:") if data["platformName"] in ["Bugcrowd", "YesWeHack"]: if data['reward']: embed.add_embed_field( name="Bounty Table:", value=f"```{data['reward']['min']} -- {data['reward']['max']}```", inline=False) if data['newInScope']: inscope = '\n'.join(data['newInScope']) add_field(embed, inscope, "InScope:") if data["platformName"] == "Bugcrowd": if data['newOutOfScope']: newOutOfScope = '\n'.join(data['newOutOfScope']) add_field(embed, newOutOfScope, "Out of scope:") embed.add_embed_field(name=" ", value= "[Click here to Buy me a coffee ☕](https://www.buymeacoffee.com/alikhalkhali)", inline=False) return embed def removed_program_message(data): embed = DiscordEmbed(title=f"{data['programName']}", description=f"Program named ** {data['programName']} ** has removed from platform!\n** Program type: ** {data['programType']}", color=data['color']) embed.set_thumbnail(url=data['logo']) embed.set_footer(text='Powered by Ali Khalkhali', icon_url='https://cdn.discordapp.com/avatars/941457826662985808/488f3bcab0de041de57860b4e05e2e9f.webp') embed.add_embed_field(name=" ", value= "[Click here to Buy me a coffee ☕](https://www.buymeacoffee.com/alikhalkhali)", inline=False) return embed def send_notification(data, webhook_url): webhook = DiscordWebhook( url=webhook_url, username=data['platformName'], avatar_url=get_platform_profile(data['platformName'])) if data["isRemoved"]: embed = removed_program_message(data) elif data["isNewProgram"]: embed = new_program_message(data) else: embed = changed_program_message(data) webhook.add_embed(embed) response = webhook.execute() if response.status_code != 200: print(data["programName"]) print("Error sending message:", response.content) def send_startup_message(webhook_url): webhook = DiscordWebhook( url=webhook_url, username="Programs Watcher", avatar_url="https://t3.ftcdn.net/jpg/00/91/64/62/360_F_91646202_b3K6ELfgM2E8QIwuNTlzco7K1r3mOJvp.jpg") embed = DiscordEmbed(title=f"🎉 Successful Start of Programs Watcher 🎉", description= "Hi, welcome to ** Programs Watcher **! 🎉\nThe program has started successfully and is now waiting for a change. 🗼✨\n** Github page: ** https://github.com/Alikhalkhali/programs-watcher", color="23ff1f") embed.set_footer(text='Powered by Ali Khalkhali', icon_url='https://cdn.discordapp.com/avatars/941457826662985808/488f3bcab0de041de57860b4e05e2e9f.webp') embed.add_embed_field(name=" ", value= "[Click here to Buy me a coffee ☕](https://www.buymeacoffee.com/alikhalkhali)", inline=False) webhook.add_embed(embed) response = webhook.execute() if response.status_code != 200: print("There was an error sending the Discord message") ================================================ FILE: modules/notifier/functions.py ================================================ import difflib def get_platform_profile(platform_name): if platform_name == "HackerOne": profile_url = "https://profile-photos.hackerone-user-content.com/variants/000/000/013/fa942b9b1cbf4faf37482bf68458e1195aab9c02_original.png/e60fe2d979b041d2254f8a36a3d2d7a24d7c4a8ad33ea024d13fc56668c7c4f6" elif platform_name == "Bugcrowd": profile_url = "https://logos.bugcrowdusercontent.com/logos/ef74/d1fa/62a5b64c/3809e0af42850a579f02c3434743e3ca_bugcrowd__1_.png" elif platform_name == "Intigriti": profile_url = "https://api.intigriti.com/file/api/file/public_bucket_d23a1f29-c2fe-4d03-8daf-df24d1e076ea-c2449aa2-3a08-4bf5-a430-441a11020851" elif platform_name == "YesWeHack": profile_url = "https://avatars.githubusercontent.com/u/16663829?s=280&v=4" return profile_url def shorten_string(string): if len(string) > 30: return string[:30] + "...\n" else: return string def split_text(huge_text, max_chunk_size=1000): sentences = huge_text.split('\n') chunks = [] current_chunk = "" for sentence in sentences: if len(current_chunk) + len(sentence) + 1 <= max_chunk_size: current_chunk += (sentence + '\n') else: chunks.append(current_chunk.strip()) current_chunk = sentence + '\n' if current_chunk: chunks.append(current_chunk.strip()) return chunks def generate_diff(old_str, new_str): diff = difflib.ndiff(old_str.splitlines(), new_str.splitlines()) result = [] for line in diff: if line.startswith('+'): result.append(f'+{line[1:]}') elif line.startswith('-'): result.append(f'-{line[1:]}') elif line.startswith(' '): result.append(line) return '\n'.join(result) ================================================ FILE: modules/platforms/bugcrowd.py ================================================ import json from modules.platforms.functions import find_program, generate_program_key, get_resource, remove_elements, save_data, check_send_notification from modules.notifier.discord import send_notification # checking bugcrowd def check_bugcrowd(tmp_dir, mUrl, first_time, db, config): json_programs_key = [] notifications = config['notifications'] monitor = config['monitor'] get_resource(tmp_dir, config['url'], "bugcrowd") bugcrowdFile = open(f"{tmp_dir}bugcrowd.json") bugcrowd = json.load(bugcrowdFile) bugcrowdFile.close() for program in bugcrowd: programName = program["name"] programURL = "https://bugcrowd.com"+program["briefUrl"] logo = program["logoUrl"] data = {"programName": programName, "reward": {},"isRemoved": False, "newType": "", "newInScope": [], "removeInScope": [], "newOutOfScope": [], "removeOutOfScope": [], "programURL": programURL, "logo": logo, "platformName": "Bugcrowd", "isNewProgram": False, "color": 14584064} dataJson = {"programName": programName, "programURL": programURL, "programType": "", "outOfScope": [], "inScope": [], "reward": {}} programKey = generate_program_key(programName, programURL) json_programs_key.append(programKey) watcherData = find_program(db, 'bugcrowd', programKey) if watcherData is None: data["isNewProgram"] = True watcherData = {"programKey": programKey, "programName": programName, "programURL": programURL, "programType": "", "outOfScope": [], "inScope": [], "reward": {}} for target in program["target_groups"]: if target["in_scope"] == False: for item in target["targets"]: dataJson["outOfScope"].append(item["name"]) else: for item in target["targets"]: dataJson["inScope"].append((item["name"])) bounty = { "min": "", "max": "" } if "rewardSummary" in program and program["rewardSummary"] != None: dataJson["programType"] = "rdp" data["programType"] = "rdp" bounty["max"] = program["rewardSummary"]["maxReward"] bounty["min"] = program["rewardSummary"]["minReward"] else: dataJson["programType"] = "vdp" data["programType"] = "vdp" dataJson["reward"] = bounty newInScope = [i for i in dataJson["inScope"] if i not in watcherData["inScope"]] removeInScope = [i for i in watcherData["inScope"] if i not in dataJson["inScope"]] removedOutOfScope = [i for i in watcherData["outOfScope"] if i not in dataJson["outOfScope"]] newOutOfScope = [i for i in dataJson["outOfScope"] if i not in watcherData["outOfScope"]] hasChanged = False is_update = False if newInScope: watcherData["inScope"].extend(newInScope) notifi_status = notifications['new_inscope'] hasChanged = True if notifi_status: data["newInScope"] = newInScope is_update = True if removeInScope: remove_elements(watcherData["inScope"], removeInScope) hasChanged = True notifi_status = notifications['removed_inscope'] if notifi_status: data["removeInScope"] = removeInScope is_update = True if newOutOfScope: watcherData["outOfScope"].extend(newOutOfScope) hasChanged = True notifi_status = notifications['new_out_of_scope'] if notifi_status: data["newOutOfScope"] = newOutOfScope is_update = True if removedOutOfScope: remove_elements(watcherData["outOfScope"], removedOutOfScope) hasChanged = True notifi_status = notifications['removed_out_of_scope'] if notifi_status: data["removeOutOfScope"] = removedOutOfScope is_update = True if dataJson["programType"] != watcherData["programType"]: watcherData["programType"] = dataJson["programType"] hasChanged = True notifi_status = notifications['new_type'] if notifi_status: data["newType"] = dataJson["programType"] is_update = True if dataJson["reward"] != watcherData["reward"]: watcherData["reward"] = bounty hasChanged = True notifi_status = notifications['new_bounty_table'] if notifi_status: data["reward"] = bounty is_update = True if hasChanged: save_data(db, "bugcrowd", programKey, watcherData) if check_send_notification(first_time, is_update, data,watcherData, monitor, notifications): send_notification(data, mUrl) db_programs_key = db['bugcrowd'].distinct("programKey") removed_programs_key = set(db_programs_key) - set(json_programs_key) for program_key in removed_programs_key: program = find_program(db,'bugcrowd', program_key) data = { "color": 14584064, "logo": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwToiI8YA0eLclDkd-vJ0xXs7bun5LdHfTrgJucvI&s", "platformName": "Bugcrowd", "isRemoved": True, "programName": program["programName"], "programType": program["programType"] } if notifications['removed_program'] and not first_time: send_notification(data,mUrl) db['bugcrowd'].delete_many({"programKey": program_key}) ================================================ FILE: modules/platforms/functions.py ================================================ import requests from hashlib import md5 def get_resource(tmp_dir, url, platformName): domainList = requests.get(url, allow_redirects=True) open(F"{tmp_dir}{platformName}.json", 'wb').write(domainList.content) def generate_program_key(programName, programURL): program_key = md5( f"{programName}|{programURL}".encode('utf-8')).hexdigest() return program_key def find_program(db, platformName, programKey): data = db[platformName].find_one({'programKey': programKey}) return data def remove_elements(array1, array2): for element in array2: array1.remove(element) def save_data(db, platformName, programKey, dataJson): db[platformName].update_one({'programKey': programKey}, { '$set': dataJson}, upsert=True) def check_send_notification(first_time,is_update,data,watcherData,monitor,notifications): pt_notify_status = False notify_status = False if data['isNewProgram']: if data['programType'] == "rdp" and monitor['rdp']: pt_notify_status = True elif data['programType'] == "vdp" and monitor["vdp"]: pt_notify_status = True else: if watcherData['programType'] == "rdp" and monitor['rdp']: pt_notify_status = True elif watcherData['programType'] == "vdp" and monitor["vdp"]: pt_notify_status = True if watcherData['programURL'] in monitor['specific_programs']: pt_notify_status = True if pt_notify_status: if not first_time and data['isNewProgram'] and notifications['new_program']: notify_status = True elif not first_time and is_update and not data['isNewProgram']: notify_status = True if watcherData['programURL'] in monitor['excluded_programs']: print(watcherData['programURL']) notify_status = False return notify_status ================================================ FILE: modules/platforms/hackerone.py ================================================ import json from modules.platforms.functions import find_program, generate_program_key, get_resource, save_data, check_send_notification from modules.notifier.discord import send_notification # checking hackerone def check_hackerone(tmp_dir, mUrl, first_time, db, config): json_programs_key = [] notifications = config['notifications'] monitor = config['monitor'] get_resource(tmp_dir, config['url'], "hackerone") hackeroneFile = open(f"{tmp_dir}hackerone.json") hackerone = json.load(hackeroneFile) hackeroneFile.close() for program in hackerone: programName = program["attributes"]["name"] logo = program["attributes"]["profile_picture"] if logo.startswith("https://hackerone-us-west-2-p"): logo = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTBmCle7j7K48bRZz483rDz52Nc6w0au28ASw&usqp=CAU" programURL = "https://hackerone.com/" + \ program["attributes"]["handle"]+"?type=team" data = {"programName": programName, "programType": "", "programURL": programURL, "logo": logo, "platformName": "HackerOne", "isRemoved": False,"isNewProgram": False, "color": 16777215} dataJson = {"programName": programName, "programURL": programURL, "programType": "", "scope": {}} programKey = generate_program_key(programName, programURL) json_programs_key.append(programKey) watcherData = find_program(db, 'hackerone', programKey) if watcherData is None: data["isNewProgram"] = True watcherData = {"programName": programName, "programURL": programURL, "programType": "", "scope": {}} if program["attributes"]["offers_bounties"]: dataJson["programType"] = "rdp" data["programType"] = "rdp" else: dataJson["programType"] = "vdp" data["programType"] = "vdp" for target in program["relationships"]["structured_scopes"]["data"]: targetType = "" if target['attributes']['eligible_for_submission']: targetType = "(InScope)" else: targetType = "(OutOfScope)" if target['attributes']['instruction'] is not None: dataJson["scope"][target["id"] ] = f"{target['attributes']['asset_identifier']} {targetType}\n{target['attributes']['instruction']}\n" else: dataJson["scope"][target["id"] ] = f"{target['attributes']['asset_identifier']} {targetType}\n" hasChanged = False scopeId = {prop for prop in dataJson["scope"]} dbScopeId = {prop for prop in watcherData["scope"]} newScope = scopeId - dbScopeId removedScope = dbScopeId - scopeId scopeId = scopeId - newScope data["newScope"] = [] data["changedScope"] = [] data["removedScope"] = [] data["newProgramType"] = [] hasChanged = False is_update = False if newScope: notifi_status = notifications['new_scope'] for i in newScope: if notifi_status: data["newScope"].append(dataJson["scope"][i]) is_update = True watcherData["scope"][i] = dataJson["scope"][i] hasChanged = True if removedScope: notifi_status = notifications['removed_scope'] for i in removedScope: if notifi_status: data["removedScope"].append(watcherData["scope"][i]) is_update = True del watcherData["scope"][i] hasChanged = True if dataJson["programType"] != watcherData["programType"]: notifi_status = notifications['new_type'] if notifi_status: data["newProgramType"] = dataJson["programType"] is_update = True watcherData["programType"] = dataJson["programType"] hasChanged = True notifi_status = notifications['changed_scope'] for id in scopeId: if dataJson["scope"][id] != watcherData["scope"][id]: if notifi_status: scope = { "new": dataJson["scope"][id], "old": watcherData["scope"][id], } data["changedScope"].append(scope) is_update = True watcherData["scope"][id] = dataJson["scope"][id] hasChanged = True if hasChanged: save_data(db, "hackerone", programKey, watcherData) if check_send_notification(first_time, is_update, data,watcherData, monitor, notifications): send_notification(data, mUrl) db_programs_key = db['hackerone'].distinct("programKey") removed_programs_key = set(db_programs_key) - set(json_programs_key) for program_key in removed_programs_key: program = find_program(db,'hackerone', program_key) data = { "color": 16777215, "logo": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwToiI8YA0eLclDkd-vJ0xXs7bun5LdHfTrgJucvI&s", "platformName": "HackerOne", "isRemoved": True, "programName": program["programName"], "programType": program["programType"] } if notifications['removed_program'] and not first_time: send_notification(data,mUrl) db['hackerone'].delete_many({"programKey": program_key}) ================================================ FILE: modules/platforms/intigriti.py ================================================ import json from modules.platforms.functions import find_program, generate_program_key, get_resource, save_data, check_send_notification from modules.notifier.discord import send_notification # checking intigriti def check_intigriti(tmp_dir, mUrl, first_time, db, config): json_programs_key = [] notifications = config['notifications'] monitor = config['monitor'] get_resource(tmp_dir, config['url'], "intigriti") intigriti = open(f"{tmp_dir}intigriti.json") intigriti = json.load(intigriti) for program in intigriti: programName = program["name"] logo = "https://secure.gravatar.com/avatar/8609b9cc1f1333c3632b2afdc8607f4d?s=500&d=identicon&r=g" programURL = f"https://app.intigriti.com/{program['webLinks']['detail']}" data = {"programName": programName, "programType": "", "programURL": programURL, "logo": logo, "platformName": "Intigriti","isRemoved": False, "isNewProgram": False, "color": 10858237} dataJson = {"programName": programName, "programURL": programURL, "programType": "", "scope": {}, "reward": {}} programKey = generate_program_key(programName, programURL) json_programs_key.append(programKey) watcherData = find_program(db, 'intigriti', programKey) if watcherData is None: data["isNewProgram"] = True watcherData = {"programName": programName, "programURL": programURL, "programType": "", "scope": {}, "reward": {}} if "domains" in program: for target in program['domains']: if target['description'] is not None: dataJson['scope'][target['id'] ] = f"{target['endpoint']}\n{target['description']}\n" else: dataJson['scope'][target['id']] = f"{target['endpoint']}\n" if program["maxBounty"]["value"] > 0: dataJson["programType"] = "rdp" bounty = { "min": f"{program['minBounty']['value']} {program['minBounty']['currency']}", "max": f"{program['maxBounty']['value']} {program['maxBounty']['currency']}" } dataJson["reward"] = bounty data["programType"] = "rdp" else: dataJson["programType"] = "vdp" data["programType"] = "vdp" # Checking for changes hasChanged = False scopeId = {prop for prop in dataJson["scope"]} dbScopeId = {prop for prop in watcherData["scope"]} newScope = scopeId - dbScopeId removedScope = dbScopeId - scopeId scopeId = scopeId - newScope data["newScope"] = [] data["changedScope"] = [] data["removedScope"] = [] data["newProgramType"] = [] data["newReward"] = [] hasChanged = False is_update = False if newScope: notifi_status = notifications['new_scope'] for i in newScope: if notifi_status: data["newScope"].append(dataJson["scope"][i]) is_update = True watcherData["scope"][i] = dataJson["scope"][i] hasChanged = True if removedScope: notifi_status = notifications['removed_scope'] for i in removedScope: if notifi_status: data["removedScope"].append(watcherData["scope"][i]) is_update = True del watcherData["scope"][i] hasChanged = True if dataJson["programType"] != watcherData["programType"]: notifi_status = notifications['new_type'] if notifi_status: data["newProgramType"] = dataJson["programType"] is_update = True watcherData["programType"] = dataJson["programType"] hasChanged = True if dataJson["reward"] != watcherData["reward"]: notifi_status = notifications['new_bounty_table'] if notifi_status: data["newReward"] = dataJson["reward"] is_update = True watcherData["reward"] = dataJson["reward"] hasChanged = True notifi_status = notifications['changed_scope'] for id in scopeId: if dataJson["scope"][id] != watcherData["scope"][id]: if notifi_status: scope = { "new": dataJson["scope"][id], "old": watcherData["scope"][id], } data["changedScope"].append(scope) is_update = True watcherData["scope"][id] = dataJson["scope"][id] hasChanged = True if hasChanged: save_data(db, "intigriti", programKey, watcherData) if check_send_notification(first_time, is_update, data,watcherData, monitor, notifications): send_notification(data, mUrl) db_programs_key = db['intigriti'].distinct("programKey") removed_programs_key = set(db_programs_key) - set(json_programs_key) for program_key in removed_programs_key: program = find_program(db,'intigriti', program_key) data = { "color": 10858237, "logo": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwToiI8YA0eLclDkd-vJ0xXs7bun5LdHfTrgJucvI&s", "platformName": "Intigriti", "isRemoved": True, "programName": program["programName"], "programType": program["programType"] } if notifications['removed_program'] and not first_time: send_notification(data,mUrl) db['intigriti'].delete_many({"programKey": program_key}) ================================================ FILE: modules/platforms/yeswehack.py ================================================ import json from modules.platforms.functions import find_program, generate_program_key, get_resource, remove_elements, save_data, check_send_notification from modules.notifier.discord import send_notification # checking yeswehack def check_yeswehack(tmp_dir, mUrl, first_time, db, config): json_programs_key = [] notifications = config['notifications'] monitor = config['monitor'] get_resource(tmp_dir, config['url'], "yeswehack") yeswehack = open(f"{tmp_dir}yeswehack.json") yeswehack = json.load(yeswehack) for program in yeswehack: programName = program['title'] logo = program['thumbnail']['url'] programURL = f"https://yeswehack.com/programs/{program['slug']}" data = {"programName": programName, "programType": "", "programURL": programURL, "logo": logo, "platformName": "YesWeHack","isRemoved": False, "isNewProgram": False, "color": 16270147} dataJson = {"programName": programName, "programURL": programURL, "programType": "", "inScope": [], "reward": {}} programKey = generate_program_key(programName, programURL) json_programs_key.append(programKey) watcherData = find_program(db, 'yeswehack', programKey) if watcherData is None: data["isNewProgram"] = True watcherData = {"programName": programName, "programURL": programURL, "programType": "", "inScope": [], "reward": {}} for target in program["scopes"]: dataJson['inScope'].append(target['scope']) if program["bounty"]: dataJson['programType'] = "rdp" data['programType'] = "rdp" currency = program['business_unit']['currency'] bounty = { "min": f"{program['bounty_reward_min']} {currency}", "max": f"{program['bounty_reward_max']} {currency}" } dataJson['reward'] = bounty else: dataJson['programType'] = "vdp" data['programType'] = "vdp" newInScope = [i for i in dataJson["inScope"] if i not in watcherData["inScope"]] removeInScope = [i for i in watcherData["inScope"] if i not in dataJson["inScope"]] data["newType"] = [] data["reward"] = [] data["removeInScope"] = [] data["newInScope"] = [] hasChanged = False is_update = False if newInScope: watcherData["inScope"].extend(newInScope) notifi_status = notifications['new_inscope'] if notifi_status: data["newInScope"] = newInScope is_update = True hasChanged = True if removeInScope: remove_elements(watcherData["inScope"], removeInScope) notifi_status = notifications['removed_inscope'] if notifi_status: data["removeInScope"] = removeInScope is_update = True hasChanged = True if dataJson['reward'] != watcherData['reward']: watcherData["reward"] = dataJson['reward'] notifi_status = notifications['new_bounty_table'] if notifi_status: data["reward"] = dataJson['reward'] is_update = True hasChanged = True if dataJson["programType"] != watcherData["programType"]: notifi_status = notifications['new_type'] if notifi_status: data["newType"] = dataJson["programType"] is_update = True watcherData["programType"] = dataJson["programType"] hasChanged = True if hasChanged: save_data(db, "yeswehack", programKey, watcherData) if check_send_notification(first_time, is_update, data,watcherData, monitor, notifications): send_notification(data, mUrl) db_programs_key = db['yeswehack'].distinct("programKey") removed_programs_key = set(db_programs_key) - set(json_programs_key) for program_key in removed_programs_key: program = find_program(db,'yeswehack', program_key) data = { "color": 16270147, "logo": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwToiI8YA0eLclDkd-vJ0xXs7bun5LdHfTrgJucvI&s", "platformName": "YesWeHack", "isRemoved": True, "programName": program["programName"], "programType": program["programType"] } if notifications['removed_program'] and not first_time: send_notification(data,mUrl) db['yeswehack'].delete_many({"programKey": program_key}) ================================================ FILE: requirements.txt ================================================ certifi==2023.7.22 charset-normalizer==3.2.0 discord-webhook==1.3.0 dnspython==2.4.2 idna==3.4 pymongo==4.5.0 PyYAML==6.0.1 requests==2.31.0 urllib3==2.0.5