GuXiaopeng commited on
Commit
7eae4fb
·
verified ·
1 Parent(s): ddbac90

Deploy Step 4A-5-R3 native cookie session restore

Browse files
Files changed (3) hide show
  1. README.md +2 -2
  2. managed_auth.py +71 -18
  3. requirements.txt +1 -2
README.md CHANGED
@@ -7,8 +7,8 @@ sdk: streamlit
7
  app_file: app.py
8
  pinned: false
9
  short_description: Agent Article
10
- sdk_version: 1.32.0
11
  python_version: 3.11
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
7
  app_file: app.py
8
  pinned: false
9
  short_description: Agent Article
10
+ sdk_version: 1.38.0
11
  python_version: 3.11
12
  ---
13
 
14
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
managed_auth.py CHANGED
@@ -11,6 +11,7 @@ import os
11
  import time
12
  from datetime import datetime, timezone
13
  from typing import Any, Callable
 
14
 
15
  import qrcode
16
  import requests
@@ -203,10 +204,14 @@ def _clear_session(*, clear_restore: bool = False) -> None:
203
 
204
 
205
  def _read_restore_cookie() -> str:
 
206
  try:
207
- cookies = getattr(st.context, "cookies", {})
208
- return str(cookies.get(RESTORE_COOKIE_NAME, "") or "").strip()
 
 
209
  except Exception:
 
210
  return ""
211
 
212
 
@@ -214,8 +219,9 @@ def _render_restore_cookie_command(
214
  token: str | None,
215
  *,
216
  expires_at: str | None = None,
 
217
  ) -> None:
218
- """Write or delete a random recovery cookie in the top-level page."""
219
  safe_name = json.dumps(RESTORE_COOKIE_NAME)
220
  safe_token = json.dumps(str(token or ""))
221
  max_age = RESTORE_COOKIE_DEFAULT_DAYS * 24 * 60 * 60
@@ -227,33 +233,65 @@ def _render_restore_cookie_command(
227
  )
228
  if not token:
229
  max_age = 0
 
230
  script = f"""
231
  <script>
232
  (() => {{
 
 
 
 
 
 
 
 
 
233
  try {{
234
- const name = {safe_name};
235
- const value = {safe_token};
236
- const maxAge = {int(max_age)};
237
- const parentDoc = window.parent.document;
238
- parentDoc.cookie = `${{name}}=${{encodeURIComponent(value)}}; Max-Age=${{maxAge}}; Path=/; Secure; SameSite=Strict`;
239
- }} catch (_) {{}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  }})();
241
  </script>
242
  """
243
  components.html(script, height=0, width=0)
244
 
245
 
246
- def _sync_restore_cookie_to_browser() -> None:
247
  token = str(st.session_state.get("sp_restore_token") or "").strip()
248
  if token:
249
  _render_restore_cookie_command(
250
  token,
251
  expires_at=st.session_state.get("sp_restore_expires_at"),
 
252
  )
253
 
254
 
255
- def _delete_restore_cookie() -> None:
256
- _render_restore_cookie_command(None)
257
 
258
 
259
  def _verify_existing_session() -> bool:
@@ -322,7 +360,11 @@ def _create_login_request() -> dict[str, Any]:
322
  return request_data
323
 
324
 
325
- def _store_authenticated_session(result: dict[str, Any]) -> None:
 
 
 
 
326
  session_token = result.get("session_token")
327
  user = result.get("user")
328
 
@@ -341,7 +383,9 @@ def _store_authenticated_session(result: dict[str, Any]) -> None:
341
  st.session_state["sp_restore_expires_at"] = result.get(
342
  "restore_expires_at"
343
  )
344
- _sync_restore_cookie_to_browser()
 
 
345
  _clear_login_request()
346
 
347
 
