[cpif] r187 - in trunk: . backend frontend-web frontend-web/skins/default

svn at argo.es svn at argo.es
Fri Jun 22 20:47:04 CEST 2007


Author: jcea
Date: Fri Jun 22 20:47:00 2007
New Revision: 187

Log:
Los usuarios ya puede ver su propio perfil, cambiar
su clave y, lo más importante, especificar servidores OpenID!!.



Added:
   trunk/frontend-web/url_perfil.py
      - copied, changed from r180, /trunk/frontend-web/url_logout.py
   trunk/frontend-web/url_perfil_POST.py
      - copied, changed from r185, /trunk/frontend-web/url_nuevo_usuario_POST.py
Modified:
   trunk/TODO
   trunk/backend/database.py
   trunk/frontend-web/skins.py
   trunk/frontend-web/skins/default/link_logout.html
   trunk/frontend-web/url_nuevo_usuario_POST.py

Modified: trunk/TODO
==============================================================================
--- trunk/TODO	(original)
+++ trunk/TODO	Fri Jun 22 20:47:00 2007
@@ -137,3 +137,10 @@
   ejemplo, no se deberia poder abrir un hilo con un titulo
   excesivamente largo o de mas de una linea.
 
+- 20070622: FRONTAL WEB: Hacer "sanity check" de los datos que
+  se acaban mostrando al usuario. Por ejemplo, su propio
+  nombre de usuario o sus servidores OpenID.
+
+  Esto es especialmente importante cuando el "master" visualiza
+  un perfil, ya que se puede provocar un XSS en la cuenta "master".
+

Modified: trunk/backend/database.py
==============================================================================
--- trunk/backend/database.py	(original)
+++ trunk/backend/database.py	Fri Jun 22 20:47:00 2007
@@ -88,7 +88,24 @@
 
   return None
 
-def usuario_add(conn,nick,datos,clave=None,OpenIDs=None) :
+def usuario_update(conn,nick,clave=None,OpenIDs=None) :
+  root=conn.get_root()
+  usuarios=root["usuarios"]["usuarios"]
+
+  usuario=usuarios.get(normaliza_nick(nick))
+  assert usuario
+
+  if clave :
+    usuario["clave"]=clave
+
+  if OpenIDs!=None :
+    old_OpenIDs=usuario["OpenID"]
+    if old_OpenIDs!=OpenIDs : # Solo grabamos si ha habido cambios
+      old_OpenIDs.clear() # Este tipo es persistente, asi que lo reutilizamos
+      old_OpenIDs.update(OpenIDs)
+
+
+def usuario_add(conn,nick,datos,clave=None,OpenIDs=set()) :
   from durus.btree import BTree
   from durus.persistent_dict import PersistentDict
   from durus.persistent_set import PersistentSet

Modified: trunk/frontend-web/skins.py
==============================================================================
--- trunk/frontend-web/skins.py	(original)
+++ trunk/frontend-web/skins.py	Fri Jun 22 20:47:00 2007
@@ -44,7 +44,8 @@
     '/LOGIN':               ['login'],
     '/error':               [],
     '/stop':                [],
-    '/nuevo_usuario_POST':  []
+    '/nuevo_usuario_POST':  [],
+    '/perfil_POST':         [],
     }
 
 import os

Modified: trunk/frontend-web/skins/default/link_logout.html
==============================================================================
--- trunk/frontend-web/skins/default/link_logout.html	(original)
+++ trunk/frontend-web/skins/default/link_logout.html	Fri Jun 22 20:47:00 2007
@@ -1 +1 @@
-<a href="%(link_auth)s">LOGOUT (%(user)s)</a>
+<a href="%(link_auth)s">LOGOUT</a> (<a href="/perfil">%(user)s</a>)

Modified: trunk/frontend-web/url_nuevo_usuario_POST.py
==============================================================================
--- trunk/frontend-web/url_nuevo_usuario_POST.py	(original)
+++ trunk/frontend-web/url_nuevo_usuario_POST.py	Fri Jun 22 20:47:00 2007
@@ -38,11 +38,21 @@
     OpenID=cuerpo.getfirst("OpenID%d" %i)
     if OpenID : # Comprobamos el caso de campos inexistentes
       OpenID=OpenID.strip()
