enfoquealafamilia commited on
Commit
7b0c4df
·
verified ·
1 Parent(s): a284bd1

v1.5.1: persistir el nombre del rep en un token firmado (?n=b64.hmac). Al fijar el nombre se emite el token; al recargar se rehidrata rep_name antes de dibujar el campo. Fail-open, mismo secreto que ?s=.

Browse files
Files changed (1) hide show
  1. app.py +61 -2
app.py CHANGED
@@ -3,6 +3,7 @@ import re
3
  import json
4
  import time
5
  import hmac
 
6
  import hashlib
7
  import threading
8
  import unicodedata
@@ -17,7 +18,7 @@ KB_PATH = BASE_DIR / KB_NAME
17
 
18
  # Version del bot. Se INCREMENTA al desplegar una mejora salida del feedback de los reps
19
  # (se comunica el numero en el changelog de esa release). Formato X.Y.
20
- APP_VERSION = "1.5.0"
21
  APP_TITLE = f"Enfoque Proto Chatbot {APP_VERSION}"
22
 
23
  # --- Persistencia remota (fuente de verdad) --------------------------------
@@ -151,6 +152,63 @@ def _valid_session_token(tok):
151
  return None
152
 
153
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  def _check_auth():
155
  auth_config = os.environ.get("HF_SPACES_AUTH", "")
156
  if not auth_config:
@@ -192,6 +250,7 @@ def _check_auth():
192
 
193
 
194
  _check_auth()
 
195
 
196
 
197
  # -- Backend -------------------------------------------------------------------
@@ -1493,7 +1552,7 @@ with st.sidebar:
1493
  st.divider()
1494
 
1495
  st.text_input("Tu nombre y apellido (obligatorio)", key="rep_name",
1496
- placeholder="Ej: María Rodríguez")
1497
  if len(st.session_state.get("rep_name", "").split()) < 2:
1498
  st.caption("⚠️ Escribe tu **nombre y apellido** para poder usar el asistente.")
1499
 
 
3
  import json
4
  import time
5
  import hmac
6
+ import base64
7
  import hashlib
8
  import threading
9
  import unicodedata
 
18
 
19
  # Version del bot. Se INCREMENTA al desplegar una mejora salida del feedback de los reps
20
  # (se comunica el numero en el changelog de esa release). Formato X.Y.
21
+ APP_VERSION = "1.5.1"
22
  APP_TITLE = f"Enfoque Proto Chatbot {APP_VERSION}"
23
 
24
  # --- Persistencia remota (fuente de verdad) --------------------------------
 
152
  return None
153
 
154
 
155
+ # -- Token del NOMBRE del rep (v1.5.1) --------------------------------------------------------
156
+ # El nombre se teclea en la barra lateral DESPUES del login (no en el login), y una recarga dura
157
+ # borra session_state -> el rep re-teclea su nombre. Para evitarlo: cuando el rep fija su nombre,
158
+ # se emite un token firmado (b64.hmac) en el query-string `?n=`; al recargar, se rehidrata el
159
+ # nombre en session_state ANTES de que se dibuje el campo. Firmado con el mismo secreto para que la
160
+ # URL no se pueda falsear. FAIL-OPEN: si `?n=` falta/está mal/no hay secreto, se pide el nombre como
161
+ # antes. El nombre NO es sensible (el rep lo declara libremente y su email ya viaja en el token `s`).
162
+ def _make_name_token(name):
163
+ b = base64.urlsafe_b64encode(name.encode()).decode().rstrip("=")
164
+ sig = hmac.new(_auth_secret().encode(), b.encode(), hashlib.sha256).hexdigest()[:16]
165
+ return f"{b}.{sig}"
166
+
167
+
168
+ def _valid_name_token(tok):
169
+ """Devuelve el nombre si el token valida; si no, None (fail-open)."""
170
+ try:
171
+ b, sig = tok.rsplit(".", 1)
172
+ good = hmac.new(_auth_secret().encode(), b.encode(), hashlib.sha256).hexdigest()[:16]
173
+ if not hmac.compare_digest(good, sig):
174
+ return None
175
+ pad = "=" * (-len(b) % 4)
176
+ name = base64.urlsafe_b64decode((b + pad).encode()).decode()
177
+ return name or None
178
+ except Exception:
179
+ return None
180
+
181
+
182
+ def _restore_name():
183
+ """Rehidrata rep_name desde `?n=` si aun no esta seteado (tras una recarga dura). Fail-open;
184
+ corre solo estando ya autenticado (despues de _check_auth)."""
185
+ try:
186
+ if st.session_state.get("rep_name"):
187
+ return
188
+ tok = st.query_params.get("n")
189
+ if tok and _auth_secret():
190
+ name = _valid_name_token(tok)
191
+ if name:
192
+ st.session_state["rep_name"] = name
193
+ except Exception:
194
+ pass
195
+
196
+
197
+ def _persist_name():
198
+ """on_change del campo de nombre: emite/actualiza el token `?n=` cuando el rep fija su nombre
199
+ (>= 2 palabras). Si lo vacia, limpia el param. Fail-open."""
200
+ try:
201
+ if not _auth_secret():
202
+ return
203
+ name = st.session_state.get("rep_name", "").strip()
204
+ if len(name.split()) >= 2:
205
+ st.query_params["n"] = _make_name_token(name)
206
+ elif "n" in st.query_params:
207
+ del st.query_params["n"]
208
+ except Exception:
209
+ pass
210
+
211
+
212
  def _check_auth():
213
  auth_config = os.environ.get("HF_SPACES_AUTH", "")
214
  if not auth_config:
 
250
 
251
 
252
  _check_auth()
253
+ _restore_name()
254
 
255
 
256
  # -- Backend -------------------------------------------------------------------
 
1552
  st.divider()
1553
 
1554
  st.text_input("Tu nombre y apellido (obligatorio)", key="rep_name",
1555
+ placeholder="Ej: María Rodríguez", on_change=_persist_name)
1556
  if len(st.session_state.get("rep_name", "").split()) < 2:
1557
  st.caption("⚠️ Escribe tu **nombre y apellido** para poder usar el asistente.")
1558