refine forgot password mechanism & get baseurl from the request instead of settings
authorSofia Papagiannaki <papagian@gmail.com>
Thu, 17 Nov 2011 09:06:35 +0000 (11:06 +0200)
committerSofia Papagiannaki <papagian@gmail.com>
Thu, 17 Nov 2011 09:06:35 +0000 (11:06 +0200)
Refs: #1584

pithos/im/target/local.py
pithos/im/templates/reset.html
pithos/im/urls.py
pithos/im/views.py
pithos/settings.py.dist

index 95e33b7..cb4238f 100644 (file)
 
 from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
 from django.conf import settings
+from django.template.loader import render_to_string
 
 from pithos.im.target.util import prepare_response
 from pithos.im.models import User
 
+from urllib import unquote
+
 def login(request):
     username = '%s@local' % request.POST.get('username')
     password = request.POST.get('password')
@@ -59,26 +62,60 @@ def login(request):
         return HttpResponseBadRequest('Unverified account')
     
     next = request.POST.get('next')
-    #if not next:
-    #    return HttpResponse('')
-    #if not request.user:
-    #    return HttpResponseRedirect(next)
-    
     return prepare_response(request, user, next)
 
 def activate(request):
     token = request.GET.get('auth')
-    url = request.GET.get('next')
+    next = request.GET.get('next')
     try:
         user = User.objects.get(auth_token=token)
     except User.DoesNotExist:
         return HttpResponseBadRequest('No such user')
     
-    url = '%s?next=%sui' %(url, settings.BASE_URL)
     user.state = 'ACTIVE'
-    user.renew_token()
     user.save()
-    response = HttpResponse()
-    response['Location'] = url
-    response.status_code = 302
-    return response
\ No newline at end of file
+    return prepare_response(request, user, next, renew=True)
+
+def reset_password(request):
+    if request.method == 'GET':
+        cookie_value = unquote(request.COOKIES.get('_pithos2_a', ''))
+        if cookie_value and '|' in cookie_value:
+            token = cookie_value.split('|', 1)[1]
+        else:
+            token = request.GET.get('auth')
+        next = request.GET.get('next')
+        username = request.GET.get('username')
+        kwargs = {'auth': token,
+                  'next': next,
+                  'username' : username}
+        if not token:
+            kwargs.update({'status': 'error',
+                           'message': 'Missing token'})
+        html = render_to_string('reset.html', kwargs)
+        return HttpResponse(html)
+    elif request.method == 'POST':
+        token = request.POST.get('auth')
+        username = request.POST.get('username')
+        password = request.POST.get('password')
+        next = request.POST.get('next')
+        if not token:
+            status = 'error'
+            message = 'Bad Request: missing token'
+        try:
+            user = User.objects.get(auth_token=token)
+            if username != user.uniq:
+                status = 'error'
+                message = 'Bad Request: username mismatch'
+            else:
+                user.password = password
+                user.status = 'NORMAL'
+                user.save()
+                return prepare_response(request, user, next, renew=True)
+        except User.DoesNotExist:
+            status = 'error'
+            message = 'Bad Request: invalid token'
+            
+        html = render_to_string('reset.html', {
+                'status': status,
+                'message': message})
+        return HttpResponse(html)
\ No newline at end of file
index 787dba0..c01e2d0 100644 (file)
@@ -5,7 +5,7 @@
 {% endblock title%}
 
 {% block body %}
-<form action="{% url pithos.im.views.reset_password %}" method="post">
+<form action="{% url pithos.im.target.local.reset_password %}" method="post">
   <div class="clearfix">
     <label for="user-uniq">password</label>
     <div class="input">
@@ -16,6 +16,7 @@
   <div class="actions">
     <input type="hidden" name="auth" value="{{ auth }}">
     <input type="hidden" name="next" value="{{ next }}">
+    <input type="hidden" name="username" value="{{ username }}">
     <button type="submit" class="btn primary">Reset</button>
   </div>
 </form>
index c0ab932..107ff5f 100644 (file)
@@ -47,20 +47,21 @@ urlpatterns = patterns('pithos.im.views',
     (r'^admin/users/(\d+)/modify/?$', 'users_modify'),
     (r'^admin/users/(\d+)/delete/?$', 'users_delete'),
     
-    (r'^invite/?$', 'invite')
+    (r'^invite/?$', 'invite'),
+    (r'^local/create/?$', 'local_create'),
+    (r'^local/reclaim/?$', 'reclaim_password'),
+    
 )
 
