Compare commits

...

221 Commits
2.2.1 ... 3.1.1

Author SHA1 Message Date
Richard Mwewa
342a54caf1 Update config.py 2023-08-01 02:33:13 +02:00
Richard Mwewa
1c8583132b Merge pull request #18 from bellingcat/dev
Update octosuite.py
2023-06-05 16:58:10 +02:00
Richard Mwewa
61c0b12d8b Update octosuite.py 2023-05-22 14:55:02 +02:00
Richard Mwewa
9d88b66005 Merge pull request #17 from bellingcat/dev
Dev
2023-04-21 18:53:45 +02:00
Richard Mwewa
d1e9932967 Update octosuite.py
Added f-string to the Organisation profile Tree.
2023-04-21 18:42:53 +02:00
Richard Mwewa
595dcc5aac Update pyproject.toml
Added line `[tool.setuptools]`. Fixes error that might be returned during compilation if there's more than one directory in the project's root directory:

error: Multiple top-level packages discovered in a flat-layout
2023-04-16 01:12:47 +02:00
Richard Mwewa
6a535ae856 Created a setup_readline function for the code used to setup readline. The function has been moved to config.py, and will be called from main.py 2023-04-12 16:17:51 +02:00
Richard Mwewa
61188fe29e Update octosuite.py
Using subprocess.call() instead of os.system()
2023-04-12 16:00:48 +02:00
Richard Mwewa
cd6155b553 Update octosuite.py
Using subprocess.call() to list directories instead of os.system()
2023-04-12 15:52:50 +02:00
Richard Mwewa
f064f80e47 Delete images directory 2023-03-07 18:38:43 +02:00
Richard Mwewa
dae2226905 Delete images directory 2023-03-07 01:45:15 +02:00
Richard Mwewa
2a92723dc8 Delete setup.py 2023-03-01 23:25:42 +02:00
Richard Mwewa
af975a4e7a Update README.md 2023-02-25 03:09:50 +02:00
Richard Mwewa
4f96419fbd Update octosuite.py 2023-02-25 03:04:01 +02:00
Richard Mwewa
774c8d19a8 Update octosuite 2023-02-25 02:59:46 +02:00
Richard Mwewa
04f3bd89cf Update pyproject.toml 2023-02-24 03:29:50 +02:00
Richard Mwewa
3fbb8d8cbe Update pyproject.toml 2023-02-24 03:03:00 +02:00
Richard Mwewa
e836413719 Update pyproject.toml 2023-02-24 02:40:31 +02:00
Richard Mwewa
2ba4438f64 Update pyproject.toml 2023-02-23 01:32:37 +02:00
Richard Mwewa
6c76b8fb39 Update pyproject.toml 2023-02-22 21:49:52 +02:00
Richard Mwewa
803e3b8ebd Create pyproject.toml 2023-02-22 16:54:30 +02:00
Richard Mwewa
6f29f633ea Update octosuite.py 2023-02-22 16:53:58 +02:00
Richard Mwewa
a9c62ebf36 Merge pull request #14 from bellingcat/dev
Dev
2023-02-22 16:30:04 +02:00
Richard Mwewa
73bdc542fa Update banner.py 2023-02-22 16:29:05 +02:00
Richard Mwewa
386e77f375 Update setup.py 2023-02-22 16:28:32 +02:00
Richard Mwewa
033e758e9e Update octosuite.py 2023-02-22 16:27:56 +02:00
Richard Mwewa
796e8e943c Update octosuite.py 2023-02-22 16:20:26 +02:00
Richard Mwewa
3125c45efb Update octosuite.py 2023-02-22 16:13:07 +02:00
Richard Mwewa
01d6115540 Update octosuite.py 2023-02-22 16:05:20 +02:00
Richard Mwewa
a7da4f442d Update config.py 2023-02-22 16:01:42 +02:00
Richard Mwewa
f967134210 Merge pull request #13 from Weltolk/patch-1
bug fix
2023-02-22 15:46:41 +02:00
Weltolk
47b28b45e0 Merge branch 'bellingcat:master' into patch-1 2023-02-22 20:10:21 +08:00
Richard Mwewa
ca5245e0db Update README.md 2023-02-22 14:03:17 +02:00
Weltolk
d2c7ba7cd9 bug fix 2023-02-22 19:11:45 +08:00
Richard Mwewa
619ef8cf9f Update 2023-02-03 17:54:37 +02:00
Richard Mwewa
8364053f97 Update README.md 2023-01-26 21:33:29 +02:00
Richard Mwewa
1f288d503f Update octosuite.py 2023-01-25 23:00:05 +02:00
Richard Mwewa
57911bd68f Update octosuite.py 2023-01-25 22:50:19 +02:00
Richard Mwewa
264048e4bf Update README.md 2023-01-25 14:38:34 +02:00
Richard Mwewa
671fbdcaa4 Update README.md 2023-01-25 14:36:45 +02:00
Richard Mwewa
5fc5af4157 Update octosuite.py 2023-01-25 14:29:13 +02:00
Richard Mwewa
8bc799c829 Update README.md 2023-01-25 14:28:14 +02:00
Richard Mwewa
85cadefd50 v3.1.0 2023-01-25 14:11:25 +02:00
Richard Mwewa
646ea3cb51 Update README.md 2023-01-23 03:08:49 +02:00
Richard Mwewa
3e18a3301a Merge pull request from #9
fix: bad indentation leading to reference before assignment error #9
2023-01-22 17:02:39 +02:00
Richard Mwewa
d4b595d79e Merge pull request from #9
fix: bad indentation leading to reference before assignment error #9
2023-01-22 17:01:34 +02:00
Richard Mwewa
0f247d1dd8 Merge pull request from issue #9
fix: bad identation leading to reference before assigment error #9
2023-01-22 16:55:55 +02:00
Richard Mwewa
1b2c441237 Merge pull request #9 from albertollamaso/fix-var-assigment
fix: bad identation leading to `reference before assigment` error
2023-01-22 16:50:36 +02:00
albertollamaso
2723c2f8dd fix: bad identation leading to reference before assigment error 2023-01-22 13:59:26 +01:00
Richard Mwewa
7576fa64a1 Update setup.py 2023-01-22 03:17:01 +02:00
Richard Mwewa
79a97a7883 Update setup.py 2023-01-22 02:48:11 +02:00
Richard Mwewa
ac6ebc6d72 Update octosuite.py 2023-01-22 02:45:05 +02:00
Richard Mwewa
a12210cfa2 Fixed bug in octosuite.py 2023-01-22 01:17:50 +02:00
Richard Mwewa
47e0b4c64a Update banner.py 2023-01-16 21:02:30 +02:00
Richard Mwewa
c4847773a0 Update setup.py 2023-01-16 21:01:19 +02:00
Richard Mwewa
832e887302 Update main.py 2023-01-16 21:00:46 +02:00
Richard Mwewa
8487898f93 Merge pull request #8 from bellingcat/dev
Update octosuite.py
2023-01-02 22:32:13 +02:00
Richard Mwewa
4d8b7394f0 Update README.md 2023-01-02 00:18:47 +02:00
Richard Mwewa
e925c9cb8a Update README.md 2023-01-02 00:07:39 +02:00
Richard Mwewa
dd2edfd204 Update octosuite.py 2023-01-01 03:12:57 +02:00
Richard Mwewa
13efce4f9c Update octosuite.py 2022-12-31 23:43:28 +02:00
Richard Mwewa
928ba6580f Update octosuite.py 2022-12-31 23:42:21 +02:00
Richard Mwewa
457c2a5472 Update config.py 2022-12-31 21:17:22 +02:00
Richard Mwewa
c6c037247f Merge pull request #7 from bellingcat/dev
Dev
2022-12-31 21:16:02 +02:00
Richard Mwewa
f84fcf0d35 Merge branch 'master' into dev 2022-12-31 21:01:43 +02:00
Richard Mwewa
8424c94bec Update Dockerfile 2022-12-31 14:56:16 +02:00
Richard Mwewa
a14b356b18 Update config.py 2022-12-31 14:52:02 +02:00
Richard Mwewa
f60f088f05 Update log_roller.py 2022-12-31 14:50:37 +02:00
Richard Mwewa
c2a5dc89ea Update main.py 2022-12-31 14:49:26 +02:00
Richard Mwewa
6a7b61b1f2 Update octosuite.py 2022-12-31 14:47:48 +02:00
Richard Mwewa
4427f30f77 Update config.py 2022-12-27 19:12:14 +02:00
Richard Mwewa
9982727de1 Update config.py 2022-12-25 03:27:55 +02:00
Richard Mwewa
866621db18 Update octosuite.py 2022-12-25 03:25:43 +02:00
Richard Mwewa
48b86cb2d0 Update octosuite.py 2022-12-25 03:12:12 +02:00
Richard Mwewa
96b10f0bf9 Update main.py 2022-12-25 03:09:29 +02:00
Richard Mwewa
53ccc9899b Update main.py 2022-12-25 03:02:42 +02:00
Richard Mwewa
bb82427abe Update csv_loggers.py 2022-12-25 02:58:05 +02:00
Richard Mwewa
ee4af7d266 Update octosuite.py 2022-12-25 02:51:56 +02:00
Richard Mwewa
3bd6af4f28 Update message_prefixes.py 2022-12-25 02:50:59 +02:00
Richard Mwewa
7531aa4f02 Update main.py 2022-12-25 02:50:36 +02:00
Richard Mwewa
f9d56c51a0 Update helper.py 2022-12-25 02:49:52 +02:00
Richard Mwewa
5bff3ccc12 Update csv_loggers.py 2022-12-25 02:49:07 +02:00
Richard Mwewa
272fcc36ed Update config.py 2022-12-25 02:48:39 +02:00
Richard Mwewa
64c1063ea5 Update banner.py 2022-12-25 02:48:15 +02:00
Richard Mwewa
4c7109f4f0 Update log_roller.py 2022-12-25 02:47:48 +02:00
Richard Mwewa
d907167713 Update csv_loggers.py 2022-12-25 02:46:18 +02:00
Richard Mwewa
9eec2e323d Update log_roller.py 2022-12-25 02:33:43 +02:00
Richard Mwewa
ead76074f5 Update message_prefixes.py 2022-12-25 02:33:22 +02:00
Richard Mwewa
e87560939f Update main.py 2022-12-25 02:32:28 +02:00
Richard Mwewa
3f1191758b Update octosuite.py 2022-12-25 02:31:24 +02:00
Richard Mwewa
34c7cd3918 Update message_prefixes.py 2022-12-24 12:46:47 +02:00
Richard Mwewa
52c4101a7a Update README.md 2022-12-24 12:45:55 +02:00
Richard Mwewa
0677b901f7 Update config.py 2022-12-23 19:41:32 +02:00
Richard Mwewa
49215fd03e Update main.py 2022-12-23 19:36:29 +02:00
Richard Mwewa
8fc14d3ec4 Update main.py 2022-12-23 19:34:44 +02:00
Richard Mwewa
3da2b91fb2 Update config.py 2022-12-23 19:33:59 +02:00
Richard Mwewa
b6908a19f4 Update octosuite.py 2022-12-23 19:33:26 +02:00
Richard Mwewa
4db8300e2c Update log_roller.py 2022-12-23 19:31:43 +02:00
Richard Mwewa
07ca8c486c Update octosuite.py 2022-12-23 19:30:11 +02:00
Richard Mwewa
9473b0278d Update config.py 2022-12-23 18:14:21 +02:00
Richard Mwewa
4113c62d09 Update config.py 2022-12-23 18:10:43 +02:00
Richard Mwewa
f235bc1186 Update main.py 2022-12-23 17:35:10 +02:00
Richard Mwewa
4d0e7beea7 Update octosuite.py 2022-12-23 17:21:53 +02:00
Richard Mwewa
7b1fd3addc Update helper.py 2022-12-23 17:17:18 +02:00
Richard Mwewa
3968f53e98 Update octosuite.py 2022-12-23 16:59:35 +02:00
Richard Mwewa
bd9c1f210f Update helper.py 2022-12-23 16:53:21 +02:00
Richard Mwewa
0518f33571 Update main.py 2022-12-23 16:52:46 +02:00
Richard Mwewa
c783a717a0 Update octosuite.py 2022-12-23 16:29:17 +02:00
Richard Mwewa
ea3b8bcd71 Update octosuite.py 2022-12-23 16:08:46 +02:00
Richard Mwewa
cdf04fe443 Update octosuite.py 2022-12-23 15:10:01 +02:00
Richard Mwewa
f3b90f2e6d Update octosuite.py 2022-12-23 14:07:12 +02:00
Richard Mwewa
bf77bc4dfe Update config.py 2022-12-23 13:59:45 +02:00
Richard Mwewa
157cb68142 Update message_prefixes.py 2022-12-23 12:18:37 +02:00
Richard Mwewa
53433c119b Update helper.py 2022-12-23 12:18:17 +02:00
Richard Mwewa
5d41e07bc2 Update main.py 2022-12-23 12:17:48 +02:00
Richard Mwewa
331c81ac46 Update and rename banners.py to banner.py 2022-12-23 12:16:39 +02:00
Richard Mwewa
e3c151e2d3 Update and rename colors.py to config.py 2022-12-23 12:03:53 +02:00
Richard Mwewa
a89596efc2 Update octosuite.py 2022-12-12 15:00:56 +02:00
Richard Mwewa
283a92fa84 Update octosuite.py 2022-12-12 14:57:36 +02:00
Richard Mwewa
beb8d561f8 Update main.py 2022-12-09 23:40:18 +02:00
Richard Mwewa
b68842df1c Update octosuite.py 2022-12-09 23:38:36 +02:00
Richard Mwewa
dd7fcc455d Update Octosuite 2022-12-05 21:03:15 +02:00
Richard Mwewa
b3ae15a062 Update Dockerfile 2022-12-02 23:15:26 +02:00
Richard Mwewa
4c8d3626b3 Update octosuite.py 2022-12-01 20:12:52 +02:00
Richard Mwewa
1f86ad4034 Update octosuite.py 2022-12-01 19:36:59 +02:00
Richard Mwewa
e151f81d76 Update Dockerfile
Added docker commands to build Octosuite's wheel file with the python build library
2022-12-01 03:18:36 +02:00
Richard Mwewa
a69fbf33d9 Update Dockerfile 2022-12-01 03:13:33 +02:00
Richard Mwewa
227fcd0482 Update octosuite.py 2022-12-01 03:10:42 +02:00
Richard Mwewa
8d04112d32 Update octosuite.py 2022-12-01 03:08:14 +02:00
Richard Mwewa
66373fd96e Update Octosuite 2022-11-30 21:49:56 +02:00
Richard Mwewa
c4f1940bb6 Update octosuite.py 2022-11-30 21:19:34 +02:00
Richard Mwewa
f79813ed45 Update octosuite.py 2022-11-30 02:55:17 +02:00
Richard Mwewa
ffd162d881 Update main.py 2022-11-30 02:42:53 +02:00
Richard Mwewa
558715fdab Update octosuite 2022-11-30 02:37:07 +02:00
Richard Mwewa
9984c71a57 Update csv_loggers.py 2022-11-25 03:38:09 +02:00
Richard Mwewa
bb2efb903b Update banners.py 2022-11-25 03:32:56 +02:00
Richard Mwewa
defe1b1159 Update banners.py 2022-11-25 03:32:03 +02:00
Richard Mwewa
347acea797 Update banners.py 2022-11-25 03:29:19 +02:00
Richard Mwewa
46937abb7e Update octosuite.py 2022-11-25 03:26:14 +02:00
Richard Mwewa
2963db3608 Update helper.py 2022-11-25 03:23:07 +02:00
Richard Mwewa
92d4f3f9f2 Update colors.py 2022-11-25 03:18:29 +02:00
Richard Mwewa
02df05df39 Update colors.py 2022-11-25 03:16:30 +02:00
Richard Mwewa
549f1940f9 Merge pull request #6 from bellingcat/dev
Dev
2022-11-25 02:58:30 +02:00
Richard Mwewa
e936525f81 Merge branch 'master' into dev 2022-11-25 02:53:10 +02:00
Richard Mwewa
29eb2bde95 Update octosuite.py 2022-11-25 02:52:22 +02:00
Richard Mwewa
d27d9b9168 Update and rename sign_vars.py to message_prefixes.py 2022-11-25 02:50:59 +02:00
Richard Mwewa
a6ca1e3c0c Update main.py 2022-11-25 02:50:09 +02:00
Richard Mwewa
5bf7ef3f39 Update colors.py 2022-11-25 02:48:52 +02:00
Richard Mwewa
ae73fdffde Update banners.py 2022-11-25 02:48:23 +02:00
Richard Mwewa
7c8fea02e6 Update setup.py 2022-11-25 02:46:24 +02:00
Richard Mwewa
40fffcab73 Update colors.py 2022-11-25 02:37:18 +02:00
Richard Mwewa
9a6127d6bc Update colors.py 2022-11-25 02:35:37 +02:00
Richard Mwewa
eb724f629f Update banners.py 2022-11-25 02:33:59 +02:00
Richard Mwewa
6d04b990db Update setup.py 2022-11-25 02:31:11 +02:00
Richard Mwewa
2537bcbab8 Update message_prefixes.py 2022-11-25 02:29:04 +02:00
Richard Mwewa
bb6c5a09e9 Update octosuite.py 2022-11-25 02:26:24 +02:00
Richard Mwewa
083d3e9f71 Update octosuite.py 2022-11-25 02:16:44 +02:00
Richard Mwewa
497c855648 Update main.py 2022-11-25 02:08:40 +02:00
Richard Mwewa
c2641b3134 Update main.py 2022-11-25 02:07:40 +02:00
Richard Mwewa
a108b4784e Update main.py 2022-11-25 02:05:44 +02:00
Richard Mwewa
597ad07490 Update octosuite.py 2022-11-25 02:04:54 +02:00
Richard Mwewa
94c1e0a737 Update and rename sign_vars.py to message_prefixes.py 2022-11-25 01:59:04 +02:00
Richard Mwewa
6e83bcf367 Update log_roller.py 2022-11-25 01:58:13 +02:00
Richard Mwewa
a57f5d47e2 Update csv_loggers.py 2022-11-25 01:55:29 +02:00
Richard Mwewa
3fa3e7a182 Update banners.py 2022-11-25 01:54:25 +02:00
Richard Mwewa
d42b7af59f Update colors.py 2022-11-25 01:53:51 +02:00
Richard Mwewa
8d337c621c Update setup.py 2022-11-25 01:52:26 +02:00
Richard Mwewa
5842a13975 Update setup.py 2022-11-25 01:51:30 +02:00
Richard Mwewa
e739f78eb9 Update main.py 2022-11-25 01:49:46 +02:00
Richard Mwewa
26cf25bf91 Update log_roller.py 2022-11-25 01:48:55 +02:00
Richard Mwewa
ad6959d1b9 Update csv_loggers.py 2022-11-25 01:47:53 +02:00
Richard Mwewa
d7af8602fe Update octosuite.py 2022-11-25 01:46:42 +02:00
Richard Mwewa
29d40ec27e Update octosuite.py 2022-11-25 01:40:00 +02:00
Richard Mwewa
6a0953401b Update banners.py 2022-11-25 01:38:52 +02:00
Richard Mwewa
e87e5c64c8 Update colors.py 2022-11-25 01:31:05 +02:00
Richard Mwewa
c53ab2a00b Update colors.py 2022-11-25 01:30:48 +02:00
Richard Mwewa
b30ad16719 Update colors.py 2022-11-25 01:30:27 +02:00
Richard Mwewa
cfa032f7cb Update colors.py 2022-11-24 23:29:51 +02:00
Richard Mwewa
87f287bfb9 Update colors.py 2022-11-24 23:25:41 +02:00
Richard Mwewa
ab70a10d19 Update csv_loggers.py 2022-11-24 23:10:25 +02:00
Richard Mwewa
02e19baa93 Update csv_loggers.py 2022-11-24 22:40:17 +02:00
Richard Mwewa
0b76846968 Update csv_loggers.py 2022-11-24 22:39:44 +02:00
Richard Mwewa
9614785455 Update colors.py 2022-11-24 22:22:31 +02:00
Richard Mwewa
6ae34437a4 Update banners.py 2022-11-24 22:10:49 +02:00
Richard Mwewa
5a1b5378ee Update setup.py 2022-11-24 22:09:11 +02:00
Richard Mwewa
64d1b6bf38 Update helper.py 2022-11-23 17:32:37 +02:00
Richard Mwewa
09fffdf192 Update helper.py 2022-11-21 18:26:31 +02:00
Richard Mwewa
8e4520b6d2 Update helper.py 2022-11-21 17:43:35 +02:00
Richard Mwewa
420186bec4 Update helper.py 2022-11-20 17:55:10 +02:00
Richard Mwewa
758676ac88 Update octosuite.py 2022-11-20 16:12:04 +02:00
Richard Mwewa
310b1fb702 Update octosuite.py 2022-11-20 16:11:08 +02:00
Richard Mwewa
6822806a77 Renamed banner.py to banners.py 2022-11-20 16:08:36 +02:00
Richard Mwewa
4eddd20480 Update octosuite.py 2022-11-20 15:29:43 +02:00
Richard Mwewa
95dcfbea6e Update helper.py 2022-11-20 15:27:01 +02:00
Richard Mwewa
258be0a2d7 Update octosuite.py 2022-11-20 15:24:14 +02:00
Richard Mwewa
3b329d039a Update octosuite.py 2022-11-20 15:16:00 +02:00
Richard Mwewa
fec88ac343 Update banner.py 2022-11-20 15:14:29 +02:00
Richard Mwewa
272cd49d0e Update octosuite.py 2022-11-20 15:09:17 +02:00
Richard Mwewa
cea07f187a Merge pull request #4 from 0xbharath/master
Added Dockerfile
2022-10-24 17:07:05 +02:00
Bharath
0f96785123 Added Dockerfile 2022-10-24 17:52:55 +05:30
Richard Mwewa
000eb80fbc Update setup.py 2022-10-21 21:55:32 +02:00
Richard Mwewa
e4f1e2928a Update octosuite.py 2022-10-21 21:54:02 +02:00
Richard Mwewa
73fa406e82 Update setup.py 2022-10-21 01:33:50 +02:00
Richard Mwewa
e99e0c317e Update banner.py 2022-10-21 01:30:31 +02:00
Richard Mwewa
7d2eada3f9 Update helper.py 2022-10-21 01:29:52 +02:00
Richard Mwewa
f706a08859 Create octosuite.py 2022-10-21 01:29:04 +02:00
Richard Mwewa
b3ccb713e1 Update main.py
All code from main.py has been moved to octosuite.py
2022-10-21 01:27:45 +02:00
Richard Mwewa
0bb330d771 Update README.md 2022-10-21 01:26:06 +02:00
Richard Mwewa
df339d33df Update README.md 2022-10-21 01:06:44 +02:00
Richard Mwewa
c296f09e0e Fixed issues that affected Windows machines
[Errno 22] Invalid argument: This error occurred in Windows machines on session start up, the datetime format used a symbol that is reserved by the windows system, thus breaking octosuite whenever it attempted to log an activity to a file.

