Compare commits

..

254 Commits

Author SHA1 Message Date
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
Richard Mwewa
d091125c15 Update setup.py 2022-07-08 12:01:27 +02:00
Richard Mwewa
e2c94fcc89 Update banner.py 2022-07-08 12:00:15 +02:00
Richard Mwewa
16f9a80818 Update main.py 2022-07-08 11:58:49 +02:00
Richard Mwewa
66d7a2c42c Update README.md 2022-07-08 11:52:42 +02:00
Richard Mwewa
456d46fdb1 Create README.md 2022-07-02 22:10:33 +02:00
Richard Mwewa
539c540a72 Update README.md 2022-07-02 22:09:46 +02:00
Richard Mwewa
db413767cd Update setup.py 2022-07-02 22:05:53 +02:00
Richard Mwewa
6a87cb51de Update sign_vars.py 2022-07-02 22:02:58 +02:00
Richard Mwewa
f98bfb34f3 Update log_roller.py 2022-07-02 21:57:53 +02:00
Richard Mwewa
43637193de Update helper.py 2022-07-02 21:56:16 +02:00
Richard Mwewa
33d9c7f5f2 Update csv_loggers.py 2022-07-02 21:53:25 +02:00
Richard Mwewa
835a78284b Update colors.py 2022-07-02 21:48:30 +02:00
Richard Mwewa
4dc2dced32 Update banner.py 2022-07-02 21:45:54 +02:00
Richard Mwewa
4b18c0307e Update main.py 2022-07-02 21:42:24 +02:00
Richard Mwewa
0ec3100347 Update README.md 2022-06-28 13:51:59 +02:00
Richard Mwewa
bb287acfe2 Update README.md 2022-06-28 13:51:01 +02:00
Richard Mwewa
7a6015b8e4 Update README.md 2022-06-28 13:40:51 +02:00
Richard Mwewa
d0f5c660b5 Update README.md 2022-06-28 01:03:06 +02:00
Richard Mwewa
2e65cfcb79 Update README.md 2022-06-28 01:00:15 +02:00
Richard Mwewa
41f392f5a0 Update README.md 2022-06-28 00:53:36 +02:00
Richard Mwewa
18bcc06070 Create codeql.yml 2022-06-28 00:34:21 +02:00
Richard Mwewa
c9cf000b23 Create .gitignore 2022-06-26 21:46:54 +02:00
Richard Mwewa
11e55f7804 Update README.md 2022-06-26 10:18:39 +02:00
Richard Mwewa
96c62c7097 Update banner.py 2022-06-26 10:08:44 +02:00
Richard Mwewa
587641cd18 Update setup.py 2022-06-26 10:07:55 +02:00
Richard Mwewa
d1ad3d14b9 Update banner.py 2022-06-26 10:06:55 +02:00
Richard Mwewa
0e3568f967 Update log_roller.py 2022-06-26 10:05:59 +02:00
Richard Mwewa
51d27c4996 [fix] error in source commands 2022-06-26 10:04:32 +02:00
Richard Mwewa
ae9d9f4af5 Update README.md 2022-06-25 09:47:51 +02:00
Richard Mwewa
482f2ee55a Update README.md 2022-06-24 15:05:38 +02:00
Richard Mwewa
9894b15209 Update README.md 2022-06-24 15:04:48 +02:00
Richard Mwewa
4d563683d2 Update README.md 2022-06-24 14:57:00 +02:00
Richard Mwewa
614a24d69c Update main.py 2022-06-23 21:12:51 +02:00
Richard Mwewa
2c18f116e9 Create python-publish.yml 2022-06-23 20:56:36 +02:00
Richard Mwewa
f67e876773 Delete output directory 2022-06-23 12:37:32 +02:00
Richard Mwewa
cf7ab5eef1 Delete downloads directory 2022-06-23 12:37:07 +02:00
Richard Mwewa
bdb88135fe Delete .logs directory 2022-06-23 12:36:49 +02:00
Richard Mwewa
e062065c75 Create setup.py 2022-06-23 12:36:11 +02:00
Richard Mwewa
b2557fd714 Create sign_vars.py 2022-06-23 12:31:33 +02:00
Richard Mwewa
2a025190bd Create log_roller.py 2022-06-23 12:30:21 +02:00
Richard Mwewa
3b4f38e76a Create helper.py 2022-06-23 12:29:18 +02:00
Richard Mwewa
5bffb8a4b5 Create csv_loggers.py 2022-06-23 12:28:01 +02:00
Richard Mwewa
1e95f70e3e Create colors.py 2022-06-23 12:25:43 +02:00
Richard Mwewa
88cc04a104 Create __init__.py 2022-06-23 12:24:48 +02:00
Richard Mwewa
3339614984 Create banner.py 2022-06-23 12:24:22 +02:00
Richard Mwewa
c9cb27f3fd Create main.py 2022-06-23 12:23:14 +02:00
Richard Mwewa
f58736f27d Delete octosuite 2022-06-23 12:22:05 +02:00
Richard Mwewa
822be0d088 Delete requirements.txt 2022-06-23 12:21:32 +02:00
Richard Mwewa
9fe13482ff Delete utilities directory 2022-06-23 12:20:44 +02:00
Richard Mwewa
c4b8e70762 Delete core directory 2022-06-23 12:19:40 +02:00
Richard Mwewa
557e64c22f Update README.md 2022-06-20 14:59:57 +02:00
Richard Mwewa
ba6d6da734 Delete python-publish.yml 2022-06-16 03:27:42 +02:00
Richard Mwewa
94a22c6de1 Update python-publish.yml 2022-06-16 03:26:25 +02:00
Richard Mwewa
0ff5765dc5 Update python-publish.yml 2022-06-16 02:39:16 +02:00
Richard Mwewa
bb4596c294 Update README.md 2022-06-16 02:06:33 +02:00
Richard Mwewa
8967e9ae7a Update python-publish.yml 2022-06-16 02:03:54 +02:00
Richard Mwewa
ccb40ec942 Update python-publish.yml 2022-06-16 01:42:23 +02:00
Richard Mwewa
4e2291eba3 Update README.md 2022-06-15 17:33:50 +02:00
Richard Mwewa
a9787efbe1 Update python-publish.yml 2022-06-15 01:46:18 +02:00
Richard Mwewa
efd7b44131 Update python-publish.yml 2022-06-15 01:08:27 +02:00
Richard Mwewa
2f40b22ab5 Create python-publish.yml 2022-06-15 00:45:44 +02:00
Richard Mwewa
17075b8a4b Rename investigations/.investigations to output/.output 2022-06-14 03:12:01 +02:00
Richard Mwewa
5d7f8cfbd7 Create .investigations 2022-06-09 18:05:07 +02:00
Richard Mwewa
daffefe24e Create README.md 2022-06-08 12:31:20 +02:00
Richard Mwewa
887957b73c Update helper.py 2022-06-05 14:42:57 +02:00
Richard Mwewa
2ab70c0737 Update colors.py 2022-06-05 14:36:18 +02:00
Richard Mwewa
0bca1d6e42 Update misc.py 2022-06-05 14:34:49 +02:00
Richard Mwewa
8f426eae26 Update misc.py 2022-06-05 14:26:49 +02:00
Richard Mwewa
d350a37cb6 Update colors.py 2022-06-05 10:55:07 +02:00
Richard Mwewa
151e8ba3dd Update misc.py 2022-06-05 10:54:04 +02:00
Richard Mwewa
23f3b43362 Update README.md 2022-05-29 13:05:13 +02:00
Richard Mwewa
985325550b Update README.md 2022-05-28 10:51:03 +02:00
Richard Mwewa
be3e14889d Update main.py 2022-05-26 15:25:29 +02:00
Richard Mwewa
62a9556432 Update misc.py 2022-05-25 11:17:52 +02:00
Richard Mwewa
705966135d Update README.md 2022-05-25 11:10:27 +02:00
Richard Mwewa
85e5c28a33 Add files via upload 2022-05-25 11:09:51 +02:00
Richard Mwewa
19165e1d48 Create .images 2022-05-25 11:09:15 +02:00
Richard Mwewa
c669aa87af Delete img directory 2022-05-25 11:07:57 +02:00
Richard Mwewa
7d0c462842 Update main.py 2022-05-25 11:06:40 +02:00
Richard Mwewa
10e2d2dae7 Update octosuite 2022-05-25 11:01:00 +02:00
Richard Mwewa
d0f9ff2dd0 Delete utils directory 2022-05-25 10:59:40 +02:00
Richard Mwewa
c88ec5f5ed Create misc.py 2022-05-25 10:58:47 +02:00
Richard Mwewa
161da5f5be Create helper.py 2022-05-25 10:55:29 +02:00
Richard Mwewa
5dd0ce300d Update and rename utils/colors.py to utilities/colors.py 2022-05-25 10:52:43 +02:00
Richard Mwewa
89b98b7281 b 2022-05-24 10:19:09 +02:00
Richard Mwewa
3e750bced7 Update README.md 2022-05-20 17:30:44 +02:00
31 changed files with 2214 additions and 1003 deletions

