mirror of
https://github.com/bellingcat/octosuite.git
synced 2026-06-13 05:48:34 +03:00
Compare commits
33 Commits
1.2.0
...
1.5.1-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d1e163d9a | ||
|
|
a8730864e9 | ||
|
|
315cb7ec6f | ||
|
|
2afac6c0d4 | ||
|
|
b226f1b53b | ||
|
|
bb38d95e57 | ||
|
|
eae41866ec | ||
|
|
1e71c2d3bd | ||
|
|
d91f88d31b | ||
|
|
d5119a87b0 | ||
|
|
c4bd431620 | ||
|
|
fe16b23fc7 | ||
|
|
8156af38d5 | ||
|
|
6fb6a0ec98 | ||
|
|
dc2a22aae0 | ||
|
|
a2aac88da3 | ||
|
|
3dbfc0f18e | ||
|
|
392b3022d7 | ||
|
|
162d36d741 | ||
|
|
49490ed95b | ||
|
|
78966551ee | ||
|
|
a939b89d23 | ||
|
|
f79ce44bc9 | ||
|
|
7e45fa5669 | ||
|
|
f55e1b3895 | ||
|
|
1ea78c2e0b | ||
|
|
2272e7ff81 | ||
|
|
44ce7799f4 | ||
|
|
6c6fc477f8 | ||
|
|
d7060e33dd | ||
|
|
b47b073af4 | ||
|
|
4f196660bc | ||
|
|
e073d63845 |
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
- OS: [e.g. iOS]
|
||||||
|
- Browser [e.g. chrome, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Smartphone (please complete the following information):**
|
||||||
|
- Device: [e.g. iPhone6]
|
||||||
|
- OS: [e.g. iOS8.1]
|
||||||
|
- Browser [e.g. stock browser, safari]
|
||||||
|
- Version [e.g. 22]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Richard Mwewa (Telegram)
|
||||||
|
url: https://t.me/rly0nheart/
|
||||||
|
about: Please ask and answer questions here.
|
||||||
|
- name: Richard Mwewa (Twitter)
|
||||||
|
url: https://m.twitter.com/rly0nheart/
|
||||||
|
about: Please report security vulnerabilities or bugs here.
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
13
.github/dependabot.yml
vendored
Normal file
13
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
# Enable version updates for pip
|
||||||
|
- package-ecosystem: "pip"
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
# Check the tqdm registry for updates every day (weekdays)
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
5
LICENSE
5
LICENSE
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
@@ -631,8 +632,8 @@ to attach them to the start of each source file to most effectively
|
|||||||
state the exclusion of warranty; and each file should have at least
|
state the exclusion of warranty; and each file should have at least
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
octosuite Advanced Github OSINT Framework
|
||||||
Copyright (C) <year> <name of author>
|
Copyright (C) 2022 Richard Mwewa
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
124
README.md
124
README.md
@@ -1,68 +1,120 @@
|
|||||||

|

|
||||||
|
|
||||||
|
|
||||||

|
|
||||||

|

|
||||||

|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||

|

|
||||||

|
|
||||||

|

|
||||||
|
|
||||||
> *Simply gather OSINT on Github users and organizations like a god🔥*
|
> *Simply gather OSINT on Github users & organizations like a God🔥*
|
||||||
|
|
||||||
|
# FEATURES
|
||||||
|
- [x] Fetches organization info
|
||||||
|
- [x] Fetches user info
|
||||||
|
- [x] Fetches repository info
|
||||||
|
- [x] Returns contents of a path from a repository
|
||||||
|
- [x] Returns a list of repos owned by an organization
|
||||||
|
- [x] Returns a list of repos owned by a user
|
||||||
|
- [x] Returns a list of gists owned by a user
|
||||||
|
- [x] Returns a list of a user's followers
|
||||||
|
- [x] Checks whether user A follows user B
|
||||||
|
- [x] Searches users
|
||||||
|
- [x] Searches repositories
|
||||||
|
- [x] Searches topics
|
||||||
|
- [x] Searches issues
|
||||||
|
- [x] Searches commits
|
||||||
|
- [x] Easily updates with the 'update' command
|
||||||
|
- [x] Automatically logs network activity (.logs folder)
|
||||||
|
|
||||||
# INSTALLATION
|
# INSTALLATION
|
||||||
**clone project**:
|
## Clone from Github
|
||||||
|
|
||||||
```
|
```
|
||||||
$ git clone https://github.com/rly0nheart/octosuite.git
|
git clone https://github.com/rly0nheart/octosuite.git
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
$ cd octosuite
|
cd octosuite
|
||||||
```
|
|
||||||
|
|
||||||
# USAGE
|
|
||||||
**Linux**:
|
|
||||||
```
|
|
||||||
$ sudo chmod +x octosuite
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ./octosuite
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
**Windows**:
|
## Install from PyPI
|
||||||
```
|
```
|
||||||
$ python3 octosuite
|
pip install octosuite
|
||||||
|
```
|
||||||
|
|
||||||
|
# GITHUB FORK USAGE
|
||||||
|
## Linux
|
||||||
|
```
|
||||||
|
sudo chmod +x octosuite
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo ./octosuite
|
||||||
|
```
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
```
|
||||||
|
python3 octosuite
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mac
|
||||||
|
```
|
||||||
|
python3 octosuite
|
||||||
|
```
|
||||||
|
|
||||||
|
# PYPI PACKAGE USAGE
|
||||||
|
## Linux
|
||||||
|
```
|
||||||
|
octosuite
|
||||||
|
```
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
```
|
||||||
|
octosuite
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mac
|
||||||
|
```
|
||||||
|
octosuite
|
||||||
```
|
```
|
||||||
|
|
||||||
# AVAILABLE COMMANDS
|
# AVAILABLE COMMANDS
|
||||||
| Command | Usage|
|
| Command | Usage|
|
||||||
| ------------- |:---------:|
|
| ------------- |:---------:|
|
||||||
| <code>orginfo</code> | *get organization info* |
|
| ``orginfo`` | *get organization info* |
|
||||||
| <code>userinfo</code> | *get user profile info* |
|
| ``userinfo`` | *get user profile info* |
|
||||||
| <code>repoinfo</code> | *get repository info* |
|
| ``repoinfo`` | *get repository info* |
|
||||||
| <code>pathcontents</code> | *get contents of a path from a specified repository* |
|
| ``pathcontents`` | *get contents of a path from a specified repository* |
|
||||||
| <code>orgrepos</code> | *get a list of repositories owned by a specified organization* |
|
| ``orgrepos`` | *get a list of repositories owned by a specified organization* |
|
||||||
| <code>userrepos</code> | *get a list of repositories owned by a specified user* |
|
| ``userrepos`` | *get a list of repositories owned by a specified user* |
|
||||||
| <code>usergists</code> | *get a list of gists owned by a specified user* |
|
| ``usergists`` | *get a list of gists owned by a specified user* |
|
||||||
| <code>userfollowers</code> | *get a list of a user's followers* |
|
| ``userfollowers`` | *get a list of a user's followers* |
|
||||||
| <code>userfollowing</code> | *check whether user A follows user B* |
|
| ``userfollowing`` | *check whether user A follows user B* |
|
||||||
| <code>usersearch</code> | *search user(s)* |
|
| ``usersearch`` | *search user(s)* |
|
||||||
| <code>reposearch</code> | *search repositor(y)(ies)* |
|
| ``reposearch`` | *search repositor(y)(ies)* |
|
||||||
| <code>topicsearch</code> | *search topics(s)* |
|
| ``topicsearch`` | *search topics(s)* |
|
||||||
| <code>issuesearch</code> | *search issue(s)* |
|
| ``issuesearch`` | *search issue(s)* |
|
||||||
| <code>commitsearch</code> | *search commit(s)* |
|
| ``commitsearch`` | *search commit(s)* |
|
||||||
| <code>usersearch</code> | *search user(s)* |
|
| ``update`` | *update octosuite* |
|
||||||
| <code>update</code> | *check for/download updates* |
|
| ``changelog`` | *show changelog* |
|
||||||
| <code>author</code> | *show author info* |
|
| ``author`` | *show author info* |
|
||||||
| <code>help</code> | *show usage/help* |
|
| ``help`` | *show usage/help* |
|
||||||
| <code>exit</code> | *exit session* |
|
| ``exit`` | *exit session* |
|
||||||
|
|
||||||
|
|
||||||
# NOTE
|
# NOTE
|
||||||
* *octosuite automatically logs network and minor user activity. The logs are saved by date and time in .logs folder*
|
* *octosuite automatically logs network and minor user activity. The logs are saved by date and time in .logs folder*
|
||||||
* *octosuite has only been tested on **Termux** *and* **Kali Linux** (for now), please be sure to let me know how it works on **Windows***
|
* *Although octosuite was developed to work on **Mac**, **Windows**, or any **Linux** *Distribution*, it has only been tested on **Termux** *and* **Kali Linux***
|
||||||
|
|
||||||
|
# PYPI
|
||||||
|
[PyPI](https://pypi.org/project/octosuite)
|
||||||
|
|
||||||
# LICENSE
|
# LICENSE
|
||||||

|

|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import os
|
||||||
from lib.colors import red,white,green,reset
|
from lib.colors import red,white,green,reset
|
||||||
banner = f'''{red}
|
banner = f'''{red}
|
||||||
▒█████ ▄████▄ ▄▄▄█████▓ ▒█████ ██████ █ ██ ██▓▄▄▄█████▓▓█████
|
▒█████ ▄████▄ ▄▄▄█████▓ ▒█████ ██████ █ ██ ██▓▄▄▄█████▓▓█████
|
||||||
@@ -7,11 +8,13 @@ banner = f'''{red}
|
|||||||
░ ████▓▒░▒ ▓███▀ ░ ▒██▒ ░ ░ ████▓▒░▒██████▒▒▒█████▓ ░██░ ▒██▒ ░ ░▒████▒
|
░ ████▓▒░▒ ▓███▀ ░ ▒██▒ ░ ░ ████▓▒░▒██████▒▒▒█████▓ ░██░ ▒██▒ ░ ░▒████▒
|
||||||
░ ▒░▒░▒░ ░ ░▒ ▒ ░ ▒ ░░ ░ ▒░▒░▒░ ▒ ▒▓▒ ▒ ░░▒▓▒ ▒ ▒ ░▓ ▒ ░░ ░░ ▒░ ░
|
░ ▒░▒░▒░ ░ ░▒ ▒ ░ ▒ ░░ ░ ▒░▒░▒░ ▒ ▒▓▒ ▒ ░░▒▓▒ ▒ ▒ ░▓ ▒ ░░ ░░ ▒░ ░
|
||||||
░ ▒ ▒░ ░ ▒ ░ ░ ▒ ▒░ ░ ░▒ ░ ░░░▒░ ░ ░ ▒ ░ ░ ░ ░ ░
|
░ ▒ ▒░ ░ ▒ ░ ░ ▒ ▒░ ░ ░▒ ░ ░░░▒░ ░ ░ ▒ ░ ░ ░ ░ ░
|
||||||
░ ░ ░ ▒ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░░░ ░ ░ ▒ v1.1.0
|
░ ░ ░ ▒ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░░░ ░ ░ ▒ v1.5.1-beta
|
||||||
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
|
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
|
||||||
░ {white}— Advanced Github {red}OSINT{white} Framework{reset}
|
░ {white}— Advanced Github {red}OSINT{white} Framework{reset}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
> {white}Welcome {os.getlogin()}{reset}
|
||||||
> {white}use '{green}help{white}' command for usage{reset}
|
> {white}use '{green}help{white}' command for usage{reset}
|
||||||
> {white}commands are case sensitive
|
> {white}commands are case sensitive
|
||||||
{'-'*30}
|
{'-'*30}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
# Colors will be unavailable on non-linux machines
|
||||||
colors = True
|
colors = True
|
||||||
machine = sys.platform # Detecting the os
|
machine = sys.platform
|
||||||
if machine.lower().startswith(("os", "win", "darwin")):
|
if machine.lower().startswith(("os", "win", "darwin","ios")):
|
||||||
colors = False # Colors will not be displayed
|
colors = False
|
||||||
|
|
||||||
if not colors:
|
if not colors:
|
||||||
reset = red = white = green = ""
|
reset = red = white = green = ""
|
||||||
|
|||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
tqdm
|
||||||
|
requests
|
||||||
255
src/main.py
255
src/main.py
@@ -1,18 +1,28 @@
|
|||||||
|
'''
|
||||||
|
octosuite Advanced Github OSINT Framework
|
||||||
|
Copyright (C) 2022 Richard Mwewa
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
'''
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
import requests
|
||||||
import platform
|
import platform
|
||||||
import subprocess
|
import subprocess
|
||||||
import urllib.request
|
from tqdm import tqdm
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
from lib import colors,banner
|
from lib.banner import banner
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
try:
|
from lib.colors import red, white, green, reset
|
||||||
import requests
|
|
||||||
except ImportError:
|
|
||||||
print(f'{colors.white}[{colors.green}*{colors.white}] Installing requirement(s). Please wait...{colors.reset}')
|
|
||||||
subprocess.run(['pip', 'install', 'requests'],shell=False)
|
|
||||||
exit(f'{colors.white}[{colors.green}+{colors.white}] Installation complete. Re-run octosuite.{colors.reset}')
|
|
||||||
|
|
||||||
|
|
||||||
class octosuite:
|
class octosuite:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -155,9 +165,6 @@ class octosuite:
|
|||||||
# Author dictionary
|
# Author dictionary
|
||||||
self.author_dict = {'Alias': 'rly0nheart',
|
self.author_dict = {'Alias': 'rly0nheart',
|
||||||
'Country': 'Zambia, Africa',
|
'Country': 'Zambia, Africa',
|
||||||
'Github': 'https://github.com/rly0nheart',
|
|
||||||
'Twitter': 'https://twitter.com/rly0nheart',
|
|
||||||
'Facebook': 'https://fb.me/rly0nheart',
|
|
||||||
'About.me': 'https://about.me/rly0nheart'}
|
'About.me': 'https://about.me/rly0nheart'}
|
||||||
|
|
||||||
def on_start(self):
|
def on_start(self):
|
||||||
@@ -168,8 +175,8 @@ class octosuite:
|
|||||||
else:
|
else:
|
||||||
subprocess.run(['clear'],shell=False)
|
subprocess.run(['clear'],shell=False)
|
||||||
|
|
||||||
print(banner.banner)
|
print(banner)
|
||||||
command = input(f'''{colors.white}┌─({colors.red}{platform.node()}{colors.white}@{colors.red}octosuite{colors.white})-[{colors.green}{os.getcwd()}{colors.white}]\n└─╼[{colors.green}:~{colors.white}]{colors.reset} ''')
|
command = input(f'''{white}┌─({red}{os.getlogin()}{white}@{red}octosuite{white})-[{green}{os.getcwd()}{white}]\n└─╼[{green}:~{white}]{reset} ''')
|
||||||
if command == 'orginfo':
|
if command == 'orginfo':
|
||||||
self.org_info()
|
self.org_info()
|
||||||
elif command == 'userinfo':
|
elif command == 'userinfo':
|
||||||
@@ -200,261 +207,303 @@ class octosuite:
|
|||||||
self.commits_search()
|
self.commits_search()
|
||||||
elif command == 'update':
|
elif command == 'update':
|
||||||
self.update()
|
self.update()
|
||||||
|
elif command == 'changelog':
|
||||||
|
print(self.changelog())
|
||||||
elif command == 'author':
|
elif command == 'author':
|
||||||
self.author()
|
self.author()
|
||||||
|
elif command == 'ilinso':
|
||||||
|
self.easter_egg()
|
||||||
elif command == 'help':
|
elif command == 'help':
|
||||||
print(self.help())
|
print(self.help())
|
||||||
elif command == 'exit':
|
elif command == 'exit':
|
||||||
logging.info('Session terminated.')
|
logging.info('Session terminated with \'exit\' command')
|
||||||
exit(f'\n{colors.white}[{colors.red}-{colors.white}] Session terminated.{colors.reset}')
|
exit(f'\n{white}[{red}-{white}] Session terminated with \'exit\' command{reset}')
|
||||||
else:
|
else:
|
||||||
print(f'\n{colors.white}[{colors.red}!{colors.white}] Unknown command: ‘{command}’{colors.reset}')
|
print(f'\n{white}[{red}!{white}] Command not found: ‘{command}’{reset}')
|
||||||
logging.warning(f'Unknown command: ‘{command}’')
|
logging.warning(f'command not found: ‘{command}’')
|
||||||
|
|
||||||
input(f'\n{colors.white}^ Press any key to continue{colors.reset} ')
|
input(f'\n{white}[{green}?{white}] Press any key to continue{reset} ')
|
||||||
|
|
||||||
|
|
||||||
def org_info(self):
|
def org_info(self):
|
||||||
organization = input(f'{colors.white}@{colors.green}Organization{colors.white} >> {colors.reset}')
|
organization = input(f'{white}@{green}Organization {white}>>{reset} ')
|
||||||
api = f'https://api.github.com/orgs/{organization}'
|
api = f'https://api.github.com/orgs/{organization}'
|
||||||
response = requests.get(api)
|
response = requests.get(api)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
print(f'\n{colors.white}[{colors.red}-{colors.white}] Organization @{organization} {colors.red}Not Found{colors.reset}')
|
print(f'\n{white}[{red}-{white}] Organization @{organization} {red}Not Found{reset}')
|
||||||
else:
|
else:
|
||||||
response = response.json()
|
response = response.json()
|
||||||
print(f"\n{colors.white}{response['name']}{colors.reset}")
|
print(f"\n{white}{response['name']}{reset}")
|
||||||
for attr in self.org_attrs:
|
for attr in self.org_attrs:
|
||||||
print(f'{colors.white}├─ {self.org_attr_dict[attr]}: {colors.green}{response[attr]}{colors.reset}')
|
print(f'{white}├─ {self.org_attr_dict[attr]}: {green}{response[attr]}{reset}')
|
||||||
|
|
||||||
|
|
||||||
# Fetching user information
|
# Fetching user information
|
||||||
def user_profile(self):
|
def user_profile(self):
|
||||||
username = input(f'{colors.white}@{colors.green}Username{colors.white} >> {colors.reset}')
|
username = input(f'{white}@{green}Username{white} >> {reset}')
|
||||||
api = f'https://api.github.com/users/{username}'
|
api = f'https://api.github.com/users/{username}'
|
||||||
response = requests.get(api)
|
response = requests.get(api)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
print(f'\n{colors.white}[{colors.red}-{colors.white}] User @{username} {colors.red}Not Found{colors.reset}')
|
print(f'\n{white}[{red}-{white}] User @{username} {red}Not Found{reset}')
|
||||||
else:
|
else:
|
||||||
response = response.json()
|
response = response.json()
|
||||||
print(f"\n{colors.white}{response['name']}{colors.reset}")
|
print(f"\n{white}{response['name']}{reset}")
|
||||||
for attr in self.profile_attrs:
|
for attr in self.profile_attrs:
|
||||||
print(f'{colors.white}├─ {self.profile_attr_dict[attr]}: {colors.green}{response[attr]}{colors.reset}')
|
print(f'{white}├─ {self.profile_attr_dict[attr]}: {green}{response[attr]}{reset}')
|
||||||
|
|
||||||
|
|
||||||
# Fetching repository information
|
# Fetching repository information
|
||||||
def repo_info(self):
|
def repo_info(self):
|
||||||
username = input(f'{colors.white}@{colors.green}Owner-username{colors.white} >> {colors.reset}')
|
username = input(f'{white}@{green}Owner-username{white} >> {reset}')
|
||||||
repo_name = input(f'{colors.white}%{colors.green}reponame{colors.white} >> {colors.reset}')
|
repo_name = input(f'{white}%{green}reponame{white} >> {reset}')
|
||||||
api = f'https://api.github.com/repos/{username}/{repo_name}'
|
api = f'https://api.github.com/repos/{username}/{repo_name}'
|
||||||
response = requests.get(api)
|
response = requests.get(api)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
print(f'\n{colors.white}[{colors.red}-{colors.white}] Repository %{repo_name} {colors.red}Not Found{colors.reset}')
|
print(f'\n{white}[{red}-{white}] Repository %{repo_name} {red}Not Found{reset}')
|
||||||
else:
|
else:
|
||||||
response = response.json()
|
response = response.json()
|
||||||
print(f"\n{colors.white}{response['full_name']}{colors.reset}")
|
print(f"\n{white}{response['full_name']}{reset}")
|
||||||
for attr in self.repo_attrs:
|
for attr in self.repo_attrs:
|
||||||
print(f"{colors.white}├─ {self.repo_attr_dict[attr]}: {colors.green}{response[attr]}{colors.reset}")
|
print(f"{white}├─ {self.repo_attr_dict[attr]}: {green}{response[attr]}{reset}")
|
||||||
|
|
||||||
|
|
||||||
# Get path contents
|
# Get path contents
|
||||||
def path_contents(self):
|
def path_contents(self):
|
||||||
username = input(f'{colors.white}@{colors.green}Owner-username{colors.white} >> {colors.reset}')
|
username = input(f'{white}@{green}Owner-username{white} >> {reset}')
|
||||||
repo_name = input(f'{colors.white}%{colors.green}reponame{colors.white} >> {colors.reset}')
|
repo_name = input(f'{white}%{green}reponame{white} >> {reset}')
|
||||||
path_name = input(f'{colors.white}/path/name >>{colors.reset} ')
|
path_name = input(f'{white}/path/name >>{reset} ')
|
||||||
api = f'https://api.github.com/repos/{username}/{repo_name}/contents/{path_name}'
|
api = f'https://api.github.com/repos/{username}/{repo_name}/contents/{path_name}'
|
||||||
response = requests.get(api)
|
response = requests.get(api)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
print(f'\n{colors.white}[{colors.red}-{colors.white}] Information {colors.red}Not Found{colors.reset}')
|
print(f'\n{white}[{red}-{white}] Information {red}Not Found{reset}')
|
||||||
else:
|
else:
|
||||||
response = response.json()
|
response = response.json()
|
||||||
for item in response:
|
for item in response:
|
||||||
print(f"\n{colors.white}{item['name']}{colors.reset}")
|
print(f"\n{white}{item['name']}{reset}")
|
||||||
for attr in self.path_attrs:
|
for attr in self.path_attrs:
|
||||||
print(f'{colors.white}├─ {self.path_attr_dict[attr]}: {colors.green}{item[attr]}{colors.reset}')
|
print(f'{white}├─ {self.path_attr_dict[attr]}: {green}{item[attr]}{reset}')
|
||||||
|
|
||||||
|
|
||||||
# Fetching organozation repositories
|
# Fetching organozation repositories
|
||||||
def org_repos(self):
|
def org_repos(self):
|
||||||
organization = input(f'{colors.white}@{colors.green}Organization{colors.white} >> {colors.reset}')
|
organization = input(f'{white}@{green}Organization{white} >> {reset}')
|
||||||
api = f'https://api.github.com/orgs/{organization}/repos?per_page=100'
|
api = f'https://api.github.com/orgs/{organization}/repos?per_page=100'
|
||||||
response = requests.get(api)
|
response = requests.get(api)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
print(f'\n{colors.white}[{colors.red}-{colors.white}] Organization @{organization} {colors.red}Not Found{colors.reset}')
|
print(f'\n{white}[{red}-{white}] Organization @{organization} {red}Not Found{reset}')
|
||||||
else:
|
else:
|
||||||
response = response.json()
|
response = response.json()
|
||||||
for repo in response:
|
for repo in response:
|
||||||
print(f"\n{colors.white}{repo['full_name']}{colors.reset}")
|
print(f"\n{white}{repo['full_name']}{reset}")
|
||||||
for attr in self.repo_attrs:
|
for attr in self.repo_attrs:
|
||||||
print(f"{colors.white}├─ {self.repo_attr_dict[attr]}: {colors.green}{repo[attr]}{colors.reset}")
|
print(f"{white}├─ {self.repo_attr_dict[attr]}: {green}{repo[attr]}{reset}")
|
||||||
print('\n')
|
print('\n')
|
||||||
|
|
||||||
|
|
||||||
# Fetching user repositories
|
# Fetching user repositories
|
||||||
def user_repos(self):
|
def user_repos(self):
|
||||||
username = input(f'{colors.white}@{colors.green}Username{colors.white} >> {colors.reset}')
|
username = input(f'{white}@{green}Username{white} >> {reset}')
|
||||||
api = f'https://api.github.com/users/{username}/repos?per_page=100'
|
api = f'https://api.github.com/users/{username}/repos?per_page=100'
|
||||||
response = requests.get(api)
|
response = requests.get(api)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
print(f'\n{colors.white}[{colors.red}-{colors.white}] User @{username} {colors.red}Not Found{colors.reset}')
|
print(f'\n{white}[{red}-{white}] User @{username} {red}Not Found{reset}')
|
||||||
else:
|
else:
|
||||||
response = response.json()
|
response = response.json()
|
||||||
for repo in response:
|
for repo in response:
|
||||||
print(f"\n{colors.white}{repo['full_name']}{colors.reset}")
|
print(f"\n{white}{repo['full_name']}{reset}")
|
||||||
for attr in self.repo_attrs:
|
for attr in self.repo_attrs:
|
||||||
print(f"{colors.white}├─ {self.repo_attr_dict[attr]}: {colors.green}{repo[attr]}{colors.reset}")
|
print(f"{white}├─ {self.repo_attr_dict[attr]}: {green}{repo[attr]}{reset}")
|
||||||
print('\n')
|
print('\n')
|
||||||
|
|
||||||
|
|
||||||
# Fetching user's gists
|
# Fetching user's gists
|
||||||
def user_gists(self):
|
def user_gists(self):
|
||||||
username = input(f'{colors.white}@{colors.green}Username{colors.white} >> {colors.reset}')
|
username = input(f'{white}@{green}Username{white} >> {reset}')
|
||||||
api = f'https://api.github.com/users/{username}/gists'
|
api = f'https://api.github.com/users/{username}/gists'
|
||||||
response = requests.get(api).json()
|
response = requests.get(api).json()
|
||||||
if response == []:
|
if response == []:
|
||||||
print(f'{colors.white}[{colors.red}-{colors.white}]User @{username} does not have any active gists.{colors.reset}')
|
print(f'{white}[{red}-{white}]User @{username} does not have any active gists.{reset}')
|
||||||
else:
|
else:
|
||||||
for item in response:
|
for item in response:
|
||||||
print(f"\n{colors.white}{item['id']}{colors.reset}")
|
print(f"\n{white}{item['id']}{reset}")
|
||||||
for attr in self.gists_attrs:
|
for attr in self.gists_attrs:
|
||||||
print(f"{colors.white}├─ {self.gists_attr_dict[attr]}: {colors.green}{item[attr]}{colors.reset}")
|
print(f"{white}├─ {self.gists_attr_dict[attr]}: {green}{item[attr]}{reset}")
|
||||||
print('\n')
|
print('\n')
|
||||||
|
|
||||||
|
|
||||||
# Fetching user's followera'
|
# Fetching user's followera'
|
||||||
def followers(self):
|
def followers(self):
|
||||||
username = input(f'{colors.white}@{colors.green}Username{colors.white} >> {colors.reset}')
|
username = input(f'{white}@{green}Username{white} >> {reset}')
|
||||||
api = f'https://api.github.com/users/{username}/followers?per_page=100'
|
api = f'https://api.github.com/users/{username}/followers?per_page=100'
|
||||||
response = requests.get(api).json()
|
response = requests.get(api).json()
|
||||||
if response == []:
|
if response == []:
|
||||||
print(f'\n{colors.white}[{colors.red}-{colors.white}]User @{username} does not have followers.{colors.reset}')
|
print(f'\n{white}[{red}-{white}]User @{username} does not have followers.{reset}')
|
||||||
else:
|
else:
|
||||||
for item in response:
|
for item in response:
|
||||||
print(f"\n{colors.white}@{item['login']}{colors.reset}")
|
print(f"\n{white}@{item['login']}{reset}")
|
||||||
for attr in self.user_attrs:
|
for attr in self.user_attrs:
|
||||||
print(f"{colors.white}├─ {self.user_attr_dict[attr]}: {colors.green}{item[attr]}{colors.reset}")
|
print(f"{white}├─ {self.user_attr_dict[attr]}: {green}{item[attr]}{reset}")
|
||||||
print('\n')
|
print('\n')
|
||||||
|
|
||||||
|
|
||||||
# Checking whether or not user[A] follows user[B]
|
# Checking whether or not user[A] follows user[B]
|
||||||
def following(self):
|
def following(self):
|
||||||
user_a = input(f'{colors.white}@{colors.green}User[A]{colors.white} >> {colors.reset}')
|
user_a = input(f'{white}@{green}User[A]{white} >> {reset}')
|
||||||
user_b = input(f'{colors.white}@{colors.green}User[B]{colors.white} >> {colors.reset}')
|
user_b = input(f'{white}@{green}User[B]{white} >> {reset}')
|
||||||
api = f'https://api.github.com/users/{user_a}/following/{user_b}'
|
api = f'https://api.github.com/users/{user_a}/following/{user_b}'
|
||||||
response = requests.get(api)
|
response = requests.get(api)
|
||||||
if response.status_code == 204:
|
if response.status_code == 204:
|
||||||
print(f'{colors.white}[{colors.green}+{colors.white}] @{user_a} follows @{user_b}.{colors.reset}')
|
print(f'{white}[{green}+{white}] @{user_a} follows @{user_b}.{reset}')
|
||||||
else:
|
else:
|
||||||
print(f'{colors.white}[{colors.red}-{colors.white}] @{user_a} does not follow @{user_b}.{colors.reset}')
|
print(f'{white}[{red}-{white}] @{user_a} does not follow @{user_b}.{reset}')
|
||||||
|
|
||||||
|
|
||||||
# User search
|
# User search
|
||||||
def user_search(self):
|
def user_search(self):
|
||||||
query = input(f'{colors.white}#{colors.green}Query{colors.white} >> {colors.reset}')
|
query = input(f'{white}#{green}Query{white} >> {reset}')
|
||||||
api = f'https://api.github.com/search/users?q={query}&per_page=100'
|
api = f'https://api.github.com/search/users?q={query}&per_page=100'
|
||||||
response = requests.get(api).json()
|
response = requests.get(api).json()
|
||||||
for item in response['items']:
|
for item in response['items']:
|
||||||
print(f"\n{colors.white}@{item['login']}{colors.reset}")
|
print(f"\n{white}@{item['login']}{reset}")
|
||||||
for attr in self.user_attrs:
|
for attr in self.user_attrs:
|
||||||
print(f"{colors.white}├─ {self.user_attr_dict[attr]}: {colors.green}{item[attr]}{colors.reset}")
|
print(f"{white}├─ {self.user_attr_dict[attr]}: {green}{item[attr]}{reset}")
|
||||||
print('\n')
|
print('\n')
|
||||||
|
|
||||||
|
|
||||||
# Repository search
|
# Repository search
|
||||||
def repo_search(self):
|
def repo_search(self):
|
||||||
query = input(f'{colors.white}#{colors.green}Query{colors.white} >> {colors.reset}')
|
query = input(f'{white}#{green}Query{white} >> {reset}')
|
||||||
api = f'https://api.github.com/search/repositories?q={query}&per_page=100'
|
api = f'https://api.github.com/search/repositories?q={query}&per_page=100'
|
||||||
response = requests.get(api).json()
|
response = requests.get(api).json()
|
||||||
for item in response['items']:
|
for item in response['items']:
|
||||||
print(f"\n{colors.white}{item['full_name']}{colors.reset}")
|
print(f"\n{white}{item['full_name']}{reset}")
|
||||||
for attr in self.repo_attrs:
|
for attr in self.repo_attrs:
|
||||||
print(f"{colors.white}├─ {self.repo_attr_dict[attr]}: {colors.green}{item[attr]}{colors.reset}")
|
print(f"{white}├─ {self.repo_attr_dict[attr]}: {green}{item[attr]}{reset}")
|
||||||
print('\n')
|
print('\n')
|
||||||
|
|
||||||
|
|
||||||
# Topics search
|
# Topics search
|
||||||
def topic_search(self):
|
def topic_search(self):
|
||||||
query = input(f'{colors.white}#{colors.green}Query{colors.white} >> {colors.reset}')
|
query = input(f'{white}#{green}Query{white} >> {reset}')
|
||||||
api = f'https://api.github.com/search/topics?q={query}&per_page=100'
|
api = f'https://api.github.com/search/topics?q={query}&per_page=100'
|
||||||
response = requests.get(api).json()
|
response = requests.get(api).json()
|
||||||
for item in response['items']:
|
for item in response['items']:
|
||||||
print(f"\n{colors.white}{item['name']}{colors.reset}")
|
print(f"\n{white}{item['name']}{reset}")
|
||||||
for attr in self.topic_attrs:
|
for attr in self.topic_attrs:
|
||||||
print(f"{colors.white}├─ {self.topic_attr_dict[attr]}: {colors.green}{item[attr]}{colors.reset}")
|
print(f"{white}├─ {self.topic_attr_dict[attr]}: {green}{item[attr]}{reset}")
|
||||||
print('\n')
|
print('\n')
|
||||||
|
|
||||||
|
|
||||||
# Issue search
|
# Issue search
|
||||||
def issue_search(self):
|
def issue_search(self):
|
||||||
query = input(f'{colors.white}#{colors.green}Query{colors.white} >> {colors.reset}')
|
query = input(f'{white}#{green}Query{white} >> {reset}')
|
||||||
api = f'https://api.github.com/search/issues?q={query}&per_page=100'
|
api = f'https://api.github.com/search/issues?q={query}&per_page=100'
|
||||||
response = requests.get(api).json()
|
response = requests.get(api).json()
|
||||||
for item in response['items']:
|
for item in response['items']:
|
||||||
print(f"\n{colors.white}{item['title']}{colors.reset}")
|
print(f"\n{white}{item['title']}{reset}")
|
||||||
for attr in self.issue_attrs:
|
for attr in self.issue_attrs:
|
||||||
print(f"{colors.white}├─ {self.issue_attr_dict[attr]}: {colors.green}{item[attr]}{colors.reset}")
|
print(f"{white}├─ {self.issue_attr_dict[attr]}: {green}{item[attr]}{reset}")
|
||||||
print('\n')
|
print('\n')
|
||||||
|
|
||||||
|
|
||||||
# Commits search
|
# Commits search
|
||||||
def commits_search(self):
|
def commits_search(self):
|
||||||
query = input(f'{colors.white}#{colors.green}Query{colors.white} >> {colors.reset}')
|
query = input(f'{white}#{green}Query{white} >> {reset}')
|
||||||
api = f'https://api.github.com/search/commits?q={query}&per_page=100'
|
api = f'https://api.github.com/search/commits?q={query}&per_page=100'
|
||||||
response = requests.get(api).json()
|
response = requests.get(api).json()
|
||||||
n=0
|
n=0
|
||||||
for item in response['items']:
|
for item in response['items']:
|
||||||
n+=1
|
n+=1
|
||||||
print(f'{colors.white}{n}.{colors.reset}')
|
print(f'{white}{n}.{reset}')
|
||||||
pprint(item['commit'])
|
pprint(item['commit'])
|
||||||
print('\n')
|
print('\n')
|
||||||
|
|
||||||
|
|
||||||
# Update program
|
# Update program
|
||||||
def update(self):
|
def update(self):
|
||||||
logging.info('Checking for update(s)...')
|
logging.info('Fetching updates...')
|
||||||
files_to_update = ['src/main.py','lib/banner.py','lib/colors.py','octosuite','LICENSE','README.md']
|
files_to_update = ['src/main.py','lib/banner.py','lib/colors.py','octosuite','.github/dependabot.yml','LICENSE','README.md','requirements.txt']
|
||||||
print(f'\n{colors.white}[{colors.green}*{colors.white}] Fetching update(s). Please wait...{colors.reset}',end='')
|
for file in tqdm(files_to_update,desc=f'{white}[{green}*{white}] Updating{reset}'):
|
||||||
for file in files_to_update:
|
data = requests.get(f'https://raw.githubusercontent.com/rly0nheart/octosuite/master/{file}')
|
||||||
data = urllib.request.urlopen(f'https://raw.githubusercontent.com/rly0nheart/octosuite/master/{file}').read()
|
|
||||||
with open(file, 'wb') as code:
|
with open(file, 'wb') as code:
|
||||||
code.write(data)
|
code.write(data.content)
|
||||||
code.close()
|
code.close()
|
||||||
|
|
||||||
logging.info('Update complete.')
|
logging.info('Update complete.')
|
||||||
exit(f'\n{colors.white}[{colors.green}+{colors.white}] Update complete. Re-run octosuite.{colors.reset}')
|
exit(f'{white}[{green}+{white}] Updated successfully. Re-run octosuite.{reset}')
|
||||||
|
|
||||||
|
|
||||||
|
def easter_egg(self):
|
||||||
|
print(f'\n{white}[{green}*{white}] Downloading. Please wait...{reset}')
|
||||||
|
file = requests.get('https://drive.google.com/uc?export=download&id=1IRu4kWSuNpYWH8hZkqQ8mLnv4sSDu-GN')
|
||||||
|
with open('EasterEgg.zip','wb') as f:
|
||||||
|
f.write(file.content)
|
||||||
|
|
||||||
|
exit(f'{white}[{green}+{white}] Downloaded (EasterEgg.zip).\n{white}[{green}!{white}] The password is: {green}horus{white}\n[{green}!{white}] Happy hunting! :).{reset}')
|
||||||
|
|
||||||
|
|
||||||
|
# Show changelog
|
||||||
|
def changelog(self):
|
||||||
|
# lol yes the changelog is hard coded
|
||||||
|
changelog_text = '''
|
||||||
|
v1.5.1-beta CHANGELOG:
|
||||||
|
|
||||||
|
• First pypi package release
|
||||||
|
• Termux users will now have to manually create the .logs folder
|
||||||
|
• Changed logs date/time format
|
||||||
|
• Removed 1 internal dependency
|
||||||
|
• There's an easter egg somewhere in here ;) (use the command 'ilinso')
|
||||||
|
'''
|
||||||
|
return changelog_text
|
||||||
|
|
||||||
|
|
||||||
# Author info
|
# Author info
|
||||||
def author(self):
|
def author(self):
|
||||||
print(f'\n{colors.white}Richard Mwewa (Ritchie){colors.reset}')
|
print(f'\n{white}Richard Mwewa (Ritchie){reset}')
|
||||||
for key,value in self.author_dict.items():
|
for key,value in self.author_dict.items():
|
||||||
print(f'{colors.white}├─ {key}: {colors.green}{value}{colors.reset}')
|
print(f'{white}├─ {key}: {green}{value}{reset}')
|
||||||
|
|
||||||
|
|
||||||
def help(self):
|
def help(self):
|
||||||
help = '''
|
help = f'''
|
||||||
|
|
||||||
usage:
|
help:
|
||||||
orginfo --> Get target organization info
|
|
||||||
userinfo --> Get target user profile info
|
{white}Command Descritption
|
||||||
repoinfo --> Get target repository info
|
------------ ---------------------------------------------------------
|
||||||
pathcontents --> Get contents of a specified path from a target repository
|
{green}orginfo{white} --> Get target organization info{reset}
|
||||||
orgrepos --> Get a list of repositories owned by a target organization
|
{green}userinfo{white} --> Get target user profile info{reset}
|
||||||
userrepos --> Get a list of repositories owned by a target user
|
{green}repoinfo{white} --> Get target repository info{reset}
|
||||||
usergists --> Get a list of gists owned by a target user
|
{green}pathcontents{white} --> Get contents of a specified path from a target repository{reset}
|
||||||
userfollowers --> Get a list of the target's followers
|
{green}orgrepos{white} --> Get a list of repositories owned by a target organization{reset}
|
||||||
userfollowing --> Check whether or not User[A] follows User[B]
|
{green}userrepos{white} --> Get a list of repositories owned by a target user{reset}
|
||||||
usersearch --> Search user(s)
|
{green}usergists{white} --> Get a list of gists owned by a target user{reset}
|
||||||
reposearch --> Search repositor[y][ies]
|
{green}userfollowers{white} --> Get a list of the target's followers{reset}
|
||||||
topicsearch --> Search topic(s)
|
{green}userfollowing{white} --> Check whether or not User[A] follows User[B]{reset}
|
||||||
issuesearch --> Search issue(s)
|
{green}usersearch{white} --> Search user(s){reset}
|
||||||
commitsearch --> Search commit(s)
|
{green}reposearch{white} --> Search repositor[y][ies]{reset}
|
||||||
update --> Check for/download update(s)
|
{green}topicsearch{white} --> Search topic(s){reset}
|
||||||
author --> Show author info
|
{green}issuesearch{white} --> Search issue(s){reset}
|
||||||
help --> Show usage/help
|
{green}commitsearch{white} --> Search commit(s){reset}
|
||||||
exit --> Exit session
|
{green}update{white} --> Update octosuite{reset}
|
||||||
|
{green}changelog{white} --> Show changelog{reset}
|
||||||
|
{green}author{white} --> Show author info{reset}
|
||||||
|
{green}help{white} --> Show usage/help{reset}
|
||||||
|
{green}exit{white} --> Exit session{reset}
|
||||||
|
{white}------------ ---------------------------------------------------------{reset}
|
||||||
'''
|
'''
|
||||||
return help
|
return help
|
||||||
|
|
||||||
|
|
||||||
# Set to automatically monitor and log network and user activity to .log folder
|
if os.path.exists('.logs'):
|
||||||
logging.basicConfig(filename=f'.logs/{datetime.now()}.log',format='[%(asctime)s] %(message)s',level=logging.DEBUG)
|
pass
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Creating the .logs directory
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
subprocess.run(['mkdir','.logs'])
|
||||||
|
else:
|
||||||
|
subprocess.run(['sudo','mkdir','.logs'],shell=False)
|
||||||
|
|
||||||
|
# Set to automatically monitor and log network and user activity into the .logs folder
|
||||||
|
logging.basicConfig(filename=f'.logs/{datetime.now()}.log',format='%(asctime)s %(message)s',datefmt='%Y-%m-%d %H:%M:%S',level=logging.DEBUG)
|
||||||
|
|||||||
Reference in New Issue
Block a user