-urlpatterns += patterns('',
-    (r'^login/shibboleth/?$', 'pithos.im.target.shibboleth.login'),
-    (r'^login/twitter/?$', 'pithos.im.target.twitter.login'),
-    (r'^login/twitter/authenticated/?$', 'pithos.im.target.twitter.authenticated'),
-    (r'^login/invitation/?$', 'pithos.im.target.invitation.login'),
-    (r'^login/local/$', 'pithos.im.target.local.login'),
-    (r'^login/local/activate/?$', 'pithos.im.target.local.activate'),
-    (r'^login/local/create/$', 'pithos.im.views.local_create'),
-    (r'^login/local/reclaim/$', 'pithos.im.views.reclaim_password'),
-    (r'^login/local/reset/$', 'pithos.im.views.reset_password'),
-    (r'^login/dummy/?$', 'pithos.im.target.dummy.login')
+urlpatterns += patterns('pithos.im.target',
+    (r'^login/shibboleth/?$', 'shibboleth.login'),
+    (r'^login/twitter/?$', 'twitter.login'),
+    (r'^login/twitter/authenticated/?$', 'twitter.authenticated'),
+    (r'^login/invitation/?$', 'invitation.login'),
+    (r'^local/?$', 'local.login'),
+    (r'^local/activate/?$', 'local.activate'),
+    (r'^local/reset/?$', 'local.reset_password'),
+    (r'^login/dummy/?$', 'dummy.login')
 )
 
 urlpatterns += patterns('',
index 727a945..ad8f8f3 100644 (file)
@@ -197,13 +197,13 @@ def generate_invitation_code():
             return code
 
 
-def send_invitation(inv):
-    url = settings.INVITATION_LOGIN_TARGET % inv.code
+def send_invitation(baseurl, inv):
+    url = settings.INVITATION_LOGIN_TARGET % (baseurl, inv.code, quote(baseurl))
     subject = _('Invitation to Pithos')
     message = render_to_string('invitation.txt', {
                 'invitation': inv,
                 'url': url,
-                'baseurl': settings.BASE_URL,
+                'baseurl': baseurl,
                 'service': settings.SERVICE_NAME,
                 'support': settings.DEFAULT_CONTACT_EMAIL})
     sender = settings.DEFAULT_FROM_EMAIL
@@ -229,7 +229,7 @@ def invite(request):
                 defaults={'code': code, 'realname': realname})
             
             try:
-                send_invitation(invitation)
+                send_invitation(request.get_host(), invitation)
                 if created:
                     inviter.invitations = max(0, inviter.invitations - 1)
                     inviter.save()
@@ -256,12 +256,15 @@ def invite(request):
             'message': message})
     return HttpResponse(html)
 
-def send_verification(user):
-    url = settings.ACTIVATION_LOGIN_TARGET % quote(user.auth_token)
+def send_verification(baseurl, user):
+    next = quote('http://%s' % baseurl)
+    url = settings.ACTIVATION_LOGIN_TARGET % (baseurl,
+                                              quote(user.auth_token),
+                                              next)
     message = render_to_string('activation.txt', {
             'user': user,
             'url': url,
-            'baseurl': settings.BASE_URL,
+            'baseurl': baseurl,
             'service': settings.SERVICE_NAME,
             'support': settings.DEFAULT_CONTACT_EMAIL})
     sender = settings.DEFAULT_FROM_EMAIL
@@ -277,6 +280,7 @@ def local_create(request):
         email = request.POST.get('email')
         password = request.POST.get('password')
         status = 'success'
+        cookie_value = None
         if not username:
             status = 'error'
             message = 'No username provided'
@@ -305,7 +309,7 @@ def local_create(request):
                 user.level = 1
                 user.renew_token()
                 try:
-                    send_verification(user)
+                    send_verification(request.get_host(), user)
                     message = _('Verification sent to %s' % user.email)
                     user.save()
                 except (SMTPException, socket.error) as e:
@@ -316,14 +320,18 @@ def local_create(request):
         html = render_to_string('local_create.html', {
                 'status': status,
                 'message': message})