-      if OpenID : OpenIDs.add(OpenID)
+      if OpenID :
+        if '"' in OpenID : # XSS
+          pagina.load_url(["error"])
+          pagina.load_dict({"generic_message": "<h1>Caracteres extra&ntilde;os en los servidores OpenID</h1>"})
+          return pagina.web()
+        OpenIDs.add(OpenID)
 
   if not (nick and clave1 and clave2) :
     pagina.load_url(["error"])
     pagina.load_dict({"generic_message": "<h1>No puedes dejar ningun campo no opcional en blanco</h1>"})
+    return pagina.web()
+
+  if '"' in nick :
+    pagina.load_url(["error"])
+    pagina.load_dict({"generic_message": "<h1>Caracteres extra&ntilde;os en el nombre de usuario</h1>"})
     return pagina.web()
 
   if clave1!=clave2 :

Copied: trunk/frontend-web/url_perfil.py (from r180, /trunk/frontend-web/url_logout.py)
==============================================================================
--- /trunk/frontend-web/url_logout.py	(original)
+++ trunk/frontend-web/url_perfil.py	Fri Jun 22 20:47:00 2007
@@ -2,8 +2,48 @@
 
 from globales import monitor
 
-def gestiona_url(handler,path,usuario) :
-  if len(path)!=1 : return None
-  # Para borrar una cookie hay que mandarla con una fecha en el pasado.
-  return (302,{"Set-Cookie":"cpif_auth=X; path=/; expires=Thu, 01-01-1970 01:00:00 GMT","Location":"/"},"")
+ at monitor
+def gestiona_url(conn,handler,path,usuario) :
+  if not usuario : # Acceso anonimo
+    return None
+
+  l=len(path)
+  if l==1 :
+    usuario_pedido=usuario
+  elif l==2 :
+    usuario_pedido=path[1]
+  else :
+    return None
+
+  import database
+  usuario_pedido_normalizado=database.normaliza_nick(usuario_pedido)
+  if usuario!="master" :
+    if database.normaliza_nick(usuario)!=usuario_pedido_normalizado :
+      return None
+
+  root=conn.get_root()
+  u=root["usuarios"]["usuarios"].get(usuario_pedido_normalizado)
+  if not u :
+    return None
+
+  texto=["<tr><td>Usuario:</td><td>%s</td></tr>" %usuario_pedido]
+  texto.append('<tr><td>Clave nueva:</td><td><input type="password" name="clave1" size="25" value="" /></td></tr>')
+  texto.append('<tr><td>Confirma clave nueva:</td><td><input type="password" name="clave2" size="25" value="" /></td></tr>')
+  OpenIDs=list(u["OpenID"])+["","","","",""] # Padding
+  texto.append('<tr><td>Servidores OpenID:</td><td><input type="text" name="OpenID1" size=55 value="%s" /></td></tr>' %OpenIDs[0])
+  texto.append('<tr><td align=right>(opcionales)</td><td><input type="text" name="OpenID2" size=55 value="%s" /></td></tr>' %OpenIDs[1])
+  for i,j in zip([3,4,5],OpenIDs[2:]) :
+    texto.append('<tr><td>&nbsp;</td><td><input type="text" name="OpenID%d" size=55 value="%s" /></td></tr>' %(i,j))
+
+  return (200,{"Content-Type":"text/html; charset=utf-8"},"""
+<html>
+<head><title>Perfil - %s</title></head>
+<body>
+<form action="/perfil_POST/%s" method="post" enctype="multipart/form-data">
+<table>
+%s
+<tr><td colspan=2 align=right><input class="form-element" type="submit" name="submit" value="Cambia perfil"/></td></tr>
+</table>
+</body>
+</html>""" %(usuario_pedido,usuario_pedido,"\r\n".join(texto)))
 

