Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mxrch
GitHub Repository: mxrch/GHunt
Path: blob/master/ghunt/parsers/people.py
252 views
1
from typing import *
2
from datetime import datetime
3
4
from ghunt.errors import *
5
from ghunt.helpers.utils import is_default_profile_pic, unicode_patch
6
from ghunt.objects.apis import Parser
7
8
import httpx
9
import imagehash
10
11
12
class PersonGplusExtendedData(Parser):
13
def __init__(self):
14
self.contentRestriction: str = ""
15
self.isEntrepriseUser: bool = False
16
17
def _scrape(self, gplus_data):
18
self.contentRestriction = gplus_data.get("contentRestriction")
19
20
if (isEnterpriseUser := gplus_data.get("isEnterpriseUser")):
21
self.isEntrepriseUser = isEnterpriseUser
22
23
class PersonDynamiteExtendedData(Parser):
24
def __init__(self):
25
self.presence: str = ""
26
self.entityType: str = ""
27
self.dndState: str = ""
28
self.customerId: str = ""
29
30
def _scrape(self, dynamite_data):
31
self.presence = dynamite_data.get("presence")
32
self.entityType = dynamite_data.get("entityType")
33
self.dndState = dynamite_data.get("dndState")
34
if (customerId := dynamite_data.get("organizationInfo", {}).get("customerInfo", {}).
35
get("customerId", {}).get("customerId")):
36
self.customerId = customerId
37
38
class PersonExtendedData(Parser):
39
def __init__(self):
40
self.dynamiteData: PersonDynamiteExtendedData = PersonDynamiteExtendedData()
41
self.gplusData: PersonGplusExtendedData = PersonGplusExtendedData()
42
43
def _scrape(self, extended_data: Dict[str, any]):
44
if (dynamite_data := extended_data.get("dynamiteExtendedData")):
45
self.dynamiteData._scrape(dynamite_data)
46
47
if (gplus_data := extended_data.get("gplusExtendedData")):
48
self.gplusData._scrape(gplus_data)
49
50
class PersonPhoto(Parser):
51
def __init__(self):
52
self.url: str = ""
53
self.isDefault: bool = False
54
self.flathash: str = None
55
56
async def _scrape(self, as_client: httpx.AsyncClient, photo_data: Dict[str, any], photo_type: str):
57
if photo_type == "profile_photo":
58
self.url = photo_data.get("url")
59
60
self.isDefault, self.flathash = await is_default_profile_pic(as_client, self.url)
61
62
elif photo_type == "cover_photo":
63
self.url = '='.join(photo_data.get("imageUrl").split("=")[:-1])
64
if (isDefault := photo_data.get("isDefault")):
65
self.isDefault = isDefault
66
else:
67
raise GHuntAPIResponseParsingError(f'The provided photo type "{photo_type}" weren\'t recognized.')
68
69
class PersonEmail(Parser):
70
def __init__(self):
71
self.value: str = ""
72
73
def _scrape(self, email_data: Dict[str, any]):
74
self.value = email_data.get("value")
75
76
class PersonName(Parser):
77
def __init__(self):
78
self.fullname: str = ""
79
self.firstName: str = ""
80
self.lastName: str = ""
81
82
def _scrape(self, name_data: Dict[str, any]):
83
# self.fullname = unicode_patch(x) if (x := name_data.get("displayName")) else None
84
# self.firstName = unicode_patch(x) if (x := name_data.get("givenName")) else None
85
# self.lastName = unicode_patch(x) if (x := name_data.get("familyName")) else None
86
pass # Google patched the names :/ very sad
87
88
class PersonProfileInfo(Parser):
89
def __init__(self):
90
self.userTypes: List[str] = []
91
92
def _scrape(self, profile_data: Dict[str, any]):
93
if "ownerUserType" in profile_data:
94
self.userTypes += profile_data.get("ownerUserType")
95
96
class PersonSourceIds(Parser):
97
def __init__(self):
98
self.lastUpdated: datetime = None
99
100
def _scrape(self, source_ids_data: Dict[str, any]):
101
if (timestamp := source_ids_data.get("lastUpdatedMicros")):
102
self.lastUpdated = datetime.utcfromtimestamp(float(timestamp[:10]))
103
104
class PersonInAppReachability(Parser):
105
def __init__(self):
106
self.apps: List[str] = []
107
108
def _scrape(self, apps_data, container_name: str):
109
for app in apps_data:
110
if app["metadata"]["container"] == container_name:
111
self.apps.append(app["appType"].title())
112
113
class PersonContainers(dict):
114
pass
115
116
class Person(Parser):
117
def __init__(self):
118
self.personId: str = ""
119
self.sourceIds: Dict[str, PersonSourceIds] = PersonContainers() # All the fetched containers
120
self.emails: Dict[str, PersonEmail] = PersonContainers()
121
self.names: Dict[str, PersonName] = PersonContainers()
122
self.profileInfos: Dict[str, PersonProfileInfo] = PersonContainers()
123
self.profilePhotos: Dict[str, PersonPhoto] = PersonContainers()
124
self.coverPhotos: Dict[str, PersonPhoto] = PersonContainers()
125
self.inAppReachability: Dict[str, PersonInAppReachability] = PersonContainers()
126
self.extendedData: PersonExtendedData = PersonExtendedData()
127
128
async def _scrape(self, as_client: httpx.AsyncClient, person_data: Dict[str, any]):
129
self.personId = person_data.get("personId")
130
if person_data.get("email"):
131
for email_data in person_data["email"]:
132
person_email = PersonEmail()
133
person_email._scrape(email_data)
134
self.emails[email_data["metadata"]["container"]] = person_email
135
136
if person_data.get("name"):
137
for name_data in person_data["name"]:
138
person_name = PersonName()
139
person_name._scrape(name_data)
140
self.names[name_data["metadata"]["container"]] = person_name
141
142
if person_data.get("readOnlyProfileInfo"):
143
for profile_data in person_data["readOnlyProfileInfo"]:
144
person_profile = PersonProfileInfo()
145
person_profile._scrape(profile_data)
146
self.profileInfos[profile_data["metadata"]["container"]] = person_profile
147
148
if person_data.get("photo"):
149
for photo_data in person_data["photo"]:
150
person_photo = PersonPhoto()
151
await person_photo._scrape(as_client, photo_data, "profile_photo")
152
self.profilePhotos[profile_data["metadata"]["container"]] = person_photo
153
154
if (source_ids := person_data.get("metadata", {}).get("identityInfo", {}).get("sourceIds")):
155
for source_ids_data in source_ids:
156
person_source_ids = PersonSourceIds()
157
person_source_ids._scrape(source_ids_data)
158
self.sourceIds[source_ids_data["container"]] = person_source_ids
159
160
if person_data.get("coverPhoto"):
161
for cover_photo_data in person_data["coverPhoto"]:
162
person_cover_photo = PersonPhoto()
163
await person_cover_photo._scrape(as_client, cover_photo_data, "cover_photo")
164
self.coverPhotos[cover_photo_data["metadata"]["container"]] = person_cover_photo
165
166
if (apps_data := person_data.get("inAppReachability")):
167
containers_names = set()
168
for app_data in person_data["inAppReachability"]:
169
containers_names.add(app_data["metadata"]["container"])
170
171
for container_name in containers_names:
172
person_app_reachability = PersonInAppReachability()
173
person_app_reachability._scrape(apps_data, container_name)
174
self.inAppReachability[container_name] = person_app_reachability
175
176
if (extended_data := person_data.get("extendedData")):
177
self.extendedData._scrape(extended_data)
178