Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mxrch
GitHub Repository: mxrch/GHunt
Path: blob/master/ghunt/modules/drive.py
252 views
1
import os
2
3
from ghunt.helpers.utils import *
4
from ghunt.objects.base import DriveExtractedUser, GHuntCreds
5
from ghunt.apis.drive import DriveHttp
6
from ghunt.apis.clientauthconfig import ClientAuthConfigHttp
7
from ghunt import globals as gb
8
from ghunt.helpers import auth
9
from ghunt.helpers.drive import get_comments_from_file, get_users_from_file
10
from ghunt.knowledge import drive as drive_knownledge
11
12
import httpx
13
import inflection
14
import humanize
15
16
import inspect
17
from typing import *
18
from datetime import timedelta
19
20
21
def show_user(user: DriveExtractedUser):
22
if user.name:
23
print(f"Full name : {user.name}")
24
else:
25
gb.rc.print("Full name : -", style="bright_black")
26
print(f"Email : {user.email_address}")
27
if user.gaia_id:
28
print(f"Gaia ID : {user.gaia_id}")
29
else:
30
gb.rc.print("Gaia ID : -", style="bright_black")
31
if user.is_last_modifying_user:
32
print("[+] Last user to have modified the document !")
33
34
async def hunt(as_client: httpx.AsyncClient, file_id: str, json_file: bool=Path):
35
if not as_client:
36
as_client = get_httpx_client()
37
38
ghunt_creds = await auth.load_and_auth(as_client)
39
40
drive = DriveHttp(ghunt_creds)
41
file_found, file = await drive.get_file(as_client, file_id)
42
if not file_found:
43
print("[-] The file wasn't found.")
44
exit(os.EX_IOERR)
45
46
is_folder = file.mime_type == "application/vnd.google-apps.folder"
47
file_type = drive_knownledge.mime_types.get(file.mime_type)
48
49
#gb.rc.print(f"[+] {'Folder' if is_folder else 'File'} found !", style="sea_green3")
50
51
gb.rc.print("šŸ—ƒļø Drive properties\n", style="deep_pink4")
52
53
print(f"Title : {file.title}")
54
print(f"{'Folder' if is_folder else 'File'} ID : {file.id}")
55
if file.md5_checksum:
56
print(f"MD5 Checksum : {file.md5_checksum}")
57
if file.file_size:
58
print(f"{'Folder' if is_folder else 'File'} size : {humanize.naturalsize(file.file_size)}")
59
60
if file_type:
61
gb.rc.print(f"\nType : {file_type} [italic]\[{file.mime_type}][/italic]")
62
else:
63
print(f"\nMime Type : {file.mime_type}")
64
if is_folder:
65
print(f"Folder link :\n=> {file.alternate_link}")
66
else:
67
print(f"Download link :\n=> {file.alternate_link}")
68
69
print(f"\n[+] Created date : {file.created_date.strftime('%Y/%m/%d %H:%M:%S (UTC)')}")
70
print(f"[+] Modified date : {file.modified_date.strftime('%Y/%m/%d %H:%M:%S (UTC)')}")
71
72
for perm in file.permissions:
73
if perm.id == "anyoneWithLink":
74
giving_roles = [perm.role.upper()] + [x.upper() for x in perm.additional_roles if x != perm.role]
75
print(f"\n[+] Sharing with link enabled ! Giving the role{'s' if len(giving_roles) > 1 else ''} {humanize_list(giving_roles)}.")
76
77
#print("\n[Source application]")
78
gb.rc.print("\nšŸ“± Source application\n", style="deep_pink2")
79
brand_found = False
80
brand = None
81
if file.source_app_id:
82
print(f"App ID : {file.source_app_id}")
83
cac = ClientAuthConfigHttp(ghunt_creds)
84
brand_found, brand = await cac.get_brand(as_client, file.source_app_id)
85
if brand_found:
86
print(f"Name : {brand.display_name}")
87
if brand.home_page_url:
88
print(f"Home page : {brand.home_page_url}")
89
else:
90
gb.rc.print(f"Home page : [italic][bright_black]Not found.[/italic][/bright_black]")
91
else:
92
gb.rc.print("Not found.", style="italic")
93
else:
94
gb.rc.print("No source application.", style="italic")
95
96
if file.image_media_metadata.height and file.image_media_metadata.width:
97
#print("\n[Image metadata]")
98
gb.rc.print("\nšŸ“ø Image metadata\n", style="light_coral")
99
print(f"Height : {file.image_media_metadata.height}")
100
print(f"Width : {file.image_media_metadata.width}")
101
if isinstance((data := file.image_media_metadata.rotation), int):
102
print(f"Rotation : {data}")
103
104
if file.video_media_metadata.height and file.video_media_metadata.width:
105
#print("\n[Video metadata]")
106
gb.rc.print("\nšŸ“ø Video metadata\n", style="light_coral")
107
print(f"Height : {file.video_media_metadata.height}")
108
print(f"Width : {file.video_media_metadata.width}")
109
if (data := file.video_media_metadata.duration_millis):
110
duration = timedelta(milliseconds=int(file.video_media_metadata.duration_millis))
111
print(f"Duration : {humanize.precisedelta(duration)}")
112
113
#print("\n[Parents]")
114
gb.rc.print("\nšŸ“‚ Parents\n", style="gold3")
115
if file.parents:
116
print(f"[+] Parents folders :")
117
for parent in file.parents:
118
print(f"- šŸ“ {parent.id}{' [Root folder]' if parent.is_root else ''}")
119
else:
120
gb.rc.print("No parent folder found.", style="italic")
121
122
if is_folder:
123
#print("\n[Items]")
124
gb.rc.print("\nšŸ—ƒļø Items\n", style="gold3")
125
found, _, drive_childs = await drive.get_childs(as_client, file_id)
126
if found and drive_childs.items:
127
count = f"{x if (x := len(drive_childs.items)) < 1000 else '>= 1000'}"
128
print(f"[+] {count} items found inside this folder !")
129
else:
130
gb.rc.print("No items found.", style="italic")
131
132
#print("\n[Users]")
133
gb.rc.print("\nšŸ‘Ŗ Users\n", style="dark_orange")
134
users = get_users_from_file(file)
135
if (owners := [x for x in users if x.role == "owner"]):
136
print(f"-> šŸ‘¤ Owner{'s' if len(owners) > 1 else ''}")
137
for user in owners:
138
show_user(user)
139
140
if (writers := [x for x in users if x.role == "writer"]):
141
print(f"\n-> šŸ‘¤ Writer{'s' if len(writers) > 1 else ''}")
142
for user in writers:
143
show_user(user)
144
145
if (commenters := [x for x in users if x.role == "commenter"]):
146
print(f"\n-> šŸ‘¤ Commenter{'s' if len(commenters) > 1 else ''}")
147
for user in commenters:
148
show_user(user)
149
150
if (readers := [x for x in users if x.role == "reader"]):
151
print(f"\n-> šŸ‘¤ Reader{'s' if len(readers) > 1 else ''}")
152
for user in readers:
153
show_user(user)
154
155
if (nones := [x for x in users if x.role == "none"]):
156
print(f"\n-> šŸ‘¤ User{'s' if len(nones) > 1 else ''} with no right")
157
for user in nones:
158
show_user(user)
159
160
#print("[Comments]")
161
gb.rc.print("\nšŸ—£ļø Comments\n", style="plum2")
162
comments_found, _, drive_comments = await drive.get_comments(as_client, file_id)
163
if comments_found and drive_comments.items:
164
authors = get_comments_from_file(drive_comments)
165
if len(drive_comments.items) > 20:
166
print(f"[+] Authors ({len(authors)} found, showing the top 20) :")
167
else:
168
print("[+] Authors :")
169
for _, author in authors[:20]:
170
print(f"- šŸ™‹ {author['name']} ({author['count']} comment{'s' if author['count'] > 1 else ''})")
171
else:
172
gb.rc.print("No comments.", style="italic")
173
174
#print("\n[Capabilities]")
175
gb.rc.print("\nšŸ§™ Capabilities\n", style="dodger_blue1")
176
capabilities = sorted([k for k,v in inspect.getmembers(file.capabilities) if v and not k.startswith("_")])
177
if is_folder:
178
if capabilities == drive_knownledge.default_folder_capabilities:
179
print("[-] You don't have special permissions against this folder.")
180
else:
181
print(f"[+] You have special permissions against this folder ! ✨")
182
for cap in capabilities:
183
print(f"- {inflection.humanize(cap)}")
184
else:
185
if capabilities == drive_knownledge.default_file_capabilities:
186
print("[-] You don't have special permissions against this file.")
187
else:
188
print(f"[+] You have special permissions against this file ! ✨")
189
for cap in capabilities:
190
print(f"- {inflection.humanize(cap)}")
191
192
if json_file:
193
json_results = {
194
"file": file if file_found else None,
195
"source_app": brand if brand_found else None,
196
"users": users,
197
"comments": drive_comments if comments_found else None
198
}
199
200
import json
201
from ghunt.objects.encoders import GHuntEncoder;
202
with open(json_file, "w", encoding="utf-8") as f:
203
f.write(json.dumps(json_results, cls=GHuntEncoder, indent=4))
204
gb.rc.print(f"\n[+] JSON output wrote to {json_file} !", style="italic")
205
206
await as_client.aclose()
207
208