72
.github/workflows/codeql.yml vendored Normal file
View File

@@ -0,0 +1,72 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
schedule:
- cron: '18 7 * * 3'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

39
.github/workflows/python-publish.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Upload Python Package
on:
release:
types: [published]
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
__pycache__/

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,22 +1,25 @@
![octosuite](img/logo.png)
![logo](https://user-images.githubusercontent.com/74001397/175805580-fffc96d4-e0ef-48bb-a55c-80b2da3e714d.png)
![OS](https://img.shields.io/badge/OS-GNU%2FLinux-red?style=for-the-badge&logo=Linux)
![OS](https://img.shields.io/badge/OS-Windows-blue?style=for-the-badge&logo=Windows)
![OS](https://img.shields.io/badge/OS-Mac-white?style=for-the-badge&logo=apple)
![GitHub](https://img.shields.io/github/license/rly0nheart/octosuite?style=for-the-badge&logo=github)
![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/rly0nheart/octosuite?style=for-the-badge&logo=github)
![GitHub commits since latest release (by date)](https://img.shields.io/github/commits-since/rly0nheart/octosuite/1.9.0?style=for-the-badge&logo=github)
![GitHub repo size](https://img.shields.io/github/repo-size/rly0nheart/octosuite?style=for-the-badge&logo=github)
A framework for gathering open-source intelligence on GitHub users, repositories and organizations
> *Simply gather OSINT on Github users & organizations like a God🔥*
# INSTALLATION
Installation instructions are on the wiki, in addition to all other documentation.
[Refer to the Wiki](https://github.com/rly0nheart/octosuite/wiki)
[![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 - 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)
![GitHub repo size](https://img.shields.io/github/repo-size/bellingcat/octosuite?style=flat&logo=github)
# FEATURES
![octosuite_gui_exe (2)](https://user-images.githubusercontent.com/74001397/186889610-4530ee26-d3c6-46fc-8c92-8709f89617fd.png "Octosuite' about window")
![octosuite_gui_exe (4)](https://user-images.githubusercontent.com/74001397/186889897-c1c17fac-fddc-4967-9084-39cfe2d1307f.png "Octosuite user profile window")
# Wiki
[Refer to the Wiki](https://github.com/bellingcat/octosuite/wiki) for installation instructions, in addition to all other documentation.
# Features
- [x] Fetches an organization's profile information
- [x] Fetches an oganization's events
- [x] Returns an organization's repositories
@@ -32,6 +35,7 @@ Installation instructions are on the wiki, in addition to all other documentatio
- [x] Returns a user's gists
- [x] Returns organizations that a user owns/belongs to
- [x] Fetches a user's events
- [x] Fetches a list of users followed by the target
- [x] Fetches a user's followers
- [x] Checks if user A follows user B
- [x] Checks if user is a public member of an organizations
@@ -43,36 +47,21 @@ Installation instructions are on the wiki, in addition to all other documentatio
- [x] Searches topics
- [x] Searches issues
- [x] Searches commits
- [x] Easily updates with the 'update:install' command
- [x] Automatically logs network activity (.logs folder)
- [x] User can view, read and delete logs
- [x] All the above can be used with command-line arguments (PyPI Package only)
- [x] ...And more
# NOTES
* *octosuite automatically logs network and minor user activity. The logs are saved by date and time in .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* ✌🏾🙂
## Note
> Octosuite automatically logs network and user activity of each session, the logs are saved by date and time in the .logs folder
# PYPI
[PyPI Package](https://pypi.org/project/octosuite)
![PyPI Downloads](https://pepy.tech/badge/octosuite)
# LICENSE
# License
![license](https://user-images.githubusercontent.com/74001397/137917929-2f2cdb0c-4d1d-4e4b-9f0d-e01589e027b5.png)
# ABOUT DEVELOPER
[About.me](https://about.me/rly0nheart)
# SUPPORTERS
[![Stargazers repo roster for @rly0nheart/octosuite](https://reporoster.com/stars/rly0nheart/octosuite)](https://github.com/rly0nheart/octosuite/stargazers)
[![Forkers repo roster for @rly0nheart/octosuite](https://reporoster.com/forks/rly0nheart/octosuite)](https://github.com/rly0nheart/octosuite/members)
# DONATIONS
Love octosuite? Please consider buying me a coffee, I will really appreciate it. ☕👌🏾😊
# 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>
Your support will be much appreciated😊

View File

@@ -1,748 +0,0 @@
'''
OCTOSUITE Advanced Github OSINT Framework
Copyright (C) 2022 Richard Mwewa
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
'''
import os
import sys
import logging
import requests
import platform
import subprocess
from tqdm import tqdm
from pprint import pprint
from utils.misc import Banner
from utils.helper import Help
from utils.colors import Color
from datetime import datetime
# logMsg
# 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).
class logMsg:
Ctrl = 'Session terminated with (Ctrl+C).'
Error = 'Session terminated on error: {}'
sessionStart = 'Started new session on {}:{}'
sessionClosed = 'Session closed with (exit) command.'
fileDeleted = 'Deleted log: {}'
readingFile = 'Reading log: {}'
viewingLogs = 'Viewing logs...'
checkingUpdates = 'Checking for update(s)...'
installingUpdates = 'Installing update(s)...'
installedUpdates = '{} Update(s) installed.'
# firstBlood
# *I couldn't think of a good name for this.*
# The firstBlood is responsible for creating/checking the availability of the .logs folder
# and enabling logging to automatically log network/user activity to a file.
class firstBlood:
# If .logs folder exists, we ignore (pass)
if os.path.exists('.logs'):
pass
else:
# Creating the .logs directory
# If the current system is Windows based, we run mkdir command (without sudo?)
# Else we run the mkdir command (with sudo)
# As of writing, I have absolutely no idea if Windows users also use sudo to run commands as root/admin
if sys.platform.lower().startswith(('win','darwin')):
subprocess.run(['mkdir','.logs'])
else:
subprocess.run(['sudo','mkdir','.logs'],shell=False)
# Set to automatically monitor and log network and user activity into the .logs folder
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)
# Attributes
# *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 Attributes:
prompt = f'\n{Color.white}[{Color.green}?{Color.white}]{Color.reset}'
warning = f'\n{Color.white}[{Color.red}!{Color.white}]{Color.reset}'
error = f'\n{Color.white}[{Color.red}x{Color.white}]{Color.reset}'
positive = f'\n{Color.white}[{Color.green}+{Color.white}]{Color.reset}'
negative = f'\n{Color.white}[{Color.red}-{Color.white}]{Color.reset}'
info = f'\n{Color.white}[{Color.green}*{Color.white}]{Color.reset}'
# Octosuite
# This class is the backbone of the program.
# It holds all important methods/information for the program.
class Octosuite:
def __init__(self):
firstBlood()
# A list of tuples, mapping commands to their respective functionalities
self.commands_map = [('org:events', self.orgEvents),
('org:profile', self.orgProfile),
('org:repos', self.orgRepos),
('org:member', self.orgMember),
('repo:pathcontents', self.pathContents),
('repo:profile', self.repoProfile),
('repo:contributors', self.repoContributors),
('repo:languages', self.repoLanguages),
('repo:stargazers', self.repoStargazers),
('repo:forks', self.repoForks),
('repo:releases', self.repoReleases),
('user:repos', self.userRepos),
('user:gists', self.userGists),
('user:orgs', self.userOrgs),
('user:profile', self.userProfile),
('user:events', self.userEvents),
('user:followers', self.userFollowers),
('user:following', self.userFollowing),
('user:subscriptions', self.userSubscriptions),
('search:users', self.userSearch),
('search:repos', self.repoSearch),
('search:topics', self.topicSearch),
('search:issues', self.issueSearch),
('search:commits', self.commitsSearch),
('logs:view',self.viewLogs),
('logs:read',self.readLog),
('logs:delete',self.deleteLog),
('update:check', self.checkUpdate),
('update:install', self.installUpdate),
('help', Help.helpCommand),
('help:search', Help.searchCommand),
('help:user', Help.userCommand),
('help:repo', Help.repoCommand),
('help:logs', Help.logsCommand),
('help:org', Help.orgCommand),
('help:update', Help.updateCommand),
('author', self.author),
('about', self.about),
('clear',self.clearScreen),
('version', self.versionInfo),
('exit', self.exitSession)]
# Path attribute
self.path_attrs =['size','type','path','sha','html_url']
# Path attribute dictionary
self.path_attr_dict = {'size': 'Size (bytes)',
'type': 'Type',
'path': 'Path',
'sha': 'SHA',
'html_url': 'URL'}
# Organization attributes
self.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']
# Organization attribute dictionary
self.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)',
'public_repos': 'Repositories (public)',
'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
self.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
self.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
self.repo_releases_attrs = ['node_id','tag_name','target_commitish','assets','draft','prerelease','created_at','published_at']
# Repo releases attribute dictionary
self.repo_releases_attr_dict = {'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
self.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
self.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
self.user_attrs = ['avatar_url','id','node_id','gravatar_id','site_admin','type','html_url']
# User attribute dictionary
self.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
self.topic_attrs = ['score','curated','featured','display_name','created_by','created_at','updated_at']
# Topic attribute dictionary
self.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
self.gists_attrs = ['node_id','description','comments','files','git_push_url','public','truncated','updated_at']
# Gists attribute dictionary
self.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
self.issue_attrs = ['id','node_id','score','state','number','comments','milestone','assignee','assignees','labels','locked','draft','closed_at','body']
# Issue attribute dict
self.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',
'body': 'Body'}
# User organizations attributes
self.user_orgs_attrs = ['avatar_url','id','node_id','url','description']
self.user_orgs_attr_dict = {'avatar_url': 'Profile Photo',
'id': 'ID#',
'node_id': 'Node ID',
'url': 'URL',
'description': 'About'}
# Author dictionary
self.author_dict = {'Alias': 'rly0nheart',
'Country': 'Zambia, Africa',
'About.me': 'https://about.me/rly0nheart',
'BuyMeACoffee': 'https://buymeacoffee.com/189381184'}
# About dictionary
self.about_dict = {'Version': Banner.versionTag,'Category': 'Open Source Intelligence'}
def onStart(self):
# Log the beginning of a session
logging.info(logMsg.sessionStart.format(platform.node(), os.getlogin()))
# Use 'cls' to clear screen on Windows based machines
# Otherwise, use 'clear'
while True:
command_input = input(f'''\n{Color.white}┌──({Color.red}{os.getlogin()}{Color.white}@{Color.red}octosuite{Color.white})-[{Color.green}{os.getcwd()}{Color.white}]\n└╼[{Color.green}:_{Color.white}]{Color.reset} ''')
# Looping through the commands base to check if the user input command matches any command in the commands base, and return its functionality
# If no match is found, we ignore it
for command, functionality in self.commands_map:
if command_input.lower() == command:
functionality()
else:
pass
# Fetching organization info
def orgProfile(self):
organization = input(f'\n{Color.white}--> @{Color.green}organization{Color.white} (username){Color.reset} ')
response = requests.get(f'https://api.github.com/orgs/{organization}')
if response.status_code == 404:
print(f"{Attributes.negative} Organization {response.json()['message']}{Color.reset}")
else:
print(f"\n{Color.white}{response.json()['name']}{Color.reset}")
for attr in self.org_attrs:
print(f'{Color.white}├─ {self.org_attr_dict[attr]}: {Color.green}{response.json()[attr]}{Color.reset}')
# Fetching user information
def userProfile(self):
username = input(f'\n{Color.white}--> @{Color.green}username{Color.reset} ')
response = requests.get(f'https://api.github.com/users/{username}')
if response.status_code == 404:
print(f"{Attributes.negative} User {response.json()['message']}{Color.reset}")
else:
print(f"\n{Color.white}{response.json()['name']}{Color.reset}")
for attr in self.profile_attrs:
print(f'{Color.white}├─ {self.profile_attr_dict[attr]}: {Color.green}{response.json()[attr]}{Color.reset}')
# Fetching repository information
def repoProfile(self):
repo_name = input(f'\n{Color.white}--> %{Color.green}reponame{Color.reset} ')
username = input(f'{Color.white}--> @{Color.green}owner{Color.white} (username){Color.reset} ')
response = requests.get(f'https://api.github.com/repos/{username}/{repo_name}')
if response.status_code == 404:
print(f"{Attributes.negative} Repository or user {response.json()['message']}{Color.reset}")
else:
print(f"\n{Color.white}{response.json()['full_name']}{Color.reset}")
for attr in self.repo_attrs:
print(f"{Color.white}├─ {self.repo_attr_dict[attr]}: {Color.green}{response.json()[attr]}{Color.reset}")
# Get path contents
def pathContents(self):
repo_name = input(f'\n{Color.white}--> %{Color.green}reponame{Color.reset} ')
username = input(f'{Color.white}--> @{Color.green}owner{Color.white} (username){Color.reset} ')
path_name = input(f'{Color.white}--> ~{Color.green}/path/name{Color.reset} ')
response = requests.get(f'https://api.github.com/repos/{username}/{repo_name}/contents/{path_name}')
if response.status_code == 404:
print(f"{Attributes.negative} Information {response.json()['message']}{Color.reset}")
else:
for item in response.json():
print(f"\n{Color.white}{item['name']}{Color.reset}")
for attr in self.path_attrs:
print(f'{Color.white}├─ {self.path_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}')
# repo contributors
def repoContributors(self):
repo_name = input(f'\n{Color.white}--> %{Color.green}reponame{Color.reset} ')
username = input(f'{Color.white}--> @{Color.green}owner{Color.white} (username){Color.reset} ')
response = requests.get(f'https://api.github.com/repos/{username}/{repo_name}/contributors')
if response.status_code == 404:
print(f"{Attributes.negative} Repository or user {response.json()['message']}{Color.reset}")
else:
for item in response.json():
print(f"\n{Color.white}{item['login']}{Color.reset}")
for attr in self.user_attrs:
print(f'{Color.white}├─ {self.user_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}')
# repo downloads
def repoLanguages(self):
repo_name = input(f'\n{Color.white}--> %{Color.green}reponame{Color.reset} ')
username = input(f'{Color.white}--> @{Color.green}owner{Color.white} (username){Color.reset} ')
response = requests.get(f'https://api.github.com/repos/{username}/{repo_name}/languages')
if response.status_code == 404:
print(f"{Attributes.negative} Repository or user {response.json()['message']}{Color.reset}")
elif response.json() == {}:
print(f'{Attributes.negative} Repository has no supported language(s){Color.reset}')
else:
for language in response.json():
print(language)
# repo stargazers
def repoStargazers(self):
repo_name = input(f'\n{Color.white}--> %{Color.green}reponame{Color.reset} ')
username = input(f'{Color.white}--> @{Color.green}owner{Color.white} (username){Color.reset} ')
response = requests.get(f'https://api.github.com/repos/{username}/{repo_name}/stargazers')
if response.status_code == 404:
print(f"{Attributes.negative} Repository or user {response.json()['message']}{Color.reset}")
elif response.json() == {}:
print(f'{Attributes.negative} Repository does not have stargazers.{Color.reset}')
else:
for item in response.json():
print(f"\n{Color.white}{item['login']}{Color.reset}")
for attr in self.user_attrs:
print(f'{Color.white}├─ {self.user_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}')
# repo forks
def repoForks(self):
repo_name = input(f'\n{Color.white}--> %{Color.green}reponame{Color.reset} ')
username = input(f'{Color.white}--> @{Color.green}owner{Color.white} (username){Color.reset} ')
response = requests.get(f'https://api.github.com/repos/{username}/{repo_name}/forks')
if response.status_code == 404:
print(f"{Attributes.negative} Repository or user {response.json()['message']}{Color.reset}")
elif response.json() == {}:
print(f'{Attributes.negative} Repository does not have forks.{Color.reset}')
else:
for item in response.json():
print(f"\n{Color.white}{item['full_name']}{Color.reset}")
for attr in self.repo_attrs:
print(f'{Color.white}├─ {self.repo_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}')
# Repo releases
def repoReleases(self):
repo_name = input(f'\n{Color.white}--> %{Color.green}reponame{Color.reset} ')
username = input(f'{Color.white}--> @{Color.green}owner{Color.white} (username){Color.reset} ')
response = requests.get(f'https://api.github.com/repos/{username}/{repo_name}/releases')
if response.status_code == 404:
print(f"{Attributes.negative} Repository or user not found{Color.reset}")
elif response.json() == []:
print(f"\n{Attributes.negative} Repository does not have releases{Color.reset}")
else:
for item in response.json():
print(f"\n{Color.white}{item['name']}{Color.reset}")
for attr in self.repo_releases_attrs:
print(f'{Color.white}├─ {self.repo_releases_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}')
print(item['body'])
# Fetching organization repositories
def orgRepos(self):
organization = input(f'\n{Color.white}--> @{Color.green}organization{Color.white} (username){Color.reset} ')
response = requests.get(f'https://api.github.com/orgs/{organization}/repos?per_page=100')
if response.status_code == 404:
print(f"{Attributes.negative} Organization {response.json()['message']}{Color.reset}")
else:
for repo in response.json():
print(f"\n{Color.white}{repo['full_name']}{Color.reset}")
for attr in self.repo_attrs:
print(f"{Color.white}├─ {self.repo_attr_dict[attr]}: {Color.green}{repo[attr]}{Color.reset}")
# organization events
def orgEvents(self):
organization = input(f"\n{Color.white}--> @{Color.green}organization{Color.white} (username){Color.reset} ")
response = requests.get(f'https://api.github.com/orgs/{organization}/events')
if response.status_code == 404:
print(f"{Attributes.negative} Organization {response.json()['message']}{Color.reset}")
else:
for item in response.json():
print(f"\n{Color.white}{item['id']}{Color.reset}")
print(f"{Color.white}├─ Type: {Color.green}{item['type']}{Color.reset}\n{Color.white}├─ Created at: {Color.green}{item['created_at']}{Color.green}")
pprint(item['payload'])
print(f"{Color.reset}\n")
# organization member
def orgMember(self):
organization = input(f"\n{Color.white}--> @{Color.green}organization{Color.white} (username){Color.reset} ")
username = input(f'{Color.white}--> @{Color.green}username{Color.reset} ')
response = requests.get(f'https://api.github.com/orgs/{organization}/public_members/{username}')
if response.status_code == 204:
print(f"{Attributes.positive} User is a public member of the organization{Color.reset}")
else:
print(f"{Attributes.negative} {response.json()['message']}{Color.reset}")
# Fetching user repositories
def userRepos(self):
username = input(f'\n{Color.white}--> @{Color.green}username{Color.reset} ')
response = requests.get(f'https://api.github.com/users/{username}/repos?per_page=100')
if response.status_code == 404:
print(f"{Attributes.negative} User {response.json()['message']}{Color.reset}")
else:
for repo in response.json():
print(f"\n{Color.white}{repo['full_name']}{Color.reset}")
for attr in self.repo_attrs:
print(f"{Color.white}├─ {self.repo_attr_dict[attr]}: {Color.green}{repo[attr]}{Color.reset}")
# Fetching user's gists
def userGists(self):
username = input(f'\n{Color.white}--> @{Color.green}username{Color.reset} ')
response = requests.get(f'https://api.github.com/users/{username}/gists')
if response.json() == []:
print(f'{Attributes.negative} User does not have any active gists{Color.reset}')
elif response.status_code == 404:
print(f"{Attributes.negative} User {response.json()['message']}{Color.reset}")
else:
for item in response.json():
print(f"\n{Color.white}{item['id']}{Color.reset}")
for attr in self.gists_attrs:
print(f"{Color.white}├─ {self.gists_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}")
# Fetching a list of organizations that a user owns or belongs to
def userOrgs(self):
username = input(f'\n{Color.white}--> @{Color.green}username{Color.reset} ')
response = requests.get(f'https://api.github.com/users/{username}/orgs')
if response.json() == []:
print(f'{Attributes.negative} User does not belong to or own any organizations.{Color.reset}')
elif response.status_code == 404:
print(f"{Attributes.negative} User {response.json()['message']}{Color.reset}")
else:
for item in response.json():
print(f'\n{Color.white}{item["login"]}{Color.reset}')
for attr in self.user_orgs_attrs:
print(f'{Color.white}├─ {self.user_orgs_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}')
# Fetching a users events
def userEvents(self):
username = input(f'\n{Color.white}--> @{Color.green}username{Color.reset} ')
response = requests.get(f'https://api.github.com/users/{username}/events/public')
if response.status_code == 404:
print(f"{Attributes.negative} User {response.json()['message']}{Color.reset}")
else:
for item in response.json():
print(f"\n{Color.white}{item['id']}{Color.reset}")
print(f"{Color.white}├─ Type: {Color.green}{item['type']}{Color.reset}\n{Color.white}├─ Created at: {Color.green}{item['created_at']}{Color.green}")
pprint(item['payload'])
print(reset)
# Fetching a target user's subscriptions
def userSubscriptions(self):
username = input(f'\n{Color.white}--> @{Color.green}username{Color.reset} ')
response = requests.get(f'https://api.github.com/users/{username}/subscriptions')
if response.json() == []:
print(f"{Attributes.negative} User does not have any subscriptions.{Color.reset}")
elif response.status_code == 404:
print(f"{Attributes.negative} User {response.json()['message']}{Color.reset}")
else:
for item in response.json():
print(f"\n{Color.white}{item['full_name']}{Color.reset}")
for attr in self.repo_attrs:
print(f"{Color.white}├─ {self.repo_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}")
# Fetching user's followera'
def userFollowers(self):
username = input(f'\n{Color.white}--> @{Color.green}username{Color.reset} ')
response = requests.get(f'https://api.github.com/users/{username}/followers?per_page=100')
if response.json() == []:
print(f'{Attributes.negative} User does not have followers.{Color.reset}')
elif response.status_code == 404:
print(f"{Attributes.negative} User {response.json()['message']}{Color.reset}")
else:
for item in response.json():
print(f"\n{Color.white}@{item['login']}{Color.reset}")
for attr in self.user_attrs:
print(f"{Color.white}├─ {self.user_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}")
# Checking whether or not user[A] follows user[B]
def userFollowing(self):
user_a = input(f'\n{Color.white}--> @{Color.green}user{Color.white}[A] (username){Color.reset} ')
user_b = input(f'{Color.white}--> @{Color.green}user{Color.white}[B] (username){Color.reset} ')
response = requests.get(f'https://api.github.com/users/{user_a}/following/{user_b}')
if response.status_code == 204:
print(f'{Attributes.positive} @{user_a} follows @{user_b}{Color.reset}')
else:
print(f'{Attributes.negative} @{user_a} does not follow @{user_b}{Color.reset}')
# User search
def userSearch(self):
query = input(f'\n{Color.white}--> @{Color.green}query{Color.white} (eg. john){Color.reset} ')
response = requests.get(f'https://api.github.com/search/users?q={query}&per_page=100').json()
for item in response['items']:
print(f"\n{Color.white}@{item['login']}{Color.reset}")
for attr in self.user_attrs:
print(f"{Color.white}├─ {self.user_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}")
# Repository search
def repoSearch(self):
query = input(f'\n{Color.white}--> %{Color.green}query{Color.white} (eg. git){Color.reset} ')
response = requests.get(f'https://api.github.com/search/repositories?q={query}&per_page=100').json()
for item in response['items']:
print(f"\n{Color.white}{item['full_name']}{Color.reset}")
for attr in self.repo_attrs:
print(f"{Color.white}├─ {self.repo_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}")
# Topics search
def topicSearch(self):
query = input(f'\n{Color.white}--> #{Color.green}query{Color.white} (eg. osint){Color.reset} ')
response = requests.get(f'https://api.github.com/search/topics?q={query}&per_page=100').json()
for item in response['items']:
print(f"\n{Color.white}{item['name']}{Color.reset}")
for attr in self.topic_attrs:
print(f"{Color.white}├─ {self.topic_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}")
# Issue search
def issueSearch(self):
query = input(f'\n{Color.white}--> !{Color.green}query{Color.white} (eg. error){Color.reset} ')
response = requests.get(f'https://api.github.com/search/issues?q={query}&per_page=100').json()
for item in response['items']:
print(f"\n{Color.white}{item['title']}{Color.reset}")
for attr in self.issue_attrs:
print(f"{Color.white}├─ {self.issue_attr_dict[attr]}: {Color.green}{item[attr]}{Color.reset}")
# Commits search
def commitsSearch(self):
query = input(f'\n{Color.white}--> :{Color.green}query{Color.white} (eg. filename:index.php){Color.reset} ')
response = requests.get(f'https://api.github.com/search/commits?q={query}&per_page=100').json()
number=0
for item in response['items']:
number+=1
print(f'\n{Color.white}-> {number}.{Color.reset}')
pprint(item['commit'])
# View octosuite log files
def viewLogs(self):
logging.info(logMsg.viewingLogs)
logs = os.listdir('.logs')
print(f'''\n{Color.white}Log Size{Color.reset}
--- ---------''')
for log in logs:
print(f"{log}\t ",os.path.getsize(".logs/"+log),"bytes")
# Delete a specified log file
def deleteLog(self):
log_file = input(f"\n{Color.white}--> logfile (eg. 2022-04-27 10:09:36AM.log){Color.reset} ")
if sys.platform.lower().startswith(('win','darwin')):
subprocess.run(['del',f'{os.getcwd()}/.logs/{log_file}'])
else:
subprocess.run(['sudo','rm',f'.logs/{log_file}'],shell=False)
logging.info(logMsg.fileDeleted.format(log_file))
print(Attributes.positive, logMsg.fileDeleted)
# Read a specified log file
def readLog(self):
log_file = input(f"\n{Color.white}--> logfile (eg. 2022-04-27 10:09:36AM.log){Color.reset} ")
with open(f'.logs/{log_file}', 'r') as log:
logging.info(logMsg.readingFile.format(log_file))
print("\n"+log.read())
# Update program
def installUpdate(self):
files_to_update = ['core/main.py','utils/helper.py','utils/misc.py','utils/colors.py','utils/changelog.py','octosuite','.github/dependabot.yml','.github/ISSUE_TEMPLATE/bug_report.md','.github/ISSUE_TEMPLATE/feature_request.md','.github/ISSUE_TEMPLATE/config.yml','LICENSE','README.md','requirements.txt']
logging.info(logMsg.installingUpdates)
for file in tqdm(files_to_update,desc = logMsg.installingUpdates):
data = requests.get(f'https://raw.githubusercontent.com/rly0nheart/octosuite/master/{file}')
with open(file, 'wb') as code:
code.write(data.content)
code.close()
logging.info(logMsg.installedUpdates.format(len(files_to_update)))
print(Attributes.positive, logMsg.installedUpdates.format(len(files_to_update)));exit()
def checkUpdate(self):
logging.info(logMsg.checkingUpdates)
response = requests.get("https://api.github.com/repos/rly0nheart/octosuite/releases/latest")
if response.json()['tag_name'] == Banner.versionTag:
print(f"{Attributes.positive} OctoSuite is up to date. Check again soon :)")
else:
print(f"{Attributes.info} A new release is available ({response.json()['tag_name']}). Use command {Color.green}update:install{Color.white} to download and install the updates.{Color.reset}")
# Show version information
def versionInfo(self):
# Yes... the changelog is actually hard coded
# It's actually frustrating having to change this everytime I publish a new release lol
print(f'''
Tag: {Banner.versionTag}
Released at: 2022-05-20 03:26AM
{'-'*31}
What's changed?
{'-'*15}
[✓] The PyPI package has been deprecated and will no longer receive any further updates
[✓] Added a functionality for returning organizations belonging to a target user (user:orgs)
[✓] Added a functionality for returning a target user's subscriptions (user:subscriptions)
[✓] Added a functionality for returning a target user's events (user:events)
[✓] Added a functionality for returning a list of contributors of a repository (repo:contributors)
[✓] Added a functionality for returning languages of a repository (repo:languages)
[✓] Added a functionality for returning stargazers of a repository (repo:stargazers)
[✓] Added a functionality for returning forks of a repository (repo:forks)
[✓] Added a functionality for checking for latest releases of Octosuite (update:check)
[✓] Added the "clear" command for clearing the screen in the Octosuite command prompt
[✓] Moved the use of the 'update' comnand to 'update:install'
[✓] Will no longer show the "Press any key to continue" prompt, it will instead return its command prompt
[✓] Commands are no longer case sensitive
[✓] Major perfomance improvements''')
# Author info
def author(self):
print(f'\n{Color.white}Richard Mwewa (Ritchie){Color.reset}')
for key,value in self.author_dict.items():
print(f'{Color.white}├─ {key}: {Color.green}{value}{Color.reset}')
def about(self):
print('''
OCTOSUITE (C) 2022 Richard Mwewa
is an advanced and lightning fast framework for gathering open-source intelligence on GitHub users and organizations.''')
# Close session
def exitSession(self):
logging.info(logMsg.sessionClosed)
print(Attributes.info, logMsg.sessionClosed);exit()
def clearScreen(self):
if sys.platform.lower().startswith(('win','darwin')):
subprocess.run(['cls'])
else:
subprocess.run(['clear'],shell=False)

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

BIN
images/octosuite_app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
images/octosuite_app1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
images/octosuite_exe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

View File

@@ -1,19 +0,0 @@
#!/usr/bin/env python3
import logging
from utils.colors import Color
from utils.misc import Banner
from core.main import Octosuite, Attributes, logMsg
print(Banner.nameLogo)
if __name__ == '__main__':
try:
Octosuite().onStart()
except KeyboardInterrupt:
logging.warning(logMsg.Ctrl)
print(Attributes.warning, logMsg.Ctrl)
except Exception as e:
logging.error(logMsg.Error.format(e))
print(Attributes.error, logMsg.Exception.format(f'{Color.red}{e}{Color.reset}'))

1
octosuite/__init__.py Normal file
View File

@@ -0,0 +1 @@

23
octosuite/banner.py Normal file
View File

@@ -0,0 +1,23 @@
import getpass
from octosuite.config import red, white, green, reset, Tree
# banner.py
# This file holds the program's banner and version tag
version_tag = "3.0.1"
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}#dev
{white}— Advanced Github {red}OSINT{white} Framework
""", banner_tree

200
octosuite/config.py Normal file
View File

@@ -0,0 +1,200 @@
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.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 Organi[sz]ation Profile Info
-----------------------------
octosuite --method org_profile --organization <organization_name>
Get Organi[sz]ation Repos
-----------------------------
octosuite --method org_repos --organization <organization_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_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', '--organization', '--organisation', help='organi[sz]ation 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
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.")

442
octosuite/csv_loggers.py Normal file
View File

@@ -0,0 +1,442 @@
import os
import csv
import logging
from rich import print as xprint
from octosuite.log_roller import prompt_log_csv, logged_to_csv
from octosuite.message_prefixes import PROMPT, WARNING, POSITIVE, NEGATIVE, INFO
# csv_loggers.py
# This file holds the functions for creating .csv files of each functionality in main
def log_org_profile(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']]
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))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Creating a .csv file of a user' profile
def log_user_profile(response):
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']
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']]
with open(os.path.join("output", f"{response.json()['login']}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(user_profile_fields)
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 path contents
def log_repo_path_contents(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']]
with open(os.path.join("output", f"{content['name']}_content_from_{repo_name}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(path_content_fields)
write_csv.writerow(path_content_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# create .csv for repository stargazer
def log_repo_stargazers(stargazer, repo_name):
user_follower_fields = ['Profile photo', 'Username', 'ID', 'Node ID', 'Gravatar ID', 'Account type',
'Is site admin?', 'URL']
user_follower_row = [stargazer['avatar_url'], stargazer['login'], stargazer['id'], stargazer['node_id'],
stargazer['gravatar_id'], stargazer['type'], stargazer['site_admin'], stargazer['html_url']]
with open(os.path.join("output", f"{stargazer['login']}_stargazer_of_{repo_name}.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)}")
# create .csv for repository forks
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 issues
def log_repo_issues(issue, 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']
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']]
with open(os.path.join("output", f"{repo_name}_issue_{issue['id']}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(repo_issue_fields)
write_csv.writerow(repo_issue_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# create .csv for repository releases
def log_repo_releases(release, repo_name):
repo_release_fields = ['Name', 'ID', 'Node ID', 'Tag', 'Branch', 'Assets', 'Is draft?', 'Is prerelease?',
'Created at', 'Published at']
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']]
with open(os.path.join("output", f"{repo_name}_release_{release['name']}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(repo_release_fields)
write_csv.writerow(repo_release_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv file for repository contributors
def log_repo_contributors(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']]
with open(os.path.join("output", f"{contributor['login']}_contributor_of_{repo_name}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(repo_contributor_fields)
write_csv.writerow(repo_contributor_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv for organization' events
def log_repo_events(event, organization):
org_event_fields = ['ID', 'Type', 'Created at', 'Payload']
org_event_row = [event['id'], event['type'], event['created_at'], event['payload']]
with open(os.path.join("output", f"{organization}_event_{event['id']}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(org_event_fields)
write_csv.writerow(org_event_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# Create .csv for organization' repositories
def log_org_repos(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']]
with open(os.path.join("output", f"{repository['name']}_repository_of_{organization}.csv"), 'w') as file:
write_csv = csv.writer(file)
write_csv.writerow(org_repo_fields)
write_csv.writerow(org_repo_row)
logging.info(logged_to_csv.format(file.name))
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
# .csv for user' repositories
def log_user_repos(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']]
with open(os.path.join("output", f"{repository['name']}_{username}.csv"), 'w') as file:
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 organizations
def log_user_orgs(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']]
with open(os.path.join("output", f"{organization['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)}")

170
octosuite/helper.py Normal file
View File

@@ -0,0 +1,170 @@
from rich.table import Table
from octosuite.config import Tree, xprint, white, green, white_bold, green_bold, header_title, reset
# helper.py
# This file holds the help text for available commands.
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 org():
xprint(usage_text_2.format(f"{green_bold}org{reset}") + usage_text_1.format(f"{green_bold}help:org{reset}"))
def repo():
xprint(usage_text_2.format(f"{green_bold}repo{reset}") + usage_text_1.format(f"{green_bold}help:repo{reset}"))
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("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"{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 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"{usage_text.format(syntax, 'organization 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 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)")
syntax = f"{green}help:<command>{reset}"
xprint(core_cmd_table)
xprint(f"\n\n{usage_text.format(syntax, 'octosuite')}")
xprint(help_sub_cmd_table)

21
octosuite/log_roller.py Normal file
View File

@@ -0,0 +1,21 @@
# LogRoller This class is where the main notification strings/messages are held, and are being used in two different
# cases (they're being used by logging to be written to log files, and being printed out to the screen).
ctrl_c = "Session terminated with Ctrl+C."
error = "An error occurred: {}"
session_opened = "Opened new session on {}:{}"
session_closed = "Session closed at {}."
viewing_logs = "Viewing logs"
viewing_csv = "Viewing CSV file(s)..."
deleted = "Deleted: {}"
reading = "Reading: {}"
file_downloading = "Downloading: {}"
file_downloaded = "Downloaded: downloads/{}"
info_not_found = "Information not found: {}, {}, {}"
user_not_found = "User not found: @{}"
org_not_found = "Organization not found: @{}"
repo_or_user_not_found = "Repository or User not found: {}, @{}"
prompt_log_csv = "Would you like to log this output to a .csv file?"
logged_to_csv = "Output logged: {}"
limit_output = "Limit '{}' output to how many? (1-100)"

52
octosuite/main.py Normal file
View File

@@ -0,0 +1,52 @@
# import everything from the octosuite.py file
from octosuite.octosuite import * # I drifted away from the 'pythonic way' here
def octosuite():
try:
run = Octosuite()
path_finder()
configure_logging()
check_updates()
if args.method:
"""
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).
"""
for argument, method in run.argument_map:
if args.method == argument:
method()
print("\n")
else:
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
except KeyboardInterrupt:
logging.warning(ctrl_c)
xprint(f"\n{WARNING} {ctrl_c}")
except Exception as e:
logging.error(error.format(e))
xprint(f"{ERROR} {error.format(e)}")

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}"

1110
octosuite/octosuite.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
tqdm
requests

31
setup.py Normal file
View File

@@ -0,0 +1,31 @@
import setuptools
with open("README.md", "r", encoding="utf-8") as file:
long_description = file.read()
setuptools.setup(
name="octosuite",
version="3.0.1",
author="Richard Mwewa",
author_email="rly0nheart@duck.com",
packages=["octosuite"],
description="Advanced Github OSINT Framework",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/bellingcat/octosuite",
license="GNU General Public License v3 (GPLv3)",
install_requires=["requests", "rich", "psutil", "pyreadline3"],
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:octosuite",
]
},
)

View File

@@ -1,57 +0,0 @@
import os
import sys
import platform
from datetime import datetime
# The Color class is responsible for enabling/disabling colors in OctoSuite
# This class gets called first at start up before any other class/method gets called (makes one think why this is not the firstBlood class)
# Color class is the reason why users get to choose whether to enable/disable colors
# Unfortunately for our friends the 'non-Linux' users, they will not yet have the opportunity to see what OctoSuite looks like with colors enabled lol
class Color:
colors = True
# Colors will be unavailable on non-linux machines
if sys.platform.lower().startswith(("os", "win", "darwin","ios")):
colors = False
if not colors:
reset = red = white = green = red_bg = ""
else:
# Printing system information was completely unnecessary (just like most things in this program :D)
# But at least users will get to know things they did not know about their machines ;)
date_time = datetime.now()
sys_info = [("Processor",platform.processor),
("Node", platform.node),
("Release", platform.release),
("Architecture", platform.architecture),
("Version", platform.version)]
banner = f"""
OCTOSUITE © 2022 Richard Mwewa
{date_time.strftime('%A %d %B %Y, %H:%M:%S%p')}
{platform.system()}"""
print(banner)
for key, value in sys_info:
print(f"\t├─ {key}: {value()}")
print("\n")
while True:
try:
color_chooser = input(f"[ ? ] Welcome {os.getlogin()}, would you like to enable colors for this session? (y/n) ")
if color_chooser.lower() == "y":
white = "\033[97m"
red = "\033[91m"
reset = "\033[0m"
green = "\033[92m"
red_bg = "\033[41;37m"
break
elif color_chooser.lower() == "n":
red = white = green = red_bg = 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).")

View File

@@ -1,118 +0,0 @@
from utils.colors import Color
class Help:
usageText = 'Use {} to get started'
def updateCommand():
print(f'''
{Color.white}Update subcommands{Color.reset}
{'='*18}
{Help.usageText.format('update:<subcommand>')}
Command Description
------- -----------
check Check for updates
install Download and install updates''')
def searchCommand():
print(f'''
{Color.white}Search subcommands{Color.reset}
{'='*18}
{Help.usageText.format('search:<subcommand>')}
Command Description
------- -----------
users Search user(s)
repos Search repositor[yies]
topics Search topic(s)
issues Search issue(s)
commits Search commit(s)''')
def userCommand():
print(f'''
{Color.white}User subcommands{Color.reset}
{'='*17}
{Help.usageText.format('user:<subcommand>')}
Command Description
------- -----------
profile Get a user's profile info
gists Return a users's gists
orgs Return organizations that a user belongs to/owns
repos Return a user's repositories
events Return a user's events
followers Return a user's followers
following Check if user[A] follows user[B]
subscriptions Return a user's subscriptions''')
def orgCommand():
print(f'''
{Color.white}Org subcommands{Color.reset}
{'='*16}
{Help.usageText.format('org:<subcommand>')}
Command Description
------- -----------
profile Get an organization's info
repos Return an organization's repositories
events Return an organization's events
member Check if a specified user is a public member of the target organization''')
def repoCommand():
print(f'''
{Color.white}Repo subcommands{Color.reset}
{'='*17}
{Help.usageText.format('repo:<subcommand>')}
Command Description
------- -----------
profile Get a repository's info
forks Return a repository's forks
releases Return a repository's releases
languages Return a repository's languages
stargazers Return a repository's stargazers
pathcontents List contents in a path of a repository''')
def logsCommand():
print(f'''
{Color.white}Logs subcommands{Color.reset}
{'='*17}
{Help.usageText.format('logs:<subcommand>')}
Command Description
------- -----------
view View logs
read Read log
delete Delete log''')
def helpCommand():
print(f'''
{Color.white}Core commands{Color.reset}
{'='*13}
{Color.white}Command Description{Color.reset}
------- -----------
help Help menu
exit Close session
clear Clear screen
about Program's info
author Developer's info
version Version info
{Color.white}Help subcommands{Color.reset}
{'='*16}
{Help.usageText.format('help:<subcommand>')}
{Color.white}Command Description{Color.reset}
------- -----------
logs List all logs management commands
repo List all repository investigation commands
user List all users investigation commands
search List all target discovery commands
update List all program updates managememt commands''')

View File

@@ -1,20 +0,0 @@
import os
from utils.colors import Color
class Banner:
versionTag = '2.0.0-beta'
nameLogo = f'''{Color.white}
_______ __ _______ __ __
| |.----.| |_.-----.| __|.--.--.|__| |_.-----.
| - || __|| _| _ ||__ || | || | _| -__|
|_______||____||____|_____||_______||_____||__|____|_____|
v{versionTag}
{Color.white}— Advanced Github {Color.red}OSINT{Color.white} Framework{Color.reset}
.:{Color.white}{Color.green}{os.getlogin()}{Color.reset}:.
- {Color.white}Use {Color.green}help{Color.reset}{Color.white} command for usage{Color.reset}
- {Color.white}Commands are case insensitive{Color.reset}
{'-'*32}
'''