[Error 2] The system cannot find the file specified: This error occurred whenever the clear command was entered, since the command was being passed through subprocess with shell set to False.
2022-09-14 18:34:04 +02:00
Richard Mwewa
04ea880276 Update README.md 2022-09-14 18:05:42 +02:00
Richard Mwewa
eef44716d5 Update setup.py 2022-09-01 11:53:35 +02:00
Richard Mwewa
8eea84e546 Update README.md 2022-08-26 13:04:12 +02:00
Richard Mwewa
acd65e7919 Update README.md 2022-08-26 13:03:26 +02:00
Richard Mwewa
4a7b199929 Add files via upload 2022-08-26 12:40:37 +02:00
Richard Mwewa
2723e75735 Update banner.py 2022-08-26 12:36:29 +02:00
Richard Mwewa
0365616478 Update main.py 2022-08-26 12:35:49 +02:00
Richard Mwewa
befd61eea0 Update setup.py 2022-08-26 12:30:18 +02:00
Richard Mwewa
daa426d73b Add files via upload 2022-08-20 16:35:06 +02:00
Richard Mwewa
22df1eae73 Add files via upload 2022-08-20 15:26:35 +02:00
Richard Mwewa
51c1efbcec Update README.md 2022-08-17 11:20:09 +02:00
16 changed files with 2126 additions and 1674 deletions

11
Dockerfile Normal file
View File