Copied: trunk/frontend-web/url_perfil_POST.py (from r185, /trunk/frontend-web/url_nuevo_usuario_POST.py)
==============================================================================
--- /trunk/frontend-web/url_nuevo_usuario_POST.py	(original)
+++ trunk/frontend-web/url_perfil_POST.py	Fri Jun 22 20:47:00 2007
@@ -5,14 +5,20 @@
 @monitor
 def gestiona_url(conn,handler,path,usuario) :
   if not usuario : # Acceso anonimo
-    import url_LOGIN
-    return url_LOGIN.gestiona_url(handler,path,usuario)
+    return None
 
-  if len(path)!=1 : return None
+  if len(path)!=2 : return None
+
+  import database
+  usuario_pedido=path[1]
+  usuario_pedido_normalizado=database.normaliza_nick(usuario_pedido)
+
+  if (usuario!="master") and (usuario_pedido_normalizado!=database.normaliza_nick(usuario)) :
+    return None
 
   import skins
   pagina = skins.Skin(path,usuario)
-  pagina.load_dict({"page_title": "cpif - Alta exitosa"})
+  pagina.load_dict({"page_title": "cpif - Cambio de perfil exitoso"})
   
   if usuario!="master" :
     pagina.load_url(["error"])
@@ -22,15 +28,11 @@
   import cgi
   ctype,pdict=cgi.parse_header(handler.headers.getheader('content-type'))
   cuerpo=cgi.FieldStorage(fp=handler.rfile,headers=handler.headers,environ={'REQUEST_METHOD':'POST'},keep_blank_values=1)
-  nick=cuerpo.getfirst("usuario")
   clave1=cuerpo.getfirst("clave1")
   clave2=cuerpo.getfirst("clave2")
-  if not (nick and clave1 and clave2) : # Comprobamos el caso de campos inexistentes
-    pagina.load_url(["error"])
-    pagina.load_dict({"generic_message": "<h1>No puedes dejar ningun campo no opcional en blanco</h1>"})
-    return pagina.web()
+  if clave1==None or clave2==None : # Comprobamos el caso de campos inexistentes
+    return None
 
-  nick=nick.strip()
   clave1=clave1.strip()
   clave2=clave2.strip()
   OpenIDs=set()
@@ -38,12 +40,12 @@
     OpenID=cuerpo.getfirst("OpenID%d" %i)
     if OpenID : # Comprobamos el caso de campos inexistentes
       OpenID=OpenID.strip()
-      if OpenID : OpenIDs.add(OpenID)
-
-  if not (nick and clave1 and clave2) :
-    pagina.load_url(["error"])
-    pagina.load_dict({"generic_message": "<h1>No puedes dejar ningun campo no opcional en blanco</h1>"})
-    return pagina.web()
+      if OpenID :
+        if '"' in OpenID : # XSS
+          pagina.load_url(["error"])
+          pagina.load_dict({"generic_message": "<h1>Caracteres extra&ntilde;os en los servidores OpenID</h1>"})
+          return pagina.web()
+        OpenIDs.add(OpenID)
 
   if clave1!=clave2 :
     pagina.load_url(["error"])
@@ -51,13 +53,13 @@
     return (pagina.web())
 
   import database
-  if database.usuario_verifica(conn,nick=nick) :
+  if not database.usuario_verifica(conn,nick=usuario_pedido) :
     pagina.load_url(["error"])
-    pagina.load_dict({"generic_message": "<h1>El usuario ya existe</h1>"})
+    pagina.load_dict({"generic_message": "<h1>El usuario NO existe</h1>"})
     return (pagina.web())
 
-  database.usuario_add(conn,nick,None,clave=clave1,OpenIDs=OpenIDs)
+  database.usuario_update(conn,usuario_pedido,clave=clave1,OpenIDs=OpenIDs)
 
-  pagina.load_dict({"generic_message": "<h1>Alta exitosa</h1>"})
-  return (pagina.web())
+  pagina.load_dict({"generic_message": "<h1>Cambio de perfil exitoso</h1>"})
+  return pagina.web()
 



More information about the cpif mailing list