Skip to content

Commit 8a4323c

Browse files
authored
feat: improve authentication (#733)
* improve: authenticate early for upload commands * provide an interactive way to choose user profile * add a nice banner * make sure all prints going to stderr * print existing profiles * prompt to stderr * validate profile name * disable prompt when the ENV is set * fix the test cli * handle invalid tokens * call authenticate directly * wip * add tests * update * introduce env MAPILLARY_TOOLS__DISABLE_AUTH_VERIFICATION * update banner
1 parent d2efc74 commit 8a4323c

File tree

12 files changed

+628
-237
lines changed

12 files changed

+628
-237
lines changed

mapillary_tools/api_v4.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def _truncate(s, limit=512):
7070
return s
7171

7272

73-
def _sanitize(headers: T.Dict):
73+
def _sanitize(headers: T.Mapping[T.Any, T.Any]) -> T.Mapping[T.Any, T.Any]:
7474
new_headers = {}
7575

7676
for k, v in headers.items():
@@ -81,6 +81,7 @@ def _sanitize(headers: T.Dict):
8181
"access-token",
8282
"access_token",
8383
"password",
84+
"user_upload_token",
8485
]:
8586
new_headers[k] = "[REDACTED]"
8687
else:
@@ -224,6 +225,44 @@ def request_get(
224225
return resp
225226

226227

228+
def is_auth_error(resp: requests.Response) -> bool:
229+
if resp.status_code in [401, 403]:
230+
return True
231+
232+
if resp.status_code in [400]:
233+
try:
234+
error_body = resp.json()
235+
except Exception:
236+
error_body = {}
237+
238+
type = error_body.get("debug_info", {}).get("type")
239+
if type in ["NotAuthorizedError"]:
240+
return True
241+
242+
return False
243+
244+
245+
def extract_auth_error_message(resp: requests.Response) -> str:
246+
assert is_auth_error(resp), "has to be an auth error"
247+
248+
try:
249+
error_body = resp.json()
250+
except Exception:
251+
error_body = {}
252+
253+
# from Graph APIs
254+
message = error_body.get("error", {}).get("message")
255+
if message is not None:
256+
return str(message)
257+
258+
# from upload service
259+
message = error_body.get("debug_info", {}).get("message")
260+
if message is not None:
261+
return str(message)
262+
263+
return resp.text
264+
265+
227266
def get_upload_token(email: str, password: str) -> requests.Response:
228267
resp = request_post(
229268
f"{MAPILLARY_GRAPH_API_ENDPOINT}/login",
@@ -252,6 +291,30 @@ def fetch_organization(
252291
return resp
253292

254293

294+
def fetch_user_or_me(
295+
user_access_token: str,
296+
user_id: T.Optional[T.Union[int, str]] = None,
297+
) -> requests.Response:
298+
if user_id is None:
299+
url = f"{MAPILLARY_GRAPH_API_ENDPOINT}/me"
300+
else:
301+
url = f"{MAPILLARY_GRAPH_API_ENDPOINT}/{user_id}"
302+
303+
resp = request_get(
304+
url,
305+
params={
306+
"fields": ",".join(["id", "username"]),
307+
},
308+
headers={
309+
"Authorization": f"OAuth {user_access_token}",
310+
},
311+
timeout=REQUESTS_TIMEOUT,
312+
)
313+
314+
resp.raise_for_status()
315+
return resp
316+
317+
255318
ActionType = T.Literal[
256319
"upload_started_upload", "upload_finished_upload", "upload_failed_upload"
257320
]

0 commit comments

Comments
 (0)