@@ -594,9 +638,16 @@ def _poll_login_once(
594
  st.stop()
595
 
596
  if status == "authenticated":
597
- _store_authenticated_session(result)
 
 
 
 
 
 
 
598
  status_box.success(tr(language, "login_auto_success"))
599
- st.rerun()
600
 
601
  _clear_login_request()
602
 
@@ -733,11 +784,13 @@ def logout_alipay_session(
733
  except Exception:
734
  pass
735
 
736
- _delete_restore_cookie()
 
 
737
  _clear_session(clear_restore=True)
738
  _clear_login_request()
739
  _clear_generation_session_state()
740
- st.rerun()
741
 
742
 
743
  def render_logged_in_account(
 
11
  import time
12
  from datetime import datetime, timezone
13
  from typing import Any, Callable
14
+ from urllib.parse import unquote
15
 
16
  import qrcode
17
  import requests
 
204
 
205
 
206
  def _read_restore_cookie() -> str:
207
+ """Read the restore cookie supplied with the initial Streamlit request."""
208
  try:
209
+ context = getattr(st, "context", None)
210
+ cookies = getattr(context, "cookies", {}) if context is not None else {}
211
+ raw_value = str(cookies.get(RESTORE_COOKIE_NAME, "") or "").strip()
212
+ return unquote(raw_value)
213
  except Exception:
214
+ # Compatibility fallback: never interrupt the approved login page.
215
  return ""
216
 
217
 
 
219
  token: str | None,
220
  *,
221
  expires_at: str | None = None,
222
+ reload_parent: bool = False,
223
  ) -> None:
224
+ """Write or delete the recovery cookie without changing visible UI."""
225
  safe_name = json.dumps(RESTORE_COOKIE_NAME)
226
  safe_token = json.dumps(str(token or ""))
227
  max_age = RESTORE_COOKIE_DEFAULT_DAYS * 24 * 60 * 60
 
233
  )
234
  if not token:
235
  max_age = 0
236
+
237
  script = f"""
238
  <script>
239
  (() => {{
240
+ const name = {safe_name};
241
+ const value = {safe_token};
242
+ const maxAge = {int(max_age)};
243
+ const reloadParent = {str(bool(reload_parent)).lower()};
244
+ const cookieText = `${{name}}=${{encodeURIComponent(value)}}; Max-Age=${{maxAge}}; Path=/; Secure; SameSite=Strict`;
245
+
246
+ let targetDocument = document;
247
+ let cookieActionSucceeded = false;
248
+
249
  try {{
250
+ if (window.parent && window.parent.document) {{
251
+ targetDocument = window.parent.document;
252
+ }}
253
+ targetDocument.cookie = cookieText;
254
+ const cookiePresent = targetDocument.cookie
255
+ .split("; ")
256
+ .some((entry) => entry.startsWith(`${{name}}=`));
257
+ cookieActionSucceeded = maxAge === 0
258
+ ? !cookiePresent
259
+ : cookiePresent;
260
+ }} catch (error) {{
261
+ console.error("SmartPaper restore-cookie action failed", error);
262
+ }}
263
+
264
+ if (!cookieActionSucceeded) {{
265
+ console.error("SmartPaper restore-cookie verification failed");
266
+ }}
267
+
268
+ if (reloadParent && cookieActionSucceeded) {{
269
+ window.setTimeout(() => {{
270
+ try {{
271
+ window.parent.location.reload();
272
+ }} catch (error) {{
273
+ window.location.reload();
274
+ }}
275
+ }}, 180);
276
+ }}
277
  }})();
278
  </script>
279
  """
280
  components.html(script, height=0, width=0)
281
 
282
 
283
+ def _sync_restore_cookie_to_browser(*, reload_parent: bool = False) -> None:
284
  token = str(st.session_state.get("sp_restore_token") or "").strip()
285
  if token:
286
  _render_restore_cookie_command(
287
  token,
288
  expires_at=st.session_state.get("sp_restore_expires_at"),
289
+ reload_parent=reload_parent,
290
  )
291
 
292
 
293
+ def _delete_restore_cookie(*, reload_parent: bool = False) -> None:
294
+ _render_restore_cookie_command(None, reload_parent=reload_parent)
295
 
296
 
297
  def _verify_existing_session() -> bool:
 
360
  return request_data
361
 
362
 
363
+ def _store_authenticated_session(
364
+ result: dict[str, Any],
365
+ *,
366
+ reload_after_cookie: bool = False,
367
+ ) -> None:
368
  session_token = result.get("session_token")
369
  user = result.get("user")
370
 
 
383
  st.session_state["sp_restore_expires_at"] = result.get(
384
  "restore_expires_at"
385
  )
386
+ _sync_restore_cookie_to_browser(
387
+ reload_parent=reload_after_cookie,
388
+ )
389
  _clear_login_request()
390
 
391
 
 
638
  st.stop()
639
 
640
  if status == "authenticated":
641
+ # Cookie assignment is synchronous in the browser. The hidden command
642
+ # then reloads the top-level page, so the new initial request carries
643
+ # the restore cookie and the approved login UI is not mixed with the
644
+ # writing interface in the same Streamlit run.
645
+ _store_authenticated_session(
646
+ result,
647
+ reload_after_cookie=True,
648
+ )
649
  status_box.success(tr(language, "login_auto_success"))
650
+ st.stop()
651
 
652
  _clear_login_request()
653
 
 
784
  except Exception:
785
  pass
786
 
787
+ # Delete the browser token first, then let browser JavaScript reload the
788
+ # page. This avoids interrupting the cookie deletion with st.rerun().
789
+ _delete_restore_cookie(reload_parent=True)
790
  _clear_session(clear_restore=True)
791
  _clear_login_request()
792
  _clear_generation_session_state()
793
+ st.stop()
794
 
795
 
796
  def render_logged_in_account(
requirements.txt CHANGED
@@ -1,4 +1,4 @@
1
- streamlit==1.32.0
2
  requests
3
  python-docx
4
  pandas
@@ -15,4 +15,3 @@ tabulate
15
  pycryptodome
16
  qrcode[pil]>=8.0,<9
17
  streamlit-autorefresh==1.0.1
18
- extra-streamlit-components==0.1.71
 
1
+ streamlit==1.38.0
2
  requests
3
  python-docx
4
  pandas
 
15
  pycryptodome
16
  qrcode[pil]>=8.0,<9
17
  streamlit-autorefresh==1.0.1