@@ -0,0 +1,11 @@
# syntax=docker/dockerfile:1
FROM python:latest
WORKDIR /app
COPY . .
RUN pip install --upgrade pip && pip install build && python -m build && pip install dist/*.whl
ENTRYPOINT ["octosuite"]

View File

@@ -1,23 +1,29 @@
![logo](https://user-images.githubusercontent.com/74001397/175805580-fffc96d4-e0ef-48bb-a55c-80b2da3e714d.png) ![logo](https://user-images.githubusercontent.com/74001397/175805580-fffc96d4-e0ef-48bb-a55c-80b2da3e714d.png)
[![Upload Python Package](https://github.com/rly0nheart/octosuite/actions/workflows/python-publish.yml/badge.svg)](https://github.com/rly0nheart/octosuite/actions/workflows/python-publish.yml) A framework for gathering open-source intelligence on GitHub users, repositories and organisations
[![CodeQL](https://github.com/rly0nheart/octosuite/actions/workflows/codeql.yml/badge.svg)](https://github.com/rly0nheart/octosuite/actions/workflows/codeql.yml)
![GitHub](https://img.shields.io/github/license/rly0nheart/octosuite?style=flat) [![Upload Python Package](https://github.com/bellingcat/octosuite/actions/workflows/python-publish.yml/badge.svg)](https://github.com/bellingcat/octosuite/actions/workflows/python-publish.yml)
[![CodeQL](https://github.com/bellingcat/octosuite/actions/workflows/codeql.yml/badge.svg)](https://github.com/bellingcat/octosuite/actions/workflows/codeql.yml)
![GitHub](https://img.shields.io/github/license/bellingcat/octosuite?style=flat)
![PyPI](https://img.shields.io/pypi/v/octosuite?style=flat&logo=pypi) ![PyPI](https://img.shields.io/pypi/v/octosuite?style=flat&logo=pypi)
![PyPI - Downloads](https://img.shields.io/pypi/dw/octosuite?style=flat&logo=pypi) ![PyPI - Downloads](https://img.shields.io/pypi/dw/octosuite?style=flat&logo=pypi)
![PyPI - Status](https://img.shields.io/pypi/status/octosuite?style=flat&logo=pypi) ![PyPI - Status](https://img.shields.io/pypi/status/octosuite?style=flat&logo=pypi)
![GitHub repo size](https://img.shields.io/github/repo-size/rly0nheart/octosuite?style=flat&logo=github) ![GitHub repo size](https://img.shields.io/github/repo-size/bellingcat/octosuite?style=flat&logo=github)
> *Simply gather OSINT on Github users & organizations like a God🔥*
## Wiki ![2023-01-23_01-01](https://user-images.githubusercontent.com/74001397/213950701-44b3f98b-89e1-443a-abb5-1be8969b611f.png "Octosuite about")
[Refer to the Wiki](https://github.com/rly0nheart/octosuite/wiki) for installation instructions, in addition to all other documentation.
## Features
- [x] Fetches an organization's profile information ![Screen Shot 2023-01-26 at 9 27 22 PM](https://user-images.githubusercontent.com/74001397/214932206-40ec42ba-4fe8-4115-b2dd-52c4d7be9b5c.png)
# Wiki
[Refer to the Wiki](https://github.com/bellingcat/octosuite/wiki) for installation instructions, in addition to all other documentation.
# Features
- [x] Fetches an organisation's profile information
- [x] Fetches an oganization's events - [x] Fetches an oganization's events
- [x] Returns an organization's repositories - [x] Returns an organisation's repositories
- [x] Returns an organization's public members - [x] Returns an organisation's public members
- [x] Fetches a repository's information - [x] Fetches a repository's information
- [x] Returns a repository's contributors - [x] Returns a repository's contributors
- [x] Returns a repository's languages - [x] Returns a repository's languages
@@ -27,35 +33,43 @@
- [x] Returns a list of files in a specified path of a repository - [x] Returns a list of files in a specified path of a repository
- [x] Fetches a user's profile information - [x] Fetches a user's profile information
- [x] Returns a user's gists - [x] Returns a user's gists
- [x] Returns organizations that a user owns/belongs to - [x] Returns organisations that a user owns/belongs to
- [x] Fetches a user's events - [x] Fetches a user's events
- [x] Fetches a list of users followed by the target - [x] Fetches a list of users followed by the target
- [x] Fetches a user's followers - [x] Fetches a user's followers
- [x] Checks if user A follows user B - [x] Checks if user A follows user B
- [x] Checks if user is a public member of an organizations - [x] Checks if user is a public member of an organisations
- [x] Returns a user's subscriptions
- [x] Gets a user's subscriptions - [x] Gets a user's subscriptions
- [x] Gets a user's events
- [x] Searches users - [x] Searches users
- [x] Searches repositories - [x] Searches repositories
- [x] Searches topics - [x] Searches topics
- [x] Searches issues - [x] Searches issues
- [x] Searches commits - [x] Searches commits
- [x] Automatically logs network activity (.logs folder) - [x] Automatically logs network/user activity (.logs folder)
- [x] User can view, read and delete logs - [x] User can manage logs (view, read, delete)
- [x] ...And more - [x] Results can be saved to a .csv file (varies)
- [x] User can manage csv files (view, read, delete)
- [x] All the above can be used with command-line arguments (PyPI Package only)
- [x] And more...
# TODO
- [ ] Rewrite the GUI in Visual Basic .NET (in progress)
## Note ## Note
> octosuite automatically logs network and minor user activity of each session. The logs are saved by date and time in the .logs folder > Octosuite automatically logs network and user activity of each session, the logs are saved by date and time in the .logs folder
>> Although octosuite was developed to work on Mac, Windows, or any Linux Distribution, it has only been tested on Termux and Kali Linux
>>> If you believe octosuite can be better, feel free to open a pull request with your improvements✌🏾🙂
## License
# License
![license](https://user-images.githubusercontent.com/74001397/137917929-2f2cdb0c-4d1d-4e4b-9f0d-e01589e027b5.png) ![license](https://user-images.githubusercontent.com/74001397/137917929-2f2cdb0c-4d1d-4e4b-9f0d-e01589e027b5.png)
## Donations # Credits
Love octosuite and would like to donate? You can buy me a coffee using the button below. * The code used for finding emails from usernames is taken from [Somdev Sangwan](https://github.com/s0md3v)'s [Zen](https://github.com/s0md3v/zen)
# Donations
If you like OctoSuite and would like to show support, you can Buy A Coffee for the developer using the button below
<a href="https://www.buymeacoffee.com/189381184" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a> <a href="https://www.buymeacoffee.com/189381184" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>
Your support is much appreciated!☕👌🏾😊 Your support will be much appreciated😊

View File

@@ -1 +0,0 @@

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -1,22 +1,23 @@
import getpass import getpass
from octosuite.colors import red, white, green, reset from octosuite.config import red, white, green, reset, Tree
'''
banner.py # banner.py
This file holds the program's banner logo and version tag # This file holds the program's banner and version tag
''' version_tag = "3.1.1"
version_tag = "2.2.1"
name_logo = f"""{white}
def banner():
banner_tree = Tree(getpass.getuser())
banner_tree.add(f"use {green}help{reset} command for usage")
banner_tree.add(f"commands are case insensitive\n")
return f"""
_______ __ _______ __ __ _______ __ _______ __ __
| |.----.| |_.-----.| __|.--.--.|__| |_.-----. | |.----.| |_.-----.| __|.--.--.|__| |_.-----.
| - || __|| _| _ ||__ || | || | _| -__| | - || __|| _| _ ||__ || | || | _| -__|
|_______||____||____|_____||_______||_____||__|____|_____| |_______||____||____|_____||_______||_____||__|____|_____|
v{version_tag} v{version_tag}
{white}— Advanced Github {red}OSINT{white} Framework {white}— Advanced Github {red}OSINT{white} Framework
""", banner_tree
.:{getpass.getuser()}:.
├─ use {green}help{reset}{white} command for usage
└╼ commands are case insensitive{reset}
"""

View File

@@ -1,43 +0,0 @@
import platform
from datetime import datetime
# This file is responsible for enabling/disabling colors in OctoSuite
# This file gets called first at start up before any other file gets called
# colors.py is the reason why users get to choose whether to enable/disable colors
system_info = [("Processor",platform.processor),
("Node", platform.node),
("Release", platform.release),
("Architecture", platform.architecture),
("Version", platform.version)]
banner = f"""
OCTOSUITE © 2022 Richard Mwewa
{datetime.now().strftime('%A %d %B %Y, %H:%M:%S%p')}
"""
print(banner)
print(f"\t{platform.system()}")
for key, value in system_info:
print(f"\t├─ {key}: {value()}")
print("\n")
while True:
try:
color_chooser = input(f"[ ? ] Welcome, would you like to enable colors for this session? (Y/n) ").lower()
if color_chooser == "y":
header_title = "bold white"
red = "[red]"
white = "[white]"
green = "[green]"
red_bold = "[white bold]"
white_bold = "[white bold]"
green_bold = "[green bold]"
reset = "[/]"
break
elif color_chooser == "n":
header_title = red = white = green = red_bold = white_bold = green_bold = reset = ""
break
else:
print(f"\n[ ! ] Your response '{color_chooser}' is invalid (expected y or n)")
except KeyboardInterrupt:
exit(f"[ ! ] Process interrupted with [Ctrl+C].")

224
octosuite/config.py Normal file
View File

@@ -0,0 +1,224 @@
import os
import psutil
import platform
import argparse
from rich.tree import Tree
from rich.text import Text
from rich.table import Table
from datetime import datetime
from rich import print as xprint
from rich.markdown import Markdown
from rich.prompt import Prompt, Confirm
def usage():
return """
Basic Usage
===========
Get User Profile Info
---------------------
octosuite --method user_profile --username <username>
Get User Repos
--------------
octosuite --method user_repos --username <username>
Get Organisation Profile Info
-----------------------------
octosuite --method org_profile --organisation <organisation_name>
Get Organi[sz]ation Repos
-----------------------------
octosuite --method org_repos --organisation <organisation_name>
Get Repo Profile Info
---------------------
octosuite --method repo_profile --username <username> --repository <repo_name>
Get Repo Forks
--------------
octosuite --method repo_forks --username <username> --repository <repo_name>
Searching
=========
Search Users
------------
octosuite --method users_search --query <query>
Search Issues
-------------
octosuite --method issues_search --query <query>
Search Commits
--------------
octosuite --method commits_search --query <query>
Search Topics
-------------
octosuite --method topics_search --query <query>
Search Repositories
-------------------
octosuite --method repos_search --query <query>
Log Management
==============
View logs
---------
octosuite --method view_logs
Read log
--------
octosuite --method read_log --log-file <log_file>
Delete log
----------
octosuite --method delete_log --log-file <log_file>
Clear logs
----------
octosuite --method clear_logs
CSV Management
==============
View CSV
---------
octosuite --method view_csv
Read CSV
--------
octosuite --method read_csv --csv-file <csv_file>
Delete CSV
----------
octosuite --method delete_csv --csv-file <csv_file>
Clear CSV's
-----------
octosuite --method clear_csv
"""
def create_parser():
parser = argparse.ArgumentParser(description='OCTOSUITE: Advanced GitHub osint framework — by Richard Mwewa | https://about.me/rly0nheart', usage=usage())
parser.add_argument('-m', '--method', help='method', choices=['user_email', 'user_profile', 'user_repos', 'user_gists', 'user_orgs', 'user_events',
'user_subscriptions', 'user_following', 'user_followers', 'user_follows',
'org_profile', 'org_repos', 'org_events', 'org_member',
'repo_profile', 'repo_contributors', 'repo_stargazers', 'repo_forks',
'repo_issues', 'repo_releases', 'repo_path_contents', 'users_search', 'issues_search',
'commits_search', 'topics_search', 'repos_search', 'view_logs', 'read_log', 'delete_log',
'clear_logs', 'view_csv', 'read_csv', 'delete_csv', 'clear_csv', 'about', 'author'])
parser.add_argument('-u', '--username', help='username')
parser.add_argument('-uB', '--username_b', help='username_B (used with user_follows)')
parser.add_argument('-o', '--organisation', '--organization', help='organisation name')
parser.add_argument('-r', '--repository', help='repository name')
parser.add_argument('-p', '--path_name', help='path name (used with repo_path_contents)')
parser.add_argument('-q', '--query', help='query (used with search methods)')
parser.add_argument('-l', '--limit', help='output limit (used with methods that return results in bulk) (default: %(default)s)', default=10)
parser.add_argument('-c', '--colors', '--colours', help='specify to run octosuite cli with colo[u]rs enabled', action='store_true')
parser.add_argument('--csv_file', help='csv file (used with csv management methods)')
parser.add_argument('--log_file', help='log file (used with logs management methods)')
parser.add_argument('--log-to-csv', help='log output to a csv file', action='store_true', dest='log_csv')
return parser
# Setup readline
def setup_readline():
if os.name == "nt":
try:
from pyreadline3 import Readline
except ImportError:
subprocess.run(['pip3', 'install', 'pyreadline3'], shell=False)
readline = Readline()
else:
import readline
def completer(text, state):
options = [i for i in commands if i.startswith(text)]
if state < len(options):
return options[state]
else:
return None
readline.parse_and_bind("tab: complete")
readline.set_completer(completer)
parser = create_parser()
args = parser.parse_args()
# This file is responsible for enabling/disabling colo[u]rs and configuring argparse in OctoSuite
# This file gets called first at start up before any other file
# config.py is the reason why users get to choose whether to enable/disable colo[u]rs, and call the program with command line arguments
# delete this file (I dare you), the entire program breaks
system_info = [("RAM", f"{str(round(psutil.virtual_memory().total / (1024.0 ** 3)))}GB"),
("Node", platform.node()),
("Release", platform.release()),
("Version", platform.version()),
("Processor", platform.processor()),
("Architecture", platform.architecture())]
first_banner = f"""
OCTOSUITE © 2023 Richard Mwewa
{datetime.now().strftime('%A %d %B %Y, %H:%M:%S%p')}
"""
if args.colors:
header_title = "bold white"
red = "[red]"
white = "[white]"
green = "[green]"
yellow = "[yellow]"
red_bold = "[white bold]"
white_bold = "[white bold]"
green_bold = "[green bold]"
reset = "[/]"
else:
print(first_banner)
system_tree = Tree(platform.system())
for system_key, system_value in system_info:
system_tree.add(f"{system_key}: {system_value}")
xprint(system_tree)
print("\n")
try:
color_chooser = Confirm.ask(f"Welcome, would you like to enable colo(u)rs for this session?")
if color_chooser:
header_title = "bold white"
red = "[red]"
white = "[white]"
green = "[green]"
yellow = "[yellow]"
red_bold = "[white bold]"
white_bold = "[white bold]"
green_bold = "[green bold]"
reset = "[/]"
else:
header_title = red = white = green = red_bold = white_bold = green_bold = reset = yellow = ""
except KeyboardInterrupt:
exit(f"[WARNING] Process interrupted with Ctrl+C.")

View File

@@ -1,447 +1,442 @@
import os
import csv import csv
import logging import logging
from rich import print as xprint from rich import print as xprint
from octosuite.sign_vars import SignVar from octosuite.log_roller import prompt_log_csv, logged_to_csv
from octosuite.log_roller import logRoller from octosuite.message_prefixes import PROMPT, WARNING, POSITIVE, NEGATIVE, INFO
from octosuite.colors import red, white, green, reset
'''
csvLogger
This class holds the methods for creating .csv files of each functionality in main
'''
class csvLogger:
# .csv for organization' profile
def logOrgProfile(response):
org_profile_fields = ['Profile photo', 'Name', 'Username', 'ID', 'Node ID', 'Email', 'About', 'Location', 'Blog', 'Followers', 'Following', 'Twitter handle', 'Gists', 'Repositories', 'Account type', 'Is verified?', 'Has organization projects?', 'Has repository projects?', 'Created at', 'Updated at']
org_profile_row = [response.json()['avatar_url'], response.json()['name'], response.json()['login'], response.json()['id'], response.json()['node_id'], response.json()['email'], response.json()['description'], response.json()['location'], response.json()['blog'], response.json()['followers'], response.json()['following'], response.json()['twitter_username'], response.json()['public_gists'], response.json()['public_repos'], response.json()['type'], response.json()['is_verified'], response.json()['has_organization_projects'], response.json()['has_repository_projects'], response.json()['created_at'], response.json()['updated_at']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{response.json()['name']}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(org_profile_fields)
writecsv.writerow(org_profile_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# Creating a .csv file of a user' profile # csv_loggers.py
def logUserProfile(response): # This file holds the functions for creating .csv files of each functionality in main
user_profile_fields = ['Profile photo', 'Name', 'Username', 'ID', 'Node ID', 'Bio', 'Blog', 'Location', 'Followers', 'Following', 'Twitter handle', 'Gists', 'Repositories', 'Organization', 'Is hireable?', 'Is site admin?', 'Joined at', 'Updated at'] def log_org_profile(response):
user_profile_row = [response.json()['avatar_url'], response.json()['name'], response.json()['login'], response.json()['id'], response.json()['node_id'], response.json()['bio'], response.json()['blog'], response.json()['location'], response.json()['followers'], response.json()['following'], response.json()['twitter_username'], response.json()['public_gists'], response.json()['public_repos'], response.json()['company'], response.json()['hireable'], response.json()['site_admin'], response.json()['created_at'], response.json()['updated_at']] org_profile_fields = ['Profile photo', 'Name', 'Username', 'ID', 'Node ID', 'Email', 'About', 'Location', 'Blog',
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower() 'Followers', 'Following', 'Twitter handle', 'Gists', 'Repositories', 'Account type',
if prompt == 'y': 'Is verified?', 'Has organisation projects?', 'Has repository projects?', 'Created at',
with open(f"output/{response.json()['login']}.csv", 'w',) as file: 'Updated at']
writecsv = csv.writer(file) org_profile_row = [response.json()['avatar_url'], response.json()['name'], response.json()['login'],
writecsv.writerow(user_profile_fields) response.json()['id'], response.json()['node_id'], response.json()['email'],
writecsv.writerow(user_profile_row) response.json()['description'], response.json()['location'], response.json()['blog'],
response.json()['followers'], response.json()['following'], response.json()['twitter_username'],
logging.info(logRoller.loggedToCsv.format(file.name)) response.json()['public_gists'], response.json()['public_repos'], response.json()['type'],
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}") response.json()['is_verified'], response.json()['has_organisation_projects'],
response.json()['has_repository_projects'], response.json()['created_at'],
else: response.json()['updated_at']]
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}") with open(os.path.join("output", f"{response.json()['name']}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(org_profile_fields)
write_csv.writerow(org_profile_row)
logging.info(logged_to_csv.format(file.name))
# create .csv for repository profile xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
def logRepoProfile(response):
repo_profile_fields = [ 'Name','ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility', 'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?', 'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?', 'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at']
repo_profile_row = [response.json()['name'], response.json()['id'], response.json()['description'], response.json()['forks'], response.json()['stargazers_count'], response.json()['watchers'], response.json()['license'], response.json()['default_branch'], response.json()['visibility'], response.json()['language'], response.json()['open_issues'], response.json()['topics'], response.json()['homepage'], response.json()['clone_url'], response.json()['ssh_url'], response.json()['fork'], response.json()['allow_forking'], response.json()['private'], response.json()['archived'], response.json()['is_template'], response.json()['has_wiki'], response.json()['has_pages'], response.json()['has_projects'], response.json()['has_issues'], response.json()['has_downloads'], response.json()['pushed_at'], response.json()['created_at'], response.json()['updated_at']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{response.json()['name']}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(repo_profile_fields)
writecsv.writerow(repo_profile_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# create .csv for repository path contents
def logRepoPathContents(content, repo_name):
path_content_fields = ['Filename', 'Size (bytes)', 'Type', 'Path', 'SHA', 'URL']
path_content_row = [content['name'], content['size'], content['type'], content['path'], content['sha'], content['html_url']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{content['name']}_content_from_{repo_name}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(path_content_fields)
writecsv.writerow(path_content_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# create .csv for repository stargazer # Creating a .csv file of a user' profile
def logRepoStargazers(stargazer, repo_name): def log_user_profile(response):
user_follower_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type', 'Is site admin?', 'URL'] user_profile_fields = ['Profile photo', 'Name', 'Username', 'ID', 'Node ID', 'Bio', 'Blog', 'Location', 'Followers',
user_follower_row = [stargazer['avatar_url'], stargazer['login'], stargazer['id'], stargazer['node_id'], stargazer['gravatar_id'], stargazer['type'], stargazer['site_admin'], stargazer['html_url']] 'Following', 'Twitter handle', 'Gists', 'Repositories', 'organisation', 'Is hireable?',
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower() 'Is site admin?', 'Joined at', 'Updated at']
if prompt == 'y': user_profile_row = [response.json()['avatar_url'], response.json()['name'], response.json()['login'],
with open(f"output/{stargazer['login']}_stargazer_of_{repo_name}.csv", 'w') as file: response.json()['id'], response.json()['node_id'], response.json()['bio'],
writecsv = csv.writer(file) response.json()['blog'], response.json()['location'], response.json()['followers'],
writecsv.writerow(user_follower_fields) response.json()['following'], response.json()['twitter_username'],
writecsv.writerow(user_follower_row) response.json()['public_gists'], response.json()['public_repos'], response.json()['company'],
response.json()['hireable'], response.json()['site_admin'], response.json()['created_at'],
logging.info(logRoller.loggedToCsv.format(file.name)) response.json()['updated_at']]
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
with open(os.path.join("output", f"{response.json()['login']}.csv"), 'w') as file:
else: write_csv = csv.writer(file)
logging.info(logRoller.loggingSkipped.format(prompt)) write_csv.writerow(user_profile_fields)
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}") write_csv.writerow(user_profile_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# create .csv for repository profile
def log_repo_profile(response):
repo_profile_fields = ['Name', 'ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility',
'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?',
'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?',
'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at']
repo_profile_row = [response.json()['name'], response.json()['id'], response.json()['description'],
response.json()['forks'], response.json()['stargazers_count'], response.json()['watchers'],
response.json()['license'], response.json()['default_branch'], response.json()['visibility'],
response.json()['language'], response.json()['open_issues'], response.json()['topics'],
response.json()['homepage'], response.json()['clone_url'], response.json()['ssh_url'],
response.json()['fork'], response.json()['allow_forking'], response.json()['private'],
response.json()['archived'], response.json()['is_template'], response.json()['has_wiki'],
response.json()['has_pages'], response.json()['has_projects'], response.json()['has_issues'],
response.json()['has_downloads'], response.json()['pushed_at'], response.json()['created_at'],
response.json()['updated_at']]
with open(os.path.join("output", f"{response.json()['name']}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(repo_profile_fields)
write_csv.writerow(repo_profile_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# create .csv for repository forks # create .csv for repository path contents
def logRepoForks(fork, count): def log_repo_path_contents(content, repo_name):
repo_fork_fields = [ 'Name','ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility', 'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?', 'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?', 'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at'] path_content_fields = ['Filename', 'Size (bytes)', 'Type', 'Path', 'SHA', 'URL']
repo_fork_row = [fork['full_name'], fork['id'], fork['description'], fork['forks'], fork['stargazers_count'], fork['watchers'], fork['license'], fork['default_branch'], fork['visibility'], fork['language'], fork['open_issues'], fork['topics'], fork['homepage'], fork['clone_url'], fork['ssh_url'], fork['fork'], fork['allow_forking'], fork['private'], fork['archived'], fork['is_template'], fork['has_wiki'], fork['has_pages'], fork['has_projects'], fork['has_issues'], fork['has_downloads'], fork['pushed_at'], fork['created_at'], fork['updated_at']] path_content_row = [content['name'], content['size'], content['type'], content['path'], content['sha'],
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower() content['html_url']]
if prompt == 'y':
with open(f"output/{fork['name']}_fork_{count}.csv", 'w') as file: with open(os.path.join("output", f"{content['name']}_content_from_{repo_name}.csv"), 'w') as file:
writecsv = csv.writer(file) write_csv = csv.writer(file)
writecsv.writerow(repo_fork_fields) write_csv.writerow(path_content_fields)
writecsv.writerow(repo_fork_row) write_csv.writerow(path_content_row)
logging.info(logRoller.loggedToCsv.format(file.name)) logging.info(logged_to_csv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}") xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# create .csv for repository issues # create .csv for repository stargazer
def logRepoIssues(issue, repo_name): def log_repo_stargazers(stargazer, repo_name):
repo_issue_fields = ['Title', 'ID', 'Node ID', 'Number', 'State', 'Reactions', 'Comments', 'Milestone', 'Assignee', 'Assignees', 'Author association', 'Labels', 'Is locked?', 'Lock reason', 'Closed at', 'Created at', 'Updated at'] user_follower_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type',
repo_issue_row = [issue['title'], issue['id'], issue['node_id'], issue['number'], issue['state'], issue['reactions'], issue['comments'], issue['milestone'], issue['assignee'], issue['assignees'], issue['author_association'], issue['labels'], issue['locked'], issue['active_lock_reason'], issue['closed_at'], issue['created_at'], issue['updated_at']] 'Is site admin?', 'URL']
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower() user_follower_row = [stargazer['avatar_url'], stargazer['login'], stargazer['id'], stargazer['node_id'],
if prompt == 'y': stargazer['gravatar_id'], stargazer['type'], stargazer['site_admin'], stargazer['html_url']]
with open(f"output/{repo_name}_issue_{issue['id']}.csv", 'w') as file:
writecsv = csv.writer(file) with open(os.path.join("output", f"{stargazer['login']}_stargazer_of_{repo_name}.csv"), 'w') as file:
writecsv.writerow(repo_issue_fields) write_csv = csv.writer(file)
writecsv.writerow(repo_issue_row) write_csv.writerow(user_follower_fields)
write_csv.writerow(user_follower_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}") logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt)) # create .csv for repository forks
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}") def log_repo_forks(fork, count):
repo_fork_fields = ['Name', 'ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility',
'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?',
'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?',
'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at']
repo_fork_row = [fork['full_name'], fork['id'], fork['description'], fork['forks'], fork['stargazers_count'],
fork['watchers'], fork['license'], fork['default_branch'], fork['visibility'], fork['language'],
fork['open_issues'], fork['topics'], fork['homepage'], fork['clone_url'], fork['ssh_url'],
fork['fork'], fork['allow_forking'], fork['private'], fork['archived'], fork['is_template'],
fork['has_wiki'], fork['has_pages'], fork['has_projects'], fork['has_issues'],
fork['has_downloads'], fork['pushed_at'], fork['created_at'], fork['updated_at']]
with open(os.path.join("output", f"{fork['name']}_fork_{count}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(repo_fork_fields)
write_csv.writerow(repo_fork_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# create .csv for repository releases # create .csv for repository issues
def logRepoReleases(release, repo_name): def log_repo_issues(issue, repo_name):
repo_release_fields = ['Name', 'ID', 'Node ID', 'Tag', 'Branch', 'Assets', 'Is draft?', 'Is prerelease?', 'Created at', 'Published at'] repo_issue_fields = ['Title', 'ID', 'Node ID', 'Number', 'State', 'Reactions', 'Comments', 'Milestone', 'Assignee',
repo_release_row = [release['name'], release['id'], release['node_id'], release['tag_name'], release['target_commitish'], release['assets'], release['draft'], release['prerelease'], release['created_at'], release['published_at']] 'Assignees', 'Author association', 'Labels', 'Is locked?', 'Lock reason', 'Closed at',
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower() 'Created at', 'Updated at']
if prompt == 'y': repo_issue_row = [issue['title'], issue['id'], issue['node_id'], issue['number'], issue['state'],
with open(f"output/{repo_name}_release_{release['name']}.csv", 'w') as file: issue['reactions'], issue['comments'], issue['milestone'], issue['assignee'], issue['assignees'],
writecsv = csv.writer(file) issue['author_association'], issue['labels'], issue['locked'], issue['active_lock_reason'],
writecsv.writerow(repo_release_fields) issue['closed_at'], issue['created_at'], issue['updated_at']]
writecsv.writerow(repo_release_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# Create .csv file for repository contributors
def logRepoContributors(contributor, repo_name):
repo_contributor_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type', 'Is site admin?', 'URL']
repo_contributor_row = [contributor['avatar_url'], contributor['login'], contributor['id'], contributor['node_id'], contributor['gravatar_id'], contributor['type'], contributor['site_admin'], contributor['html_url']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{contributor['login']}_contributor_of_{repo_name}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(repo_contributor_fields)
writecsv.writerow(repo_contributor_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
print(f"{SignVar.info} {logRoller.loggingSkipped}\n")
# Create .csv for organization' events
def logOrgEvents(event, organization):
org_event_fields = ['ID', 'Type', 'Created at', 'Payload']
org_event_row = [event['id'], event['type'], event['created_at'], event['payload']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{organization}_event_{event['id']}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(org_event_fields)
writecsv.writerow(org_event_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# Create .csv for organization' repositories
def logOrgRepos(repository, organization):
org_repo_fields = [ 'Name','ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility', 'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?', 'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?', 'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at']
org_repo_row = [repository['full_name'], repository['id'], repository['description'], repository['forks'], repository['stargazers_count'], repository['watchers'], repository['license'], repository['default_branch'], repository['visibility'], repository['language'], repository['open_issues'], repository['topics'], repository['homepage'], repository['clone_url'], repository['ssh_url'], repository['fork'], repository['allow_forking'], repository['private'], repository['archived'], repository['is_template'], repository['has_wiki'], repository['has_pages'], repository['has_projects'], repository['has_issues'], repository['has_downloads'], repository['pushed_at'], repository['created_at'], repository['updated_at']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{repository['name']}_repository_of_{organization}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(org_repo_fields)
writecsv.writerow(org_repo_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# .csv for user' repositories
def logUserRepos(repository, username):
user_repo_fields = [ 'Name','ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility', 'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?', 'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?', 'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at']
user_repo_row = [repository['full_name'], repository['id'], repository['description'], repository['forks'], repository['stargazers_count'], repository['watchers'], repository['license'], repository['default_branch'], repository['visibility'], repository['language'], repository['open_issues'], repository['topics'], repository['homepage'], repository['clone_url'], repository['ssh_url'], repository['fork'], repository['allow_forking'], repository['private'], repository['archived'], repository['is_template'], repository['has_wiki'], repository['has_pages'], repository['has_projects'], repository['has_issues'], repository['has_downloads'], repository['pushed_at'], repository['created_at'], repository['updated_at']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{repository['name']}_{username}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(user_repo_fields)
writecsv.writerow(user_repo_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# .csv for user events with open(os.path.join("output", f"{repo_name}_issue_{issue['id']}.csv"), 'w') as file:
def logUserEvents(event): write_csv = csv.writer(file)
user_event_fields = ['Actor', 'Type', 'Repository', 'Created at', 'Payload'] write_csv.writerow(repo_issue_fields)
user_event_row = [event['actor']['login'], event['type'], event['repo']['name'], event['created_at'], event['payload']] write_csv.writerow(repo_issue_row)
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{event['actor']['login']}_event_{event['id']}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(user_event_fields)
writecsv.writerow(user_event_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# .csv for user gists
def logUserGists(gist):
user_gist_fields = ['ID', 'Node ID', 'About', 'Comments', 'Files', 'Git Push URL', 'Is public?', 'Is truncated?', 'Updated at']
user_gist_row = [gist['id'], gist['node_id'], gist['description'], gist['comments'], gist['files'], gist['git_push_url'], gist['public'], gist['truncated'], gist['updated_at']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{gist['id']}_gists_{gist['owner']['login']}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(user_gist_fields)
writecsv.writerow(user_gist_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# .csv for user followers
def logUserFollowers(follower, username):
user_follower_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type', 'Is site admin?', 'URL']
user_follower_row = [follower['avatar_url'], follower['login'], follower['id'], follower['node_id'], follower['gravatar_id'], follower['type'], follower['site_admin'], follower['html_url']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{follower['login']}_follower_of_{username}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(user_follower_fields)
writecsv.writerow(user_follower_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# .csv for user following
def logUserFollowing(user, username):
user_following_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type', 'Is site admin?', 'URL']
user_following_row = [user['avatar_url'], user['login'], user['id'], user['node_id'], user['gravatar_id'], user['type'], user['site_admin'], user['html_url']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{user['login']}_followed_by_{username}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(user_following_fields)
writecsv.writerow(user_following_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# .csv for user' subscriptions
def logUserSubscriptions(repository, username):
user_subscription_fields = [ 'Name','ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility', 'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?', 'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?', 'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at']
user_subscription_row = [repository['name'], repository['id'], repository['description'], repository['forks'], repository['stargazers_count'], repository['watchers'], repository['license'], repository['default_branch'], repository['visibility'], repository['language'], repository['open_issues'], repository['topics'], repository['homepage'], repository['clone_url'], repository['ssh_url'], repository['fork'], repository['allow_forking'], repository['private'], repository['archived'], repository['is_template'], repository['has_wiki'], repository['has_pages'], repository['has_projects'], repository['has_issues'], repository['has_downloads'], repository['pushed_at'], repository['created_at'], repository['updated_at']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{username}_subscriptions_{repository['name']}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(user_subscription_fields)
writecsv.writerow(user_subscription_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# .csv for user organizations
def logUserOrgs(organization, username):
user_org_fields = ['Profile photo', 'Name', 'ID', 'Node ID', 'URL', 'About']
user_org_row = [organization['avatar_url'], organization['login'], organization['id'], organization['node_id'], organization['url'], organization['description']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y':
with open(f"output/{organization['login']}_{username}.csv", 'w') as file:
writecsv = csv.writer(file)
writecsv.writerow(user_org_fields)
writecsv.writerow(user_org_row)
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else:
logging.info(logRoller.loggingSkipped.format(prompt))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
# Create .csv for user search logging.info(logged_to_csv.format(file.name))
def logUserSearch(user, query): xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
user_search_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type', 'Is site admin?', 'URL']
user_search_row = [user['avatar_url'], user['login'], user['id'], user['node_id'], user['gravatar_id'], user['type'], user['site_admin'], user['html_url']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower() # create .csv for repository releases
if prompt == 'y': def log_repo_releases(release, repo_name):
with open(f"output/{user['login']}_user_search_result_for_{query}.csv", 'w') as file: repo_release_fields = ['Name', 'ID', 'Node ID', 'Tag', 'Branch', 'Assets', 'Is draft?', 'Is prerelease?',
writecsv = csv.writer(file) 'Created at', 'Published at']
writecsv.writerow(user_search_fields) repo_release_row = [release['name'], release['id'], release['node_id'], release['tag_name'],
writecsv.writerow(user_search_row) release['target_commitish'], release['assets'], release['draft'], release['prerelease'],
release['created_at'], release['published_at']]
logging.info(logRoller.loggedToCsv.format(file.name))
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}") with open(os.path.join("output", f"{repo_name}_release_{release['name']}.csv"), 'w') as file:
write_csv = csv.writer(file)
else: write_csv.writerow(repo_release_fields)
logging.info(logRoller.loggingSkipped.format(prompt)) write_csv.writerow(repo_release_row)
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}")
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv for repository search
def logRepoSearch(repository, query):
repo_search_fields = [ 'Name','ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility', 'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?', 'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?', 'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at'] # Create .csv file for repository contributors
repo_search_row = [repository['full_name'], repository['id'], repository['description'], repository['forks'], repository['stargazers_count'], repository['watchers'], repository['license'], repository['default_branch'], repository['visibility'], repository['language'], repository['open_issues'], repository['topics'], repository['homepage'], repository['clone_url'], repository['ssh_url'], repository['fork'], repository['allow_forking'], repository['private'], repository['archived'], repository['is_template'], repository['has_wiki'], repository['has_pages'], repository['has_projects'], repository['has_issues'], repository['has_downloads'], repository['pushed_at'], repository['created_at'], repository['updated_at']] def log_repo_contributors(contributor, repo_name):
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower() repo_contributor_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type',
if prompt == 'y': 'Is site admin?', 'URL']
with open(f"output/{repository['name']}_repository_search_result_for_{query}.csv", 'w') as file: repo_contributor_row = [contributor['avatar_url'], contributor['login'], contributor['id'], contributor['node_id'],
writecsv = csv.writer(file) contributor['gravatar_id'], contributor['type'], contributor['site_admin'],
writecsv.writerow(repo_search_fields) contributor['html_url']]
writecsv.writerow(repo_search_row)
with open(os.path.join("output", f"{contributor['login']}_contributor_of_{repo_name}.csv"), 'w') as file:
logging.info(logRoller.loggedToCsv.format(file.name)) write_csv = csv.writer(file)
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}") write_csv.writerow(repo_contributor_fields)
write_csv.writerow(repo_contributor_row)
else:
logging.info(logRoller.loggingSkipped.format(prompt)) logging.info(logged_to_csv.format(file.name))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}") xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv for topic search # Create .csv for organisation' events
def logTopicSearch(topic, query): def log_repo_events(event, organisation):
topic_search_fields = ['Name', 'Score', 'Curated', 'Featured', 'Display name', 'Created by', 'Created at', 'Updated at'] org_event_fields = ['ID', 'Type', 'Created at', 'Payload']
topic_search_row = [topic['name'], topic['score'], topic['curated'], topic['featured'], topic['display_name'], topic['created_by'], topic['created_at'], topic['updated_at']] org_event_row = [event['id'], event['type'], event['created_at'], event['payload']]
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower()
if prompt == 'y': with open(os.path.join("output", f"{organisation}_event_{event['id']}.csv"), 'w') as file:
with open(f"output/{topic['name']}_topic_search_result_for_{query}.csv", 'w') as file: write_csv = csv.writer(file)
writecsv = csv.writer(file) write_csv.writerow(org_event_fields)
writecsv.writerow(topic_search_fields) write_csv.writerow(org_event_row)
writecsv.writerow(topic_search_row)
logging.info(logged_to_csv.format(file.name))
logging.info(logRoller.loggedToCsv.format(file.name)) xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}")
else: # Create .csv for organisation' repositories
logging.info(logRoller.loggingSkipped.format(prompt)) def log_org_repos(repository, organisation):
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}") org_repo_fields = ['Name', 'ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility',
'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?',
'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?',
# Create .csv for issues search 'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at']
def logIssueSearch(issue, query): org_repo_row = [repository['full_name'], repository['id'], repository['description'], repository['forks'],
issue_search_fields = ['Title', 'ID', 'Node ID', 'Number', 'State', 'Reactions', 'Comments', 'Milestone', 'Assignee', 'Assignees', 'Author association', 'Labels', 'Is locked?', 'Lock reason', 'Closed at', 'Created at', 'Updated at'] repository['stargazers_count'], repository['watchers'], repository['license'],
issue_search_row = [issue['title'], issue['id'], issue['node_id'], issue['number'], issue['state'], issue['reactions'], issue['comments'], issue['milestone'], issue['assignee'], issue['assignees'], issue['author_association'], issue['labels'], issue['locked'], issue['active_lock_reason'], issue['closed_at'], issue['created_at'], issue['updated_at']] repository['default_branch'], repository['visibility'], repository['language'],
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower() repository['open_issues'], repository['topics'], repository['homepage'], repository['clone_url'],
if prompt == 'y': repository['ssh_url'], repository['fork'], repository['allow_forking'], repository['private'],
with open(f"output/{issue['id']}_issue_search_result_for_{query}.csv", 'w') as file: repository['archived'], repository['is_template'], repository['has_wiki'], repository['has_pages'],
writecsv = csv.writer(file) repository['has_projects'], repository['has_issues'], repository['has_downloads'],
writecsv.writerow(issue_search_fields) repository['pushed_at'], repository['created_at'], repository['updated_at']]
writecsv.writerow(issue_search_row)
with open(os.path.join("output", f"{repository['name']}_repository_of_{organisation}.csv"), 'w') as file:
logging.info(logRoller.loggedToCsv.format(file.name)) write_csv = csv.writer(file)
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}") write_csv.writerow(org_repo_fields)
write_csv.writerow(org_repo_row)
else:
logging.info(logRoller.loggingSkipped.format(prompt)) logging.info(logged_to_csv.format(file.name))
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}") xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv for commits search # .csv for user' repositories
def logCommitsSearch(commit, query): def log_user_repos(repository, username):
commit_search_fields = ['SHA', 'Author', 'Username', 'Email', 'Committer', 'Repository', 'URL', 'Description'] user_repo_fields = ['Name', 'ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility',
commit_search_row = [commit['commit']['tree']['sha'], commit['commit']['author']['name'], commit['author']['login'], commit['commit']['author']['email'], commit['commit']['committer']['name'], commit['repository']['full_name'], commit['html_url'], commit['commit']['message']] 'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?',
xprint(f"\n{SignVar.prompt} {logRoller.askLogCsv}", end="");prompt = input().lower() 'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?',
if prompt == 'y': 'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at']
with open(f"output/{commit['commit']['tree']['sha']}_commit_search_result_for_{query}.csv", 'w') as file: user_repo_row = [repository['full_name'], repository['id'], repository['description'], repository['forks'],
writecsv = csv.writer(file) repository['stargazers_count'], repository['watchers'], repository['license'],
writecsv.writerow(commit_search_fields) repository['default_branch'], repository['visibility'], repository['language'],
writecsv.writerow(commit_search_row) repository['open_issues'], repository['topics'], repository['homepage'], repository['clone_url'],
repository['ssh_url'], repository['fork'], repository['allow_forking'], repository['private'],
logging.info(logRoller.loggedToCsv.format(file.name)) repository['archived'], repository['is_template'], repository['has_wiki'], repository['has_pages'],
xprint(f"{SignVar.positive} {logRoller.loggedToCsv.format(file.name)}") repository['has_projects'], repository['has_issues'], repository['has_downloads'],
repository['pushed_at'], repository['created_at'], repository['updated_at']]
else:
logging.info(logRoller.loggingSkipped.format(prompt)) with open(os.path.join("output", f"{repository['name']}_{username}.csv"), 'w') as file:
xprint(f"{SignVar.info} {logRoller.loggingSkipped.format(prompt)}") write_csv = csv.writer(file)
write_csv.writerow(user_repo_fields)
write_csv.writerow(user_repo_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# .csv for user events
def log_user_events(event):
user_event_fields = ['Actor', 'Type', 'Repository', 'Created at', 'Payload']
user_event_row = [event['actor']['login'], event['type'], event['repo']['name'], event['created_at'],
event['payload']]
with open(os.path.join("output", f"{event['actor']['login']}_event_{event['id']}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(user_event_fields)
write_csv.writerow(user_event_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# .csv for user gists
def log_user_gists(gist):
user_gist_fields = ['ID', 'Node ID', 'About', 'Comments', 'Files', 'Git Push URL', 'Is public?', 'Is truncated?',
'Updated at']
user_gist_row = [gist['id'], gist['node_id'], gist['description'], gist['comments'], gist['files'],
gist['git_push_url'], gist['public'], gist['truncated'], gist['updated_at']]
with open(os.path.join("output", f"{gist['id']}_gists_{gist['owner']['login']}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(user_gist_fields)
write_csv.writerow(user_gist_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# .csv for user followers
def log_user_followers(follower, username):
user_follower_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type',
'Is site admin?', 'URL']
user_follower_row = [follower['avatar_url'], follower['login'], follower['id'], follower['node_id'],
follower['gravatar_id'], follower['type'], follower['site_admin'], follower['html_url']]
with open(f"output/{follower['login']}_follower_of_{username}.csv", 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(user_follower_fields)
write_csv.writerow(user_follower_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# .csv for user following
def log_user_following(user, username):
user_following_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type',
'Is site admin?', 'URL']
user_following_row = [user['avatar_url'], user['login'], user['id'], user['node_id'], user['gravatar_id'],
user['type'], user['site_admin'], user['html_url']]
with open(os.path.join("output", f"{user['login']}_followed_by_{username}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(user_following_fields)
write_csv.writerow(user_following_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# .csv for user' subscriptions
def log_user_subscriptions(repository, username):
user_subscription_fields = ['Name', 'ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility',
'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?',
'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?',
'Has pages?', 'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at',
'Created at', 'Updated at']
user_subscription_row = [repository['name'], repository['id'], repository['description'], repository['forks'],
repository['stargazers_count'], repository['watchers'], repository['license'],
repository['default_branch'], repository['visibility'], repository['language'],
repository['open_issues'], repository['topics'], repository['homepage'],
repository['clone_url'], repository['ssh_url'], repository['fork'],
repository['allow_forking'], repository['private'], repository['archived'],
repository['is_template'], repository['has_wiki'], repository['has_pages'],
repository['has_projects'], repository['has_issues'], repository['has_downloads'],
repository['pushed_at'], repository['created_at'], repository['updated_at']]
with open(os.path.join("output", f"{username}_subscriptions_{repository['name']}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(user_subscription_fields)
write_csv.writerow(user_subscription_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# .csv for user organisations
def log_user_orgs(organisation, username):
user_org_fields = ['Profile photo', 'Name', 'ID', 'Node ID', 'URL', 'About']
user_org_row = [organisation['avatar_url'], organisation['login'], organisation['id'], organisation['node_id'],
organisation['url'], organisation['description']]
with open(os.path.join("output", f"{organisation['login']}_{username}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(user_org_fields)
write_csv.writerow(user_org_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv for user search
def log_users_search(user, query):
user_search_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type', 'Is site admin?',
'URL']
user_search_row = [user['avatar_url'], user['login'], user['id'], user['node_id'], user['gravatar_id'],
user['type'], user['site_admin'], user['html_url']]
with open(os.path.join("output", f"{user['login']}_user_search_result_for_{query}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(user_search_fields)
write_csv.writerow(user_search_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv for repository search
def log_repos_search(repository, query):
repo_search_fields = ['Name', 'ID', 'About', 'Forks', 'Stars', 'Watchers', 'License', 'Branch', 'Visibility',
'Language(s)', 'Open issues', 'Topics', 'Homepage', 'Clone URL', 'SSH URL', 'Is fork?',
'Is forkable?', 'Is private?', 'Is archived?', 'Is template?', 'Has wiki?', 'Has pages?',
'Has projects?', 'Has issues?', 'Has downloads?', 'Pushed at', 'Created at', 'Updated at']
repo_search_row = [repository['full_name'], repository['id'], repository['description'], repository['forks'],
repository['stargazers_count'], repository['watchers'], repository['license'],
repository['default_branch'], repository['visibility'], repository['language'],
repository['open_issues'], repository['topics'], repository['homepage'], repository['clone_url'],
repository['ssh_url'], repository['fork'], repository['allow_forking'], repository['private'],
repository['archived'], repository['is_template'], repository['has_wiki'],
repository['has_pages'], repository['has_projects'], repository['has_issues'],
repository['has_downloads'], repository['pushed_at'], repository['created_at'],
repository['updated_at']]
with open(os.path.join("output", f"{repository['name']}_repository_search_result_for_{query}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(repo_search_fields)
write_csv.writerow(repo_search_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv for topic search
def log_topics_search(topic, query):
topic_search_fields = ['Name', 'Score', 'Curated', 'Featured', 'Display name', 'Created by', 'Created at',
'Updated at']
topic_search_row = [topic['name'], topic['score'], topic['curated'], topic['featured'], topic['display_name'],
topic['created_by'], topic['created_at'], topic['updated_at']]
with open(os.path.join("output", f"{topic['name']}_topic_search_result_for_{query}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(topic_search_fields)
write_csv.writerow(topic_search_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv for issues search
def log_issues_search(issue, query):
issue_search_fields = ['Title', 'ID', 'Node ID', 'Number', 'State', 'Reactions', 'Comments', 'Milestone',
'Assignee', 'Assignees', 'Author association', 'Labels', 'Is locked?', 'Lock reason',
'Closed at', 'Created at', 'Updated at']
issue_search_row = [issue['title'], issue['id'], issue['node_id'], issue['number'], issue['state'],
issue['reactions'], issue['comments'], issue['milestone'], issue['assignee'],
issue['assignees'], issue['author_association'], issue['labels'], issue['locked'],
issue['active_lock_reason'], issue['closed_at'], issue['created_at'], issue['updated_at']]
with open(os.path.join("output", f"{issue['id']}_issue_search_result_for_{query}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(issue_search_fields)
write_csv.writerow(issue_search_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv for commits search
def log_commits_search(commit, query):
commit_search_fields = ['SHA', 'Author', 'Username', 'Email', 'Committer', 'Repository', 'URL', 'Description']
commit_search_row = [commit['commit']['tree']['sha'], commit['commit']['author']['name'], commit['author']['login'],
commit['commit']['author']['email'], commit['commit']['committer']['name'],
commit['repository']['full_name'], commit['html_url'], commit['commit']['message']]
with open(os.path.join("output", f"{commit['commit']['tree']['sha']}_commit_search_result_for_{query}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(commit_search_fields)
write_csv.writerow(commit_search_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")

View File

@@ -1,182 +1,171 @@
from rich.table import Table from rich.table import Table
from rich import print as xprint from octosuite.config import Tree, xprint, white, green, white_bold, green_bold, header_title, reset
from octosuite.colors import white, green, white_bold, green_bold, header_title, reset
"""
Help
This class holds the help text for available commands.
"""
class Help:
usageText = 'Use syntax {} to get started with %s{}%s.' % (green_bold, reset)
usageText1 = '%sUse {} to view all available subcommands.%s' % (white, reset)
usageText2 = "%sThe {} command works with subcommands. %s" % (white, reset)
def Org():
xprint(Help.usageText2.format(f"{green_bold}org{reset}") + Help.usageText1.format(f"{green_bold}help:org{reset}"))
def Repo():
xprint(Help.usageText2.format(f"{green_bold}repo{reset}") + Help.usageText1.format(f"{green_bold}help:repo{reset}"))
def User():
xprint(Help.usageText2.format(f"{green_bold}user{reset}") + Help.usageText1.format(f"{green_bold}help:user{reset}"))
def Search():
xprint(Help.usageText2.format(f"{green_bold}search{reset}") + Help.usageText1.format(f"{green_bold}help:search{reset}"))
def Source():
xprint(Help.usageText2.format(f"{green_bold}source{reset}") + Help.usageText1.format(f"{green_bold}help:source{reset}"))
def Logs():
xprint(Help.usageText2.format(f"{green_bold}logs{reset}") + Help.usageText1.format(f"{green_bold}help:logs{reset}"))
def Version():
xprint(Help.usageText2.format(f"{green_bold}version{reset}") + Help.usageText1.format(f"{green_bold}help:version{reset}"))
def Csv():
xprint(Help.usageText2.format(f"{green_bold}csv{reset}") + Help.usageText1.format(f"{green_bold}help:csv{reset}"))
def versionCommand():
version_cmd_table =Table(show_header=True, header_style=header_title)
version_cmd_table.add_column("Command", style="dim", width=12)
version_cmd_table.add_column("Description")
version_cmd_table.add_row("check", "Check for new release(s)")
version_cmd_table.add_row("info", "Version information")
syntax = f"{green}version:<command>{reset}" # helper.py
xprint(f"{Help.usageText.format(syntax, 'version management')}") # This file holds the help text for available commands.
xprint(version_cmd_table) usage_text = 'Use syntax {} to get started with %s{}%s.' % (green_bold, reset)
usage_text_1 = '%sUse {} to view all available subcommands.%s' % (white, reset)
usage_text_2 = "%sThe {} command works with subcommands. %s" % (white, reset)
def sourceCommand():
source_cmd_table =Table(show_header=True, header_style=header_title)
source_cmd_table.add_column("Command", style="dim", width=12)
source_cmd_table.add_column("Description")
source_cmd_table.add_row("zipball", "Download source code Zipball")
source_cmd_table.add_row("tarball", "Download source code Tarball")
syntax = f"{green}source:<command>{reset}"
xprint(f"{Help.usageText.format(syntax, 'source code downloads')}")
xprint(source_cmd_table)
def searchCommand():
search_cmd_table =Table(show_header=True, header_style=header_title)
search_cmd_table.add_column("Command", style="dim", width=12)
search_cmd_table.add_column("Description")
search_cmd_table.add_row("users", "Search user(s)")
search_cmd_table.add_row("repos", "Search repositor[y][ies]")
search_cmd_table.add_row("topics", "Search topic(s)")
search_cmd_table.add_row("issues", "Search issue(s)")
search_cmd_table.add_row("commits", "Search commit(s)")
syntax = f"{green}search:<command>{reset}"
xprint(f"{Help.usageText.format(syntax, 'target discovery')}")
xprint(search_cmd_table)
def userCommand():
user_cmd_table =Table(show_header=True, header_style=header_title)
user_cmd_table.add_column("Command", style="dim", width=12)
user_cmd_table.add_column("Description")
user_cmd_table.add_row("profile", "Get a target's profile info")
user_cmd_table.add_row("gists", "Return a users's gists")
user_cmd_table.add_row("org", "Return organizations that a target belongs to/owns")
user_cmd_table.add_row("repos", "Return a target's repositories")
user_cmd_table.add_row("events", "Return a target's events")
user_cmd_table.add_row("follows", "Check if user(A) follows user(B)")
user_cmd_table.add_row("followers", "Return a target's followers")
user_cmd_table.add_row("following", "Return a list of users the target is following")
user_cmd_table.add_row("subscriptions", "Return a target's subscriptions")
syntax = f"{green}user:<command>{reset}"
xprint(f"{Help.usageText.format(syntax, 'user investigation(s)')}")
xprint(user_cmd_table)
def orgCommand():
org_cmd_table =Table(show_header=True, header_style=header_title)
org_cmd_table.add_column("Command", style="dim", width=12)
org_cmd_table.add_column("Description")
org_cmd_table.add_row("profile", "Get a target organization' profile info")
org_cmd_table.add_row("repos", "Return a target organization' repositories")
org_cmd_table.add_row("events", "Return a target organization' events")
org_cmd_table.add_row("member", "Check if a specified user is a public member of the target organization")
syntax = f"{green}org:<command>{reset}"
xprint(f"{Help.usageText.format(syntax, 'organization investigation(s)')}")
xprint(org_cmd_table)
def repoCommand():
repo_cmd_table =Table(show_header=True, header_style=header_title)
repo_cmd_table.add_column("Command", style="dim", width=12)
repo_cmd_table.add_column("Description")
repo_cmd_table.add_row("profile", "Get a repository's info")
repo_cmd_table.add_row("issues", "Return a repository's issues")
repo_cmd_table.add_row("forks", "Return a repository's forks")
repo_cmd_table.add_row("releases", "Return a repository's releases")
repo_cmd_table.add_row("stargazers", "Return a repository's stargazers")
repo_cmd_table.add_row("path_contents", "List contents in a path of a repository")
syntax = f"{green}repo:<command>{reset}"
xprint(f"{Help.usageText.format(syntax, 'repository investigation(s)')}")
xprint(repo_cmd_table)
def logsCommand():
logs_cmd_table =Table(show_header=True, header_style=header_title)
logs_cmd_table.add_column("Command", style="dim", width=12)
logs_cmd_table.add_column("Description")
logs_cmd_table.add_row("view", "View logs")
logs_cmd_table.add_row("read", "Read log")
logs_cmd_table.add_row("delete", "Delete log")
syntax = f"{green}logs:<command>{reset}"
xprint(f"{Help.usageText.format(syntax, 'log(s) management')}")
xprint(logs_cmd_table)
def csvCommand():
csv_cmd_table =Table(show_header=True, header_style=header_title)
csv_cmd_table.add_column("Command", style="dim", width=12)
csv_cmd_table.add_column("Description")
csv_cmd_table.add_row("view", "View csv files")
csv_cmd_table.add_row("read", "Read csv")
csv_cmd_table.add_row("delete", "Delete csv")
syntax = f"{green}csv:<command>{reset}"
xprint(f"{Help.usageText.format(syntax, 'csv management')}")
xprint(csv_cmd_table)
def helpCommand(): def org():
core_cmd_table =Table(show_header=True, header_style=header_title) xprint(usage_text_2.format(f"{green_bold}org{reset}") + usage_text_1.format(f"{green_bold}help:org{reset}"))
core_cmd_table.add_column("Command", style="dim", width=12)
core_cmd_table.add_column("Description")
core_cmd_table.add_row("help", "Help menu")
core_cmd_table.add_row("exit", "Close session")
core_cmd_table.add_row("clear", "Clear screen")
core_cmd_table.add_row("about", "Program's info")
core_cmd_table.add_row("author", "Developer's info")
help_sub_cmd_table =Table(show_header=True, header_style=header_title)
help_sub_cmd_table.add_column("Command", style="dim", width=12)
help_sub_cmd_table.add_column("Description")
help_sub_cmd_table.add_row("csv", "List all csv management commands")
help_sub_cmd_table.add_row("logs", "List all logs management commands")
help_sub_cmd_table.add_row("org", "List all organization investigation commands")
help_sub_cmd_table.add_row("user", "List all users investigation commands")
help_sub_cmd_table.add_row("repo", "List all repository investigation commands")
help_sub_cmd_table.add_row("search", "List all target discovery commands")
help_sub_cmd_table.add_row("source", "List all source code download commands (for developers)")
help_sub_cmd_table.add_row("version", "List all version management commands")
syntax = f"{green}help:<command>{reset}"
xprint(core_cmd_table) def repo():
xprint(f"\n\n{Help.usageText.format(syntax, 'octosuite')}") xprint(usage_text_2.format(f"{green_bold}repo{reset}") + usage_text_1.format(f"{green_bold}help:repo{reset}"))
xprint(help_sub_cmd_table)
def user():
xprint(usage_text_2.format(f"{green_bold}user{reset}") + usage_text_1.format(f"{green_bold}help:user{reset}"))
def search():
xprint(usage_text_2.format(f"{green_bold}search{reset}") + usage_text_1.format(f"{green_bold}help:search{reset}"))
def source():
xprint(usage_text_2.format(f"{green_bold}source{reset}") + usage_text_1.format(f"{green_bold}help:source{reset}"))
def logs():
xprint(usage_text_2.format(f"{green_bold}logs{reset}") + usage_text_1.format(f"{green_bold}help:logs{reset}"))
def csv():
xprint(usage_text_2.format(f"{green_bold}csv{reset}") + usage_text_1.format(f"{green_bold}help:csv{reset}"))
def source_command():
source_cmd_table = Table(show_header=True, header_style=header_title)
source_cmd_table.add_column("Command", style="dim")
source_cmd_table.add_column("Description")
source_cmd_table.add_row("zipball", "Download source code Zipball")
source_cmd_table.add_row("tarball", "Download source code Tarball")
syntax = f"{green}source:<command>{reset}"
xprint(f"{usage_text.format(syntax, 'source code downloads')}")
xprint(source_cmd_table)
def search_command():
search_cmd_table = Table(show_header=True, header_style=header_title)
search_cmd_table.add_column("Command", style="dim")
search_cmd_table.add_column("Description")
search_cmd_table.add_row("users", "Search user(s)")
search_cmd_table.add_row("repos", "Search repositor[y][ies]")
search_cmd_table.add_row("topics", "Search topic(s)")
search_cmd_table.add_row("issues", "Search issue(s)")
search_cmd_table.add_row("commits", "Search commit(s)")
syntax = f"{green}search:<command>{reset}"
xprint(f"{usage_text.format(syntax, 'target discovery')}")
xprint(search_cmd_table)
def user_command():
user_cmd_table = Table(show_header=True, header_style=header_title)
user_cmd_table.add_column("Command", style="dim")
user_cmd_table.add_column("Description")
user_cmd_table.add_row("email", "Return a target's email")
user_cmd_table.add_row("profile", "Get a target's profile info")
user_cmd_table.add_row("gists", "Return a users's gists")
user_cmd_table.add_row("orgs", "Return organisations that a target belongs to/owns")
user_cmd_table.add_row("repos", "Return a target's repositories")
user_cmd_table.add_row("events", "Return a target's events")
user_cmd_table.add_row("follows", "Check if user(A) follows user(B)")
user_cmd_table.add_row("followers", "Return a target's followers")
user_cmd_table.add_row("following", "Return a list of users the target is following")
user_cmd_table.add_row("subscriptions", "Return a target's subscriptions")
syntax = f"{green}user:<command>{reset}"
xprint(f"{usage_text.format(syntax, 'user investigation(s)')}")
xprint(user_cmd_table)
def org_command():
org_cmd_table = Table(show_header=True, header_style=header_title)
org_cmd_table.add_column("Command", style="dim")
org_cmd_table.add_column("Description")
org_cmd_table.add_row("profile", "Get a target organisation' profile info")
org_cmd_table.add_row("repos", "Return a target organisation' repositories")
org_cmd_table.add_row("events", "Return a target organisation' events")
org_cmd_table.add_row("member", "Check if a specified user is a public member of the target organisation")
syntax = f"{green}org:<command>{reset}"
xprint(f"{usage_text.format(syntax, 'organisation investigation(s)')}")
xprint(org_cmd_table)
def repo_command():
repo_cmd_table = Table(show_header=True, header_style=header_title)
repo_cmd_table.add_column("Command", style="dim")
repo_cmd_table.add_column("Description")
repo_cmd_table.add_row("profile", "Get a repository's info")
repo_cmd_table.add_row("issues", "Return a repository's issues")
repo_cmd_table.add_row("forks", "Return a repository's forks")
repo_cmd_table.add_row("releases", "Return a repository's releases")
repo_cmd_table.add_row("stargazers", "Return a repository's stargazers")
repo_cmd_table.add_row("contributors", "Return a repository's contributors")
repo_cmd_table.add_row("path_contents", "List contents in a path of a repository")
syntax = f"{green}repo:<command>{reset}"
xprint(f"{usage_text.format(syntax, 'repository investigation(s)')}")
xprint(repo_cmd_table)
def logs_command():
logs_cmd_table = Table(show_header=True, header_style=header_title)
logs_cmd_table.add_column("Command", style="dim")
logs_cmd_table.add_column("Description")
logs_cmd_table.add_row("view", "View logs")
logs_cmd_table.add_row("read", "Read log")
logs_cmd_table.add_row("delete", "Delete log")
logs_cmd_table.add_row("clear", "clear logs")
syntax = f"{green}logs:<command>{reset}"
xprint(f"{usage_text.format(syntax, 'log(s) management')}")
xprint(logs_cmd_table)
def csv_command():
csv_cmd_table = Table(show_header=True, header_style=header_title)
csv_cmd_table.add_column("Command", style="dim")
csv_cmd_table.add_column("Description")
csv_cmd_table.add_row("view", "View csv files")
csv_cmd_table.add_row("read", "Read csv")
csv_cmd_table.add_row("delete", "Delete csv")
csv_cmd_table.add_row("clear", "clear csv files")
syntax = f"{green}csv:<command>{reset}"
xprint(f"{usage_text.format(syntax, 'csv management')}")
xprint(csv_cmd_table)
def help_command():
core_cmd_table = Table(show_header=True, header_style=header_title)
core_cmd_table.add_column("Command", style="dim", width=12)
core_cmd_table.add_column("Description")
core_cmd_table.add_row("ls", "List contents of the specified directory")
core_cmd_table.add_row("cd", "Move to specified directory")
core_cmd_table.add_row("help", "Help menu")
core_cmd_table.add_row("exit", "Close session")
core_cmd_table.add_row("clear", "Clear screen")
core_cmd_table.add_row("about", "Program's info")
core_cmd_table.add_row("author", "Developer's info")
help_sub_cmd_table = Table(show_header=True, header_style=header_title)
help_sub_cmd_table.add_column("Command", style="dim", width=12)
help_sub_cmd_table.add_column("Description")
help_sub_cmd_table.add_row("csv", "List all csv management commands")
help_sub_cmd_table.add_row("logs", "List all logs management commands")
help_sub_cmd_table.add_row("org", "List all organisation investigation commands")
help_sub_cmd_table.add_row("user", "List all users investigation commands")
help_sub_cmd_table.add_row("repo", "List all repository investigation commands")
help_sub_cmd_table.add_row("search", "List all target discovery commands")
help_sub_cmd_table.add_row("source", "List all source code download commands (for developers)")
syntax = f"{green}help:<command>{reset}"
xprint(core_cmd_table)
xprint(f"\n\n{usage_text.format(syntax, 'octosuite')}")
xprint(help_sub_cmd_table)

View File

@@ -1,27 +1,21 @@
""" # LogRoller This class is where the main notification strings/messages are held, and are being used in two different
logRoller # cases (they're being used by logging to be written to log files, and being printed out to the screen).
This class is where the main notification strings/messages are held,
and are being used in two different cases (they're beig used by logging to be written to log files, and being printed out to the screen).
""" ctrl_c = "Session terminated with Ctrl+C."
class logRoller: error = "An error occurred: {}"
Ctrl = "Session terminated with {}." session_opened = "Opened new session on {}:{}"
Error = "An error occurred: {}" session_closed = "Session closed at {}."
sessionOpened = "Opened new session on {}:{}" viewing_logs = "Viewing logs"
sessionClosed = "Session closed at {}." viewing_csv = "Viewing CSV file(s)..."
viewingLogs = "Viewing logs..." deleted = "Deleted: {}"
viewingCsv = "Viewing CSV file(s)..." reading = "Reading: {}"
deletedLog = "Deleted log -> {}" file_downloading = "Downloading: {}"
readingLog = "Reading log -> {}" file_downloaded = "Downloaded: downloads/{}"
readingCsv = 'Reading csv -> {}' info_not_found = "Information not found: {}, {}, {}"
deletedCsv = 'Deleted csv -> {}' user_not_found = "User not found: @{}"
fileDownloading = "Downloading -> {}..." org_not_found = "organisation not found: @{}"
fileDownloaded = "Downloaded -> downloads/{}" repo_or_user_not_found = "Repository or User not found: {}, @{}"
infoNotFound = "Information not found -> ({} - {} - {})" prompt_log_csv = "Would you like to log this output to a .csv file?"
repoNotFound = "Repository not found -> ({})" logged_to_csv = "Output logged: {}"
userNotFound = "User not found -> (@{})" limit_output = "Limit '{}' output to how many? (1-100)"
orgNotFound = "Organization not found -> (@{})"
repoOrUserNotFound = "Repository or user not found -> ({} - @{})"
askLogCsv = "Do you wish to log this output to a .csv file? (Y/n) "
loggedToCsv = "Output logged -> ({})"
loggingSkipped = "Logging skipped -> ({})"
limitInput = "Limit '{}' output to how many? (1-100) "

View File

@@ -1,918 +1,53 @@
#!usr/bin/python # import everything from the octosuite.py file
from octosuite.octosuite import * # I drifted away from the 'pythonic way' here
import os
import csv
import sys
import json
import logging
import getpass
import requests
import platform
import subprocess
from rich.table import Table
from datetime import datetime
from rich import print as xprint
from octosuite.helper import Help
from octosuite.sign_vars import SignVar
from octosuite.log_roller import logRoller
from octosuite.csv_loggers import csvLogger
from octosuite.banner import name_logo, version_tag
from octosuite.colors import red, white, green, red_bold, white_bold, green_bold, header_title, reset
# API endpoint def octosuite():
endpoint = 'https://api.github.com' setup_readline()
# Path attribute try:
path_attrs =['size','type','path','sha','html_url'] run = Octosuite()
# Path attribute dictionary path_finder()
path_attr_dict = {'size': 'Size (bytes)', configure_logging()
'type': 'Type', check_updates()
'path': 'Path', if args.method:
'sha': 'SHA', """
'html_url': 'URL'} Iterate over the argument_map and check if the passed command line argument matches any argument in it [argument_map],
if there's a match, we return its method. If no match is found, we do nothing (which will return the usage).
"""
# Organization attributes for argument, method in run.argument_map:
org_attrs = ['avatar_url','login','id','node_id','email','description','blog','location','followers','following','twitter_username','public_gists','public_repos','type','is_verified','has_organization_projects','has_repository_projects','created_at','updated_at'] if args.method == argument:
# Organization attribute dictionary method()
org_attr_dict = {'avatar_url': 'Profile Photo',
'login': 'Username',
'id': 'ID',
'node_id': 'Node ID',
'email': 'Email',
'description': 'About',
'location': 'Location',
'blog': 'Blog',
'followers': 'Followers',
'following': 'Following',
'twitter_username': 'Twitter handle',
'public_gists': 'Gists',
'public_repos': 'Repositories',
'type': 'Account type',
'is_verified': 'Is verified?',
'has_organization_projects': 'Has organization projects?',
'has_repository_projects': 'Has repository projects?',
'created_at': 'Created at',
'updated_at': 'Updated at'}
# Repository attributes
repo_attrs = ['id','description','forks','stargazers_count','watchers','license','default_branch','visibility','language','open_issues','topics','homepage','clone_url','ssh_url','fork','allow_forking','private','archived','has_downloads','has_issues','has_pages','has_projects','has_wiki','pushed_at','created_at','updated_at']
# Repository attribute dictionary
repo_attr_dict = {'id': 'ID',
'description': 'About',
'forks': 'Forks',
'stargazers_count': 'Stars',
'watchers': 'Watchers',
'license': 'License',
'default_branch': 'Branch',
'visibility': 'Visibility',
'language': 'Language(s)',
'open_issues': 'Open issues',
'topics': 'Topics',
'homepage': 'Homepage',
'clone_url': 'Clone URL',
'ssh_url': 'SSH URL',
'fork': 'Is fork?',
'allow_forking': 'Is forkable?',
'private': 'Is private?',
'archived': 'Is archived?',
'is_template': 'Is template?',
'has_wiki': 'Has wiki?',
'has_pages': 'Has pages?',
'has_projects': 'Has projects?',
'has_issues': 'Has issues?',
'has_downloads': 'Has downloads?',
'pushed_at': 'Pushed at',
'created_at': 'Created at',
'updated_at': 'Updated at'}
# Repo releases attributes
repo_releases_attrs = ['id', 'node_id','tag_name','target_commitish','assets','draft','prerelease','created_at','published_at']
# Repo releases attribute dictionary
repo_releases_attr_dict = {'id': 'ID',
'node_id': 'Node ID',
'tag_name': 'Tag',
'target_commitish': 'Branch',
'assets': 'Assets',
'draft': 'Is draft?',
'prerelease': 'Is prerelease?',
'created_at': 'Created at',
'published_at': 'Published at'}
# Profile attributes
profile_attrs = ['avatar_url','login','id','node_id','bio','blog','location','followers','following','twitter_username','public_gists','public_repos','company','hireable','site_admin','created_at','updated_at']
# Profile attribute dictionary
profile_attr_dict = {'avatar_url': 'Profile Photo',
'login': 'Username',
'id': 'ID',
'node_id': 'Node ID',
'bio': 'Bio',
'blog': 'Blog',
'location': 'Location',
'followers': 'Followers',
'following': 'Following',
'twitter_username': 'Twitter Handle',
'public_gists': 'Gists (public)',
'public_repos': 'Repositories (public)',
'company': 'Organization',
'hireable': 'Is hireable?',
'site_admin': 'Is site admin?',
'created_at': 'Joined at',
'updated_at': 'Updated at'}
# User attributes
user_attrs = ['avatar_url','id','node_id','gravatar_id','site_admin','type','html_url']
# User attribute dictionary
user_attr_dict = {'avatar_url': 'Profile Photo',
'id': 'ID',
'node_id': 'Node ID',
'gravatar_id': 'Gravatar ID',
'site_admin': 'Is site admin?',
'type': 'Account type',
'html_url': 'URL'}
# Topic atrributes
topic_attrs = ['score','curated','featured','display_name','created_by','created_at','updated_at']
# Topic attribute dictionary
topic_attr_dict = {'score': 'Score',
'curated': 'Curated',
'featured': 'Featured',
'display_name': 'Display name',
'created_by': 'Created by',
'created_at': 'Created at',
'updated_at': 'Updated at'}
# Gists attributes
gists_attrs = ['node_id','description','comments','files','git_push_url','public','truncated','updated_at']
# Gists attribute dictionary
gists_attr_dict = {'node_id': 'Node ID',
'description': 'About',
'comments': 'Comments',
'files': 'Files',
'git_push_url': 'Git Push URL',
'public': 'Is public?',
'truncated': 'Is truncated?',
'updated_at': 'Updated at'}
# Issue attributes
issue_attrs = ['id','node_id','score','state','number','comments','milestone','assignee','assignees','labels','locked','draft','closed_at']
# Issue attribute dict
issue_attr_dict = {'id': 'ID',
'node_id': 'Node ID',
'score': 'Score',
'state': 'State',
'closed_at': 'Closed at',
'number': 'Number',
'comments': 'Comments',
'milestone': 'Milestone',
'assignee': 'Assignee',
'assignees': 'Assignees',
'labels': 'Labels',
'draft': 'Is draft?',
'locked': 'Is locked?',
'created_at': 'Created at'}
# Repo issues attributes
repo_issues_attrs = ['id','node_id','state', 'reactions','number','comments','milestone','assignee','active_lock_reason', 'author_association','assignees','labels','locked','closed_at','created_at','updated_at']
# Issue attribute dict
repo_issues_attr_dict = {'id': 'ID',
'node_id': 'Node ID',
'number': 'Number',
'state': 'State',
'reactions': 'Reactions',
'comments': 'Comments',
'milestone': 'Milestone',
'assignee': 'Assignee',
'assignees': 'Assignees',
'author_association': 'Author association',
'labels': 'Labels',
'locked': 'Is locked?',
'active_lock_reason': 'Lock reason',
'closed_at': 'Closed at',
'created_at': 'Created at',
'updated_at': 'Updated at'}
# User organizations attributes
user_orgs_attrs = ['avatar_url','id','node_id','url','description']
user_orgs_attr_dict = {'avatar_url': 'Profile Photo',
'id': 'ID',
'node_id': 'Node ID',
'url': 'URL',
'description': 'About'}
# Author dictionary
author_dict = {'Alias': 'rly0nheart',
'Country': ':zambia: Zambia, Africa',
'About.me': 'https://about.me/rly0nheart',
'Buy Me A Coffee': 'https://buymeacoffee.com/189381184'}
'''
pathFinder()
This function is responsible for creating/checking the availability of the (.logs, output, downloads) folders,
enabling logging to automatically log network/user activity to a file,
and logging the start of a session.
'''
def pathFinder():
'''
Here we create/check 3 directories (.logs, output, downloads) on startup
If they exists, we ignore, otherwise, we create them
'''
directory_list = ['.logs', 'output', 'downloads']
for directory in directory_list:
os.makedirs(directory, exist_ok=True)
'''
Configure logging to log activities to a file, which will be named by the date and time a session was opened.
'''
now = datetime.now()
now_formatted = now.strftime("%Y-%m-%d %H:%M:%S%p")
logging.basicConfig(filename=f".logs/{now_formatted}.log", format="[%(asctime)s] [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S%p", level=logging.DEBUG)
# Log the start of a session
logging.info(logRoller.sessionOpened.format(platform.node(), getpass.getuser()))
'''
onStart()
This is the main function, responsible for mapping commands, calling other functions, and catching exceptions
'''
def onStart():
pathFinder()
# A list of tuples mapping commands to their functions
command_map = [("exit", exitSession),
("clear",clearScreen),
("about", about),
("author", author),
("help", Help.helpCommand),
("help:version", Help.versionCommand),
("help:source", Help.sourceCommand),
("help:search", Help.searchCommand),
("help:user", Help.userCommand),
("help:repo", Help.repoCommand),
("help:logs", Help.logsCommand),
("help:csv", Help.csvCommand),
("help:org", Help.orgCommand),
("version", Help.Version),
("version:info", versionInfo),
("version:check", versionCheck),
("source", Help.Source),
("source:tarball", downloadTarball),
("source:zipball", downloadZipball),
("org", Help.Org),
("org:events", orgEvents),
("org:profile", orgProfile),
("org:repos", orgRepos),
("org:member", orgMember),
("repo", Help.Repo),
("repo:path_contents", pathContents),
("repo:profile", repoProfile),
("repo:contributors", repoContributors),
("repo:stargazers", repoStargazers),
("repo:forks", repoForks),
("repo:issues", repoIssues),
("repo:releases", repoReleases),
("user", Help.User),
("user:repos", userRepos),
("user:gists", userGists),
("user:orgs", userOrgs),
("user:profile", userProfile),
("user:events", userEvents),
("user:followers", userFollowers),
("user:follows", userFollows),
("user:following", userFollowing),
("user:subscriptions", userSubscriptions),
("search", Help.Search),
("search:users", userSearch),
("search:repos", repoSearch),
("search:topics", topicSearch),
("search:issues", issueSearch),
("search:commits", commitsSearch),
("logs", Help.Logs),
("logs:view",viewLogs),
("logs:read",readLog),
("logs:delete",deleteLog),
("csv", Help.Csv),
("csv:view", viewCsv),
("csv:read", readCsv),
("csv:delete", deleteCsv)]
xprint(name_logo)
'''
Main loop keeps octosuite running, this will break if Octosuite detects a KeyboardInterrupt (Ctrl+C)
or if the 'exit' command is entered.
'''
while True:
try:
xprint(f"{white}┌──({red}{getpass.getuser()}{white}@{red}octosuite{white})\n├──[~{green}{os.getcwd()}{white}]\n└╼ {reset}", end="");command_input = input().lower()
print("\n")
'''
Iterating over the command_map and check if the user input matches any command in it [command_map],
if there's a match, we return its function. If no match is found, we ignore it.
'''
for command, function in command_map:
if command_input == command:
function()
print("\n") print("\n")
else: else:
pass pass
else:
"""
Main loop keeps octosuite running, this will break if Octosuite detects a KeyboardInterrupt (Ctrl+C)
or if the 'exit' command is entered.
"""
xprint(banner()[0], banner()[1])
while True:
command_input = Prompt.ask(f"{white}┌──({red}{getpass.getuser()}{white}@{red}octosuite{white})\n├──[~{green}{os.getcwd()}{white}]\n└╼{reset}")
"""
Iterate over the command_map and check if the user input matches any command in it [command_map],
if there's a match, we return its method. If no match is found, we ignore it.
"""
if command_input[:2] == 'cd':
os.chdir(command_input[3:])
elif command_input[:2] == 'ls':
os.system(f'dir {command_input[3:]}' if os.name == 'nt' else f'ls {command_input[3:]}')
else:
for command, method in run.command_map:
if command_input == command:
method()
print("\n")
else:
pass
# This catches the KeyboardInterrupt exception (Ctrl+C) except KeyboardInterrupt:
except KeyboardInterrupt: logging.warning(ctrl_c)
logging.warning(logRoller.Ctrl.format("Ctrl+C")) xprint(f"\n{WARNING} {ctrl_c}")
xprint(f"{SignVar.warning} {logRoller.Ctrl.format('Ctrl+C')}")
break
# This initially catches all exceptions (except the KeyboardInterrupt)
except Exception as e:
logging.error(logRoller.Error.format(e))
xprint(f"{SignVar.error} {logRoller.Error.format(e)}")
# Fetching organization info
def orgProfile():
xprint(f"{white}>> @{green}Organization {white}(username){reset} ", end="");organization = input()
response = requests.get(f"{endpoint}/orgs/{organization}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.orgNotFound.format(organization)}")
elif response.status_code == 200:
xprint(f"\n{white}{response.json()['name']}{reset}")
for attr in org_attrs:
xprint(f"{white}├─ {org_attr_dict[attr]}:{reset} {response.json()[attr]}")
csvLogger.logOrgProfile(response)
else:
xprint(response.json())
# Fetching user information
def userProfile():
xprint(f"{white}>> @{green}Username{reset} ", end="");username = input()
response = requests.get(f"{endpoint}/users/{username}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.userNotFound.format(username)}")
elif response.status_code == 200:
xprint(f"\n{white}{response.json()['name']}{reset}")
for attr in profile_attrs:
xprint(f"{white}├─ {profile_attr_dict[attr]}:{reset} {response.json()[attr]}")
csvLogger.logUserProfile(response)
else:
xprint(response.json())
# Fetching repository information
def repoProfile():
xprint(f"{white}>> %{green}Repository{reset} ", end="");repo_name = input()
xprint(f"{white}>> @{green}Owner{white} (username) ", end="");username = input()
response = requests.get(f"{endpoint}/repos/{username}/{repo_name}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.repoOrUserNotFound.format(repo_name, username)}")
elif response.status_code == 200:
xprint(f"\n{white}{response.json()['full_name']}{reset}")
for attr in repo_attrs:
xprint(f"{white}├─ {repo_attr_dict[attr]}:{reset} {response.json()[attr]}")
csvLogger.logRepoProfile(response)
else:
xprint(response.json())
# Get path contents
def pathContents():
xprint(f"{white}>> %{green}Repository{reset} ", end="");repo_name = input()
xprint(f"{white}>> @{green}Owner{white} (username) ", end="");username = input()
xprint(f"{white}>> ~{green}/path/name{reset} ", end="");path_name = input()
response = requests.get(f"{endpoint}/repos/{username}/{repo_name}/contents/{path_name}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.infoNotFound.format(repo_name, username, path_name)}")
elif response.status_code == 200:
content_count = 0
for content in response.json():
content_count += 1
xprint(f"\n{white}{content['name']}{reset}")
for attr in path_attrs:
xprint(f"{white}├─ {path_attr_dict[attr]}:{reset} {content[attr]}")
csvLogger.logRepoPathContents(content, repo_name)
xprint(SignVar.info, f"Found {content_count} file(s) in {repo_name}/{path_name}.")
else:
xprint(response.json())
# repo contributors
def repoContributors():
xprint(f"{white}>> %{green}Repository{reset} ", end="");repo_name = input()
xprint(f"{white}>> @{green}Owner{white} (username) ", end="");username = input()
xprint(SignVar.prompt, logRoller.limitInput.format("contributors"), end="");limit = int(input())
response = requests.get(f"{endpoint}/repos/{username}/{repo_name}/contributors?per_page={limit}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.repoOrUserNotFound.format(repo_name, username)}")
elif response.status_code == 200:
for contributor in response.json():
xprint(f"\n{white}{contributor['login']}{reset}")
for attr in user_attrs:
xprint(f"{white}├─ {user_attr_dict[attr]}:{reset} {contributor[attr]}")
csvLogger.logRepoContributors(contributor, repo_name)
else:
xprint(response.json())
# repo stargazers
def repoStargazers():
xprint(f"{white}>> %{green}Repository{reset} ");repo_name = input()
xprint(f"{white}>> @{green}Owner{white} (username){reset} ", end="");username = input()
xprint(SignVar.prompt, logRoller.limitInput.format("repository stargazers"), end="");limit = int(input())
response = requests.get(f"{endpoint}/repos/{username}/{repo_name}/stargazers?per_page={limit}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.repoOrUserNotFound.format(repo_name, username)}")
elif response.json() == {}:
xprint(f"{SignVar.negative} Repository does not have any stargazers -> ({repo_name})")
elif response.status_code == 200:
for stargazer in response.json():
xprint(f"\n{white}{stargazer['login']}{reset}")
for attr in user_attrs:
xprint(f"{white}├─ {user_attr_dict[attr]}:{reset} {stargazer[attr]}")
csvLogger.logRepoStargazers(stargazer, repo_name)
else:
xprint(response.json())
# repo forks
def repoForks():
xprint(f"{white}>> %{green}Repository{reset} ", end="");repo_name = input()
xprint(f"{white}>> @{green}Owner{white} (username){reset} ", end="");username = input()
xprint(SignVar.prompt, logRoller.limitInput.format("repository forks"), end="");limit = int(input())
response = requests.get(f"{endpoint}/repos/{username}/{repo_name}/forks?per_page={limit}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.repoOrUserNotFound.format(repo_name, username)}")
elif response.json() == {}:
xprint(f"{SignVar.negative} Repository does not have forks -> ({repo_name})")
elif response.status_code == 200:
count = 0
for fork in response.json():
count += 1
xprint(f"\n{white}{fork['full_name']}{reset}")
for attr in repo_attrs:
xprint(f"{white}├─ {repo_attr_dict[attr]}:{reset} {fork[attr]}")
csvLogger.logRepoForks(fork, count)
else:
xprint(response.json())
except Exception as e:
# Repo issues logging.error(error.format(e))
def repoIssues(): xprint(f"{ERROR} {error.format(e)}")
xprint(f"{white}>> %{green}Repository{reset} ", end="");repo_name = input()
xprint(f"{white}>> @{green}Owner{white} (username){reset} ", end="");username = input()
xprint(SignVar.prompt, logRoller.limitInput.format("repository issues"), end="");limit = int(input())
response = requests.get(f"{endpoint}/repos/{username}/{repo_name}/issues?per_page={limit}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.repoOrUserNotFound.format(repo_name, username)}")
elif response.json() == []:
xprint(f"{SignVar.negative} Repository does not have open issues -> ({repo_name})")
elif response.status_code == 200:
for issue in response.json():
xprint(f"\n{white}{issue['title']}{reset}")
for attr in repo_issues_attrs:
xprint(f"{white}├─ {repo_issues_attr_dict[attr]}:{reset} {issue[attr]}")
xprint(issue['body'])
csvLogger.logRepoIssues(issue, repo_name)
else:
xprint(response.json())
# Repo releases
def repoReleases():
xprint(f"{white}>> %{green}Repository{reset} ", end="");repo_name = input()
xprint(f"{white}>> @{green}Owner{white} (username){reset} ", end="");username = input()
xprint(SignVar.prompt, logRoller.limitInput.format("repository releases"), end="");limit = int(input())
response = requests.get(f"{endpoint}/repos/{username}/{repo_name}/releases?per_page={limit}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.repoOrUserNotFound.format(repo_name, username)}")
elif response.json() == []:
xprint(f"{SignVar.negative} Repository does not have releases -> ({repo_name})")
elif response.status_code == 200:
for release in response.json():
xprint(f"\n{white}{release['name']}{reset}")
for attr in repo_releases_attrs:
xprint(f"{white}├─ {repo_releases_attr_dict[attr]}:{reset} {release[attr]}")
xprint(release['body'])
csvLogger.logRepoReleases(release, repo_name)
else:
xprint(response.json())
# Fetching organization repositories
def orgRepos():
xprint(f"{white}>> @{green}Organization{white} (username){reset} ", end="");organization = input()
xprint(SignVar.prompt, logRoller.limitInput.format("organization repositories"), end="");limit = int(input())
response = requests.get(f"{endpoint}/orgs/{organization}/repos?per_page={limit}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.orgNotFound.format(organization)}")
elif response.status_code == 200:
for repository in response.json():
xprint(f"\n{white}{repository['full_name']}{reset}")
for attr in repo_attrs:
xprint(f"{white}├─ {repo_attr_dict[attr]}:{reset} {repository[attr]}")
csvLogger.logOrgRepos(repository, organization)
else:
xprint(response.json())
# organization events
def orgEvents():
xprint(f"{white}>> @{green}Organization{white} (username){reset} ", end="");organization = input()
xprint(SignVar.prompt, logRoller.limitInput.format("organization repositories"), end="");limit = int(input())
response = requests.get(f"{endpoint}/orgs/{organization}/events?per_page={limit}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.orgNotFound.format(organization)}")
elif response.status_code == 200:
for event in response.json():
xprint(f"\n{white}{event['id']}{reset}")
xprint(f"{white}├─ Type:{reset} {event['type']}\n{white}├─ Created at:{reset} {event['created_at']}")
xprint(event['payload'])
csvLogger.logOrgEvents(event, organization)
else:
xprint(response.json())
# organization member
def orgMember():
xprint(f"{white}>> @{green}Organization{white} (username){reset} ", end="");organization = input()
xprint(f"{white}>> @{green}Username{reset} ", end="");username = input()
response = requests.get(f"{endpoint}/orgs/{organization}/public_members/{username}")
if response.status_code == 204:
xprint(f"{SignVar.positive} User ({username}) is a public member of the organization -> ({organization})")
else:
xprint(f"{SignVar.negative} {response.json()['message']}")
# Fetching user repositories
def userRepos():
xprint(f"{white}>> @{green}Username{reset} ", end="");username = input()
xprint(SignVar.prompt, logRoller.limitInput.format("repositories"), end="");limit = int(input())
response = requests.get(f"{endpoint}/users/{username}/repos?per_page={limit}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.userNotFound.format(username)}")
elif response.status_code == 200:
for repository in response.json():
xprint(f"\n{white}{repository['full_name']}{reset}")
for attr in repo_attrs:
xprint(f"{white}├─ {repo_attr_dict[attr]}:{reset} {repository[attr]}")
csvLogger.logUserRepos(repository, username)
else:
xprint(response.json())
# Fetching user's gists
def userGists():
xprint(f"{white}>> @{green}Username{reset} ", end="");username = input()
xprint(SignVar.prompt, logRoller.limitInput.format('gists'), end="");limit = int(input())
response = requests.get(f"{endpoint}/users/{username}/gists?per_page={limit}")
#xprint(response.json())
if response.json() == []:
xprint(f"{SignVar.negative} User does not have gists.")
elif response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.userNotFound.format(username)}")
elif response.status_code == 200:
for gist in response.json():
xprint(f"\n{white}{gist['id']}{reset}")
for attr in gists_attrs:
xprint(f"{white}├─ {gists_attr_dict[attr]}:{reset} {gist[attr]}")
csvLogger.logUserGists(gist)
else:
xprint(response.json())
# Fetching a list of organizations that a user owns or belongs to
def userOrgs():
xprint(f"{white}>> @{green}Username{reset} ", end="");username = input()
xprint(SignVar.prompt, logRoller.limitInput.format("user organizations"), end="");limit = int(input())
response = requests.get(f"{endpoint}/users/{username}/orgs?per_page={limit}")
if response.json() == []:
xprint(f"{SignVar.negative} User ({username}) does not (belong to/own) any organizations.")
elif response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.userNotFound.format(username)}")
elif response.status_code == 200:
for organization in response.json():
print(f"\n{white}{organization['login']}{reset}")
for attr in user_orgs_attrs:
xprint(f"{white}├─ {user_orgs_attr_dict[attr]}:{reset} {organization[attr]}")
csvLogger.logUserOrgs(organization, username)
else:
xprint(response.json())
# Fetching a users events
def userEvents():
xprint(f"{white}>> @{green}Username{reset} ", end="");username = input()
xprint(SignVar.prompt, logRoller.limitInput.format("events"), end="");limit = int(input())
response = requests.get(f"{endpoint}/users/{username}/events/public?per_page={limit}")
if response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.userNotFound.format(username)}")
elif response.status_code == 200:
for event in response.json():
xprint(f"\n{white}{event['id']}{reset}")
xprint(f"{white}├─ Actor:{reset} {event['actor']['login']}")
xprint(f"{white}├─ Type:{reset} {event['type']}")
xprint(f"{white}├─ Repository:{reset} {event['repo']['name']}")
xprint(f"{white}├─ Created at:{reset} {event['created_at']}")
xprint(event['payload'])
csvLogger.logUserEvents(event)
else:
xprint(response.json())
# Fetching a target user's subscriptions
def userSubscriptions():
xprint(f"{white}>> @{green}Username{reset} ", end="");username = input().lower()
xprint(SignVar.prompt, logRoller.limitInput.format("user subscriptions"), end="");limit = int(input())
response = requests.get(f"{endpoint}/users/{username}/subscriptions?per_page={limit}")
if response.json() == []:
xprint(f"{SignVar.negative} User does not have any subscriptions.")
elif response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.userNotFound.format(username)}")
elif response.status_code == 200:
for repository in response.json():
xprint(f"\n{white}{repository['full_name']}{reset}")
for attr in repo_attrs:
xprint(f"{white}├─ {repo_attr_dict[attr]}:{reset} {repository[attr]}")
csvLogger.logUserSubscriptions(repository, username)
else:
xprint(response.json())
# Fetching a list of users the target follows
def userFollowing():
xprint(f"{white}>> @{green}Username{reset} ", end="");username = input().lower()
xprint(SignVar.prompt, logRoller.limitInput.format("user' following"), end="");limit = int(input())
response = requests.get(f"{endpoint}/users/{username}/following?per_page={limit}")
if response.json() == []:
xprint(f"{SignVar.negative} User ({username})does not follow anyone.")
elif response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.userNotFound.format(username)}")
elif response.status_code == 200:
for user in response.json():
xprint(f"\n{white}@{user['login']}{reset}")
for attr in user_attrs:
xprint(f"{white}├─ {user_attr_dict[attr]}:{reset} {user[attr]}")
csvLogger.logUserFollowing(user, username)
else:
xprint(response.json())
# Fetching user's followera'
def userFollowers():
xprint(f"{white}>> @{green}Username{reset} ", end="");username = input().lower()
xprint(SignVar.prompt, logRoller.limitInput.format("user followers"),end="");limit = int(input())
response = requests.get(f"{endpoint}/users/{username}/followers?per_page={limit}")
if response.json() == []:
xprint(f"{SignVar.negative} User ({username})does not have followers.")
elif response.status_code == 404:
xprint(f"{SignVar.negative} {logRoller.userNotFound.format(username)}")
elif response.status_code == 200:
for follower in response.json():
xprint(f"\n{white}@{follower['login']}{reset}")
for attr in user_attrs:
xprint(f"{white}├─ {user_attr_dict[attr]}:{reset} {follower[attr]}")
csvLogger.logUserFollowers(follower, username)
else:
xprint(response.json())
# Checking whether or not user[A] follows user[B]
def userFollows():
xprint(f"{white}>> @{green}user{white}(A) (username){reset} ", end="");user_a = input()
xprint(f"{white}>> @{green}user{white}(B) (username){reset} ", end="");user_b = input()
response = requests.get(f"{endpoint}/users/{user_a}/following/{user_b}")
if response.status_code == 204:
xprint(f"{SignVar.positive} @{user_a} FOLLOWS @{user_b}")
else:
xprint(f"{SignVar.negative} @{user_a} DOES NOT FOLLOW @{user_b}")
# User search
def userSearch():
xprint(f"{white}>> @{green}Query{white} (eg. john){reset} ", end="");query = input()
xprint(SignVar.prompt, logRoller.limitInput.format("user search"), end="");limit = int(input())
response = requests.get(f"{endpoint}/search/users?q={query}&per_page={limit}").json()
for user in response['items']:
xprint(f"\n{white}@{user['login']}{reset}")
for attr in user_attrs:
xprint(f"{white}├─ {user_attr_dict[attr]}:{reset} {user[attr]}")
csvLogger.logUserSearch(user, query)
# Repository search
def repoSearch():
xprint(f"{white}>> %{green}Query{white} (eg. git){reset} ", end="");query = input()
xprint(SignVar.prompt, logRoller.limitInput.format("repositor[y][ies] search"), end="");limit = int(input())
response = requests.get(f"{endpoint}/search/repositories?q={query}&per_page={limit}").json()
for repository in response['items']:
xprint(f"\n{white}{repository['full_name']}{reset}")
for attr in repo_attrs:
xprint(f"{white}├─ {repo_attr_dict[attr]}:{reset} {repository[attr]}")
csvLogger.logRepoSearch(repository, query)
# Topics search
def topicSearch():
xprint(f"{white}>> #{green}Query{white} (eg. osint){reset} ", end="");query = input()
xprint(SignVar.prompt, logRoller.limitInput.format("topic(s) search"),end="");limit = int(input())
response = requests.get(f"{endpoint}/search/topics?q={query}&per_page={limit}").json()
for topic in response['items']:
xprint(f"\n{white}{topic['name']}{reset}")
for attr in topic_attrs:
xprint(f"{white}├─ {topic_attr_dict[attr]}:{reset} {topic[attr]}")
csvLogger.logTopicSearch(topic, query)
# Issue search
def issueSearch():
xprint(f"{white}>> !{green}Query{white} (eg. error){reset} ", end="");query = input()
xprint(SignVar.prompt, logRoller.limitInput.format("issue(s) search"), end="");limit = int(input())
response = requests.get(f"{endpoint}/search/issues?q={query}&per_page={limit}").json()
for issue in response['items']:
xprint(f"\n\n{white}{issue['title']}{reset}")
for attr in repo_issues_attrs:
xprint(f"{white}├─ {repo_issues_attr_dict[attr]}:{reset} {issue[attr]}")
xprint(issue['body'])
csvLogger.logIssueSearch(issue, query)
# Commits search
def commitsSearch():
xprint(f"{white}>> :{green}Query{white} (eg. filename:index.php){reset} ", end="");query = input()
xprint(SignVar.prompt, logRoller.limitInput.format("commit(s) search"), end="");limit = int(input())
response = requests.get(f"{endpoint}/search/commits?q={query}&per_page={limit}").json()
for commit in response['items']:
xprint(f"\n{white}{commit['commit']['tree']['sha']}{reset}")
xprint(f"{white}├─ Author:{reset} {commit['commit']['author']['name']}")
xprint(f"{white}├─ Username:{reset} {commit['author']['login']}")
xprint(f"{white}├─ Email:{reset} {commit['commit']['author']['email']}")
xprint(f"{white}├─ Commiter:{reset} {commit['commit']['committer']['name']}")
xprint(f"{white}├─ Repository:{reset} {commit['repository']['full_name']}")
xprint(f"{white}├─ URL:{reset} {commit['html_url']}")
xprint(commit['commit']['message'])
csvLogger.logCommitsSearch(commit, query)
# View csv files
def viewCsv():
logging.info(logRoller.viewingCsv)
csv_files = os.listdir("output")
csv_table =Table(show_header=True, header_style=header_title)
csv_table.add_column("CSV", style="dim", width=12)
csv_table.add_column("Size (bytes)")
for csv_file in csv_files:
csv_table.add_row(str(csv_file), str(os.path.getsize("output/"+csv_file)))
xprint(csv_table)
# Read a specified csv file
def readCsv():
xprint(f"{white}>> {green}.csv {reset}(filename) ", end="");csv_file = input()
with open(f"output/{csv_file}.csv", "r") as file:
logging.info(logRoller.readingCsv.format(csv_file))
xprint("\n"+file.read())
# Delete a specified csv file
def deleteCsv():
xprint(f"{white}>> {green}.csv {reset}filename{reset} ", end="");csv_file = input()
if sys.platform.lower().startswith(("win", "darwin")):
subprocess.run(['del',f'.output\{csv_file}.csv'])
else:
subprocess.run(['sudo','rm',f'output/{csv_file}.csv'],shell=False)
logging.info(logRoller.deletedCsv.format(csv_file))
xprint(f"{SignVar.positive} {logRoller.deletedCsv.format(csv_file)}")
# View octosuite log files
def viewLogs():
logging.info(logRoller.viewingLogs)
logs = os.listdir(".logs")
logs_table =Table(show_header=True, header_style=header_title)
logs_table.add_column("Log", style="dim", width=12)
logs_table.add_column("Size (bytes)")
for log in logs:
logs_table.add_row(str(log), str(os.path.getsize(".logs/"+log)))
xprint(logs_table)
# Read a specified log file
def readLog():
xprint(f"{white}>> {green}.log date{reset} (eg. 2022-04-27 10:09:36AM) ", end="");log_file = input()
with open(f".logs/{log_file}.log", "r") as log:
logging.info(logRoller.readingLog.format(log_file))
xprint("\n"+log.read())
# Delete a specified log file
def deleteLog():
xprint(f"{white}>> {green}.log date{reset} (eg. 2022-04-27 10:09:36AM) ", end="");log_file = input()
if sys.platform.lower().startswith(("win", "darwin")):
subprocess.run(['del',f'.logs\{log_file}.log'])
else:
subprocess.run(['sudo','rm',f'.logs/{log_file}.log'],shell=False)
logging.info(logRoller.deletedLog.format(log_file))
xprint(f"{SignVar.positive} {logRoller.deletedLog.format(log_file)}")
# Downloading release tarball
def downloadTarball():
logging.info(logRoller.fileDownloading.format(f"octosuite.v{version_tag}.tar"))
xprint(SignVar.info, logRoller.fileDownloading.format(f"octosuite.v{version_tag}.tar"))
data = requests.get(f"{endpoint}/repos/rly0nheart/octosuite/tarballball/{version_tag}")
with open(f"downloads/octosuite.v{version_tag}.tar", "wb") as file:
file.write(data.content)
file.close()
logging.info(logRoller.fileDownloaded.format(f"octosuite.v{version_tag}.tar"))
xprint(SignVar.positive, logRoller.fileDownloaded.format(f"octosuite.v{version_tag}.tar"))
# Downloading release zipball
def downloadZipball():
logging.info(logRoller.fileDownloading.format(f"octosuite.v{version_tag}.zip"))
xprint(SignVar.info, logRoller.fileDownloading.format(f"octosuite.v{version_tag}.zip"))
data = requests.get(f"{endpoint}/repos/rly0nheart/octosuite/zipball/{version_tag}")
with open(f"downloads/octosuite.v{version_tag}.zip", "wb") as file:
file.write(data.content)
file.close()
logging.info(logRoller.fileDownloaded.format(f"octosuite.v{version_tag}.zip"))
xprint(SignVar.positive, logRoller.fileDownloaded.format(f"octosuite.v{version_tag}.zip"))
def versionCheck():
response = requests.get(f"{endpoint}/repos/rly0nheart/octosuite/releases/latest")
if response.json()['tag_name'] == version_tag:
xprint(f"{SignVar.positive} Octosuite is up to date. Check again soon! :)")
else:
xprint(f"{SignVar.info} A new release is available (octosuite.v{response.json()['tag_name']}). Exit Octosuite and run '{green_bold}pip install --upgrade octosuite{white}' to download and install the update.")
# Author info
def author():
xprint(f"{white}Richard Mwewa (Ritchie){reset}")
for key,value in author_dict.items():
xprint(f"{white}├─ {key}:{reset} {value}")
# About program
def about():
xprint(f"""
{white_bold}OCTOSUITE © 2022 Richard Mwewa{reset}
An advanced and lightning fast framework for gathering open-source intelligence on GitHub users and organizations.
With over 20+ features, Octosuite only runs on 2 external dependencies, and returns the gathered intelligence in a highly readable format.
'_This is how you gather GitHub OSINT like a god:fire:_'
{white_bold}Read the wiki:{reset} https://github.com/rly0nheart/octosuite/wiki
{white_bold}GitHub REST API documentation:{reset} https://docs.github.com/rest
""")
# Close session
def exitSession():
xprint(f"{SignVar.prompt} This will close the current session, continue? (Y/n) ", end="");prompt = input().lower()
if prompt == 'y':
logging.info(logRoller.sessionClosed.format(datetime.now()))
xprint(f"{SignVar.info} {logRoller.sessionClosed.format(datetime.now())}")
exit()
else:
pass
# Clear screen
def clearScreen():
'''
We use 'cls' on Windows machines to clear the screen,
otherwise, we use 'clear'
'''
if sys.platform.lower().startswith(("win", "darwin")):
subprocess.run(['cls'])
else:
subprocess.run(['clear'], shell=False)
# Show version information
def versionInfo():
'''
Yes... the changelog is hard coded lol
'''
xprint(f"""
{white_bold}Whats new in v{version_tag}?{reset}
[ {green}fixed{reset} ] minor mistakes in code
""")

View File

@@ -0,0 +1,13 @@
from octosuite.config import red, white, green, yellow, reset
"""
message prefixes that show what
a notification in OctoSuite might be all about. This might not be very important or necessary in some cases,
but I think it's better to know the severity of the notifications you get in a program.
"""
PROMPT = f"{white}[{green}PROMPT{white}]{reset}"
WARNING = f"{white}[{yellow}WARNING{white}]{reset}"
ERROR = f"{white}[{red}ERROR{white}]{reset}"
POSITIVE = f"{white}[{green}POSITIVE{white}]{reset}"
NEGATIVE = f"{white}[{red}NEGATIVE{white}]{reset}"
INFO = f"{white}[{green}INFO{white}]{reset}"

1127
octosuite/octosuite.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +0,0 @@
from octosuite.colors import red, white, green, reset
'''
SignVar
*Even here, I couldn't think of a good name.*
The Attributes class holds the signs/symbols that show what a notification in OctoSuite might be all about.
This might not be very important or necessary in some cases, but I think it's better to know the severerity of the notifications you get in a program.
'''
class SignVar:
prompt = f"{white}[{green} ? {white}]{reset}"
warning = f"{white}[{red} ! {white}]{reset}"
error = f"{white}[{red} x {white}]{reset}"
positive = f"{white}[{green} + {white}]{reset}"
negative = f"{white}[{red} - {white}]{reset}"
info = f"{white}[{green} * {white}]{reset}"

39
pyproject.toml Normal file
View File

@@ -0,0 +1,39 @@
[build-system]
requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"
[tool.setuptools]
packages = ["octosuite"]
[project]
name = "octosuite"
version = "3.1.1"
description = "Advanced GitHub OSINT Framework"
readme = "README.md"
requires-python = ">=3.8"
license = {file = "LICENSE"}
keywords = ["github", "python", "github-api", "framework", "osint", "osint-framework", "osint-python", "osint-tool"]
authors = [{name = "Richard Mwewa", email = "rly0nheart@duck.com"}]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 3",
"Intended Audience :: Information Technology",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent",
"Natural Language :: English"
]
dependencies = [
"rich",
"psutil",
"requests",
"pyreadline3",
]
[project.urls]
homepage = "https://github.com/bellingcat/octosuite"
documentation = "https://github.com/bellingcat/octosuite/wiki"
repository = "https://github.com/bellingcat/octosuite.git"
[project.scripts]
octosuite = "octosuite.main:octosuite"

View File

@@ -1,31 +0,0 @@
import setuptools
with open("README.md", "r", encoding="utf-8") as file:
long_description = file.read()
setuptools.setup(
name="octosuite",
version="2.2.1",
author="Richard Mwewa",
author_email="richardmwewa@duck.com",
packages=["octosuite"],
description="Advanced Github OSINT Framework",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/rly0nheart/octosuite",
license="GNU General Public License v3 (GPLv3)",
install_requires=["requests", "rich"],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Information Technology',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Operating System :: OS Independent',
'Natural Language :: English',
'Programming Language :: Python :: 3'
],
entry_points={
"console_scripts": [
"octosuite=octosuite.main:onStart",
]
},
)