-        return HttpResponse(html)
-
-def send_password(user):
-    url = settings.PASSWORD_RESET_TARGET % quote(user.auth_token)
+        response = HttpResponse(html)
+        return response
+
+def send_password(baseurl, user):
+    next = quote('http://%s' % baseurl)
+    url = settings.PASSWORD_RESET_TARGET % (baseurl,
+                                            quote(user.uniq),
+                                            next)
     message = render_to_string('password.txt', {
             'user': user,
             'url': url,
-            'baseurl': settings.BASE_URL,
+            'baseurl': baseurl,
             'service': settings.SERVICE_NAME,
             'support': settings.DEFAULT_CONTACT_EMAIL})
     sender = settings.DEFAULT_FROM_EMAIL
@@ -339,9 +347,10 @@ def reclaim_password(request):
         try:
             user = User.objects.get(uniq=username)
             try:
-                send_password(user)
+                send_password(request.get_host(), user)
                 status = 'success'
                 message = _('Password reset sent to %s' % user.email)
+                user.status = 'UNVERIFIED'
                 user.save()
             except (SMTPException, socket.error) as e:
                 status = 'error'
@@ -355,36 +364,3 @@ def reclaim_password(request):
                 'status': status,
                 'message': message})
         return HttpResponse(html)
-
-def reset_password(request):
-    if request.method == 'GET':
-        token = request.GET.get('auth')
-        next = request.GET.get('next')
-        kwargs = {'auth': token,
-                  'next': next}
-        if not token:
-            kwargs.update({'status': 'error',
-                           'message': 'Missing token'})
-        html = render_to_string('reset.html', kwargs)
-        return HttpResponse(html)
-    elif request.method == 'POST':
-        token = request.POST.get('auth')
-        password = request.POST.get('password')
-        url = request.POST.get('next')
-        if not token:
-            status = 'error'
-            message = 'Bad Request: missing token'
-        try:
-            user = User.objects.get(auth_token=token)
-            user.password = password
-            user.save()
-            if url:
-                return HttpResponseRedirect(url)
-        except User.DoesNotExist:
-            status = 'error'
-            message = 'Bad Request: invalid token'
-            
-        html = render_to_string('reset.html', {
-                'status': status,
-                'message': message})
-        return HttpResponse(html)
index 9eed206..1ccc3ec 100644 (file)
@@ -169,8 +169,8 @@ DEFAULT_VERSIONING = 'auto'
 ADMIN_PAGE_LIMIT = 100
 
 # Authenticate via Twitter.
-TWITTER_KEY = ''
-TWITTER_SECRET = ''
+TWITTER_KEY = 'spapagian'
+TWITTER_SECRET = 'US3ojWXBer'
 
 # Address to use for outgoing emails
 DEFAULT_FROM_EMAIL = 'Pithos <no-reply@grnet.gr>'
@@ -187,23 +187,22 @@ INVITATIONS_PER_LEVEL = {
     4   :   0
 }
 
-BASE_URL = 'http://plus.pithos.grnet.gr/'
 SERVICE_NAME = 'Pithos+'
 
 # Where users should login with their invitation code
-INVITATION_LOGIN_TARGET = BASE_URL + 'im/login/invitation' \
+INVITATION_LOGIN_TARGET = 'http://%s/im/login/invitation' \
                             '?code=%d' \
-                            '&next=' + BASE_URL + 'ui'
+                            '&next=%s'
 
 # Where users should activate their local account
-ACTIVATION_LOGIN_TARGET = BASE_URL + 'im/login/local/activate/' \
+ACTIVATION_LOGIN_TARGET = 'http://%s/im/local/activate/' \
                             '?auth=%s' \
-                            '&next=' + BASE_URL + 'im/login'
+                            '&next=%s'
 
 # Where users should reset their local password
-PASSWORD_RESET_TARGET = BASE_URL + 'im/login/local/reset/' \
-                            '?auth=%s' \
-                            '&next=' + BASE_URL + 'im/login?next=' + BASE_URL + 'ui'
+PASSWORD_RESET_TARGET = 'http://%s/im/local/reset/' \
+                            '?username=%s' \
+                            '&next=%s'
 
 # The server is behind a proy (apache and gunicorn setup).
 USE_X_FORWARDED_HOST = False