sima-cli 0.0.29__py3-none-any.whl → 0.0.30__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sima_cli/__version__.py +1 -1
- sima_cli/auth/basic_auth.py +84 -23
- {sima_cli-0.0.29.dist-info → sima_cli-0.0.30.dist-info}/METADATA +1 -1
- {sima_cli-0.0.29.dist-info → sima_cli-0.0.30.dist-info}/RECORD +8 -8
- {sima_cli-0.0.29.dist-info → sima_cli-0.0.30.dist-info}/WHEEL +0 -0
- {sima_cli-0.0.29.dist-info → sima_cli-0.0.30.dist-info}/entry_points.txt +0 -0
- {sima_cli-0.0.29.dist-info → sima_cli-0.0.30.dist-info}/licenses/LICENSE +0 -0
- {sima_cli-0.0.29.dist-info → sima_cli-0.0.30.dist-info}/top_level.txt +0 -0
sima_cli/__version__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# sima_cli/__version__.py
|
2
|
-
__version__ = "0.0.
|
2
|
+
__version__ = "0.0.30"
|
sima_cli/auth/basic_auth.py
CHANGED
@@ -78,55 +78,116 @@ def _fetch_and_store_csrf_token(session: requests.Session) -> str:
|
|
78
78
|
|
79
79
|
|
80
80
|
def login_external():
|
81
|
-
"""Interactive login workflow with CSRF token, cookie caching, and
|
81
|
+
"""Interactive login workflow with CSRF token, cookie caching, and TOTP handling."""
|
82
82
|
for attempt in range(1, 4):
|
83
83
|
session = requests.Session()
|
84
84
|
session.headers.update(HEADERS)
|
85
85
|
|
86
86
|
_load_cookie_jar(session)
|
87
|
-
csrf_token = _load_csrf_token()
|
88
|
-
|
89
|
-
if not csrf_token:
|
90
|
-
csrf_token = _fetch_and_store_csrf_token(session)
|
91
|
-
|
87
|
+
csrf_token = _load_csrf_token() or _fetch_and_store_csrf_token(session)
|
92
88
|
if not csrf_token:
|
93
89
|
click.echo("❌ CSRF token is missing or invalid.")
|
94
90
|
continue
|
95
|
-
|
96
91
|
session.headers["X-CSRF-Token"] = csrf_token
|
97
92
|
|
98
93
|
if _is_session_valid(session):
|
99
94
|
click.echo("🚀 You are already logged in.")
|
100
95
|
return session
|
101
96
|
|
102
|
-
#
|
97
|
+
# Fresh login prompt
|
103
98
|
_delete_auth_files()
|
104
99
|
click.echo(f"🔐 Sima.ai Developer Portal Login Attempt {attempt}/3")
|
105
100
|
username = click.prompt("Email or Username")
|
106
101
|
password = getpass.getpass("Password: ")
|
107
102
|
|
108
|
-
|
103
|
+
# Base payload (no TOTP yet)
|
104
|
+
base_data = {
|
109
105
|
"login": username,
|
110
106
|
"password": password,
|
111
|
-
"second_factor_method": "1"
|
107
|
+
"second_factor_method": "1", # TOTP
|
112
108
|
}
|
113
109
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
110
|
+
def _post_login(payload: dict):
|
111
|
+
"""POST and return (status_code, json or None, text) with robust error handling."""
|
112
|
+
try:
|
113
|
+
resp = session.post(LOGIN_URL, data=payload, timeout=30)
|
114
|
+
except Exception as e:
|
115
|
+
return None, None, f"request failed: {e}"
|
116
|
+
j = None
|
117
|
+
try:
|
118
|
+
j = resp.json()
|
119
|
+
except Exception:
|
120
|
+
pass
|
121
|
+
return resp.status_code, j, (j or resp.text)
|
122
|
+
|
123
|
+
# First try without TOTP (server may ask for it)
|
124
|
+
status, j, raw = _post_login(base_data)
|
125
|
+
|
126
|
+
# Helper: decide if success
|
127
|
+
def _success():
|
128
|
+
# Prefer server 'ok': True, but also double-check the session cookie validity
|
129
|
+
if j and j.get("ok") is True:
|
130
|
+
return True
|
131
|
+
return _is_session_valid(session)
|
132
|
+
|
133
|
+
# If immediate success
|
134
|
+
if status == 200 and _success():
|
125
135
|
_save_cookie_jar(session)
|
126
|
-
|
136
|
+
welcome = (j.get("users", [{}])[0].get("name") if isinstance(j, dict) else "") or ""
|
137
|
+
click.echo(f"✅ Login successful. Welcome to Sima Developer Portal{', ' + welcome if welcome else ''}!")
|
127
138
|
return session
|
139
|
+
|
140
|
+
# See if TOTP is required/invalid; then prompt and retry up to 3 times
|
141
|
+
def _needs_totp(payload_json):
|
142
|
+
if not isinstance(payload_json, dict):
|
143
|
+
return False
|
144
|
+
if payload_json.get("totp_enabled") is True:
|
145
|
+
return True
|
146
|
+
reason = payload_json.get("reason") or payload_json.get("error")
|
147
|
+
return str(reason) in {"invalid_second_factor", "second_factor_required"}
|
148
|
+
|
149
|
+
if _needs_totp(j):
|
150
|
+
# Try up to 3 TOTP attempts within this login attempt
|
151
|
+
for totp_try in range(1, 4):
|
152
|
+
totp = click.prompt(f"🔢 Enter TOTP code (attempt {totp_try}/3)", hide_input=True)
|
153
|
+
data = dict(base_data)
|
154
|
+
data["second_factor_token"] = totp
|
155
|
+
|
156
|
+
status, j2, raw2 = _post_login(data)
|
157
|
+
if status == 200 and (j2 and j2.get("ok") is True or _is_session_valid(session)):
|
158
|
+
_save_cookie_jar(session)
|
159
|
+
welcome = (j2.get("users", [{}])[0].get("name") if isinstance(j2, dict) else "") or ""
|
160
|
+
click.echo(f"✅ Login successful. Welcome to Sima Developer Portal{', ' + welcome if welcome else ''}!")
|
161
|
+
return session
|
162
|
+
|
163
|
+
# If still invalid 2FA, let user try again; otherwise break to outer loop
|
164
|
+
msg = ""
|
165
|
+
if isinstance(j2, dict):
|
166
|
+
reason = j2.get("reason") or j2.get("error") or ""
|
167
|
+
msg = f" ({reason})" if reason else ""
|
168
|
+
if isinstance(j2, dict) and str(j2.get("reason")) in {"invalid_second_factor"}:
|
169
|
+
click.echo(f"❌ Invalid authentication code. Please try again.{msg}")
|
170
|
+
continue
|
171
|
+
else:
|
172
|
+
click.echo(f"❌ Login failed with TOTP{msg}.")
|
173
|
+
break # go to next overall attempt
|
174
|
+
|
175
|
+
# exhausted TOTP tries
|
176
|
+
click.echo("❌ TOTP verification failed after 3 attempts.")
|
177
|
+
continue # next overall attempt
|
178
|
+
|
179
|
+
# Not a TOTP case; report error and continue
|
180
|
+
err_detail = ""
|
181
|
+
if isinstance(j, dict):
|
182
|
+
err_detail = j.get("error") or j.get("message") or ""
|
183
|
+
reason = j.get("reason")
|
184
|
+
if reason and reason != err_detail:
|
185
|
+
err_detail = f"{err_detail} ({reason})" if err_detail else reason
|
128
186
|
else:
|
129
|
-
|
187
|
+
err_detail = str(raw)[:200]
|
188
|
+
|
189
|
+
click.echo(f"❌ Login failed. {err_detail or 'Please check your credentials and try again.'}")
|
130
190
|
|
131
191
|
click.echo("❌ Login failed after 3 attempts.")
|
132
192
|
raise SystemExit(1)
|
193
|
+
|
@@ -1,11 +1,11 @@
|
|
1
1
|
sima_cli/__init__.py,sha256=Nb2jSg9-CX1XvSc1c21U9qQ3atINxphuNkNfmR-9P3o,332
|
2
2
|
sima_cli/__main__.py,sha256=ehzD6AZ7zGytC2gLSvaJatxeD0jJdaEvNJvwYeGsWOg,69
|
3
|
-
sima_cli/__version__.py,sha256=
|
3
|
+
sima_cli/__version__.py,sha256=fcUZK1xhI360Deo68dmn4Df_ffnBdYiwwdvLTu09P58,49
|
4
4
|
sima_cli/cli.py,sha256=GYmQ7_XObl9VgFwuWWkWDo-_Y_Vn6lM53F7mKiYGubI,17126
|
5
5
|
sima_cli/app_zoo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
6
|
sima_cli/app_zoo/app.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
7
|
sima_cli/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
sima_cli/auth/basic_auth.py,sha256=
|
8
|
+
sima_cli/auth/basic_auth.py,sha256=mEmPrj32TVu1s34xR_UrJlIKHA3xBh98i_FzIZvAWag,7364
|
9
9
|
sima_cli/auth/login.py,sha256=yCYXWgrfbP4jSTZ3hITfxlgHkdVQVzsd8hQKpqaqCKs,3780
|
10
10
|
sima_cli/data/resources_internal.yaml,sha256=zlQD4cSnZK86bLtTWuvEudZTARKiuIKmB--Jv4ajL8o,200
|
11
11
|
sima_cli/data/resources_public.yaml,sha256=U7hmUomGeQ2ULdo1BU2OQHr0PyKBamIdK9qrutDlX8o,201
|
@@ -44,7 +44,7 @@ sima_cli/utils/disk.py,sha256=66Kr631yhc_ny19up2aijfycWfD35AeLQOJgUsuH2hY,446
|
|
44
44
|
sima_cli/utils/env.py,sha256=IP5HrH0lE7RMSiBeXcEt5GCLMT5p-QQroG-uGzl5XFU,8181
|
45
45
|
sima_cli/utils/net.py,sha256=WVntA4CqipkNrrkA4tBVRadJft_pMcGYh4Re5xk3rqo,971
|
46
46
|
sima_cli/utils/network.py,sha256=UvqxbqbWUczGFyO-t1SybG7Q-x9kjUVRNIn_D6APzy8,1252
|
47
|
-
sima_cli-0.0.
|
47
|
+
sima_cli-0.0.30.dist-info/licenses/LICENSE,sha256=a260OFuV4SsMZ6sQCkoYbtws_4o2deFtbnT9kg7Rfd4,1082
|
48
48
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
49
49
|
tests/test_app_zoo.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
50
50
|
tests/test_auth.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -53,8 +53,8 @@ tests/test_download.py,sha256=t87DwxlHs26_ws9rpcHGwr_OrcRPd3hz6Zmm0vRee2U,4465
|
|
53
53
|
tests/test_firmware.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
54
|
tests/test_model_zoo.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
55
|
tests/test_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
|
-
sima_cli-0.0.
|
57
|
-
sima_cli-0.0.
|
58
|
-
sima_cli-0.0.
|
59
|
-
sima_cli-0.0.
|
60
|
-
sima_cli-0.0.
|
56
|
+
sima_cli-0.0.30.dist-info/METADATA,sha256=CywF-g-sv44c9qK1UIAu3AROiPOwnPISqiSSQMnOEiY,3705
|
57
|
+
sima_cli-0.0.30.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
58
|
+
sima_cli-0.0.30.dist-info/entry_points.txt,sha256=xRYrDq1nCs6R8wEdB3c1kKuimxEjWJkHuCzArQPT0Xk,47
|
59
|
+
sima_cli-0.0.30.dist-info/top_level.txt,sha256=FtrbAUdHNohtEPteOblArxQNwoX9_t8qJQd59fagDlc,15
|
60
|
+
sima_cli-0.0.30.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|