def test_move(self): 'Make sure that only superusers can promote or demote other users' url = self.get_url('user_move') # Check that we only see the login page if the user is not logged in self.assert_('value=Login' in self.post(url).unicode_body) # Check that normal users can't promote or demote other users self.login(self.userN) token = get_token(self.get(self.get_url('user_index')).body) targetUser = db.query(User).filter_by(username=self.userS['username']).first() params = ReplaceableDict(token=token, targetUserID=targetUser.id, is_super=1) self.assert_('value=Login' in self.post(url, params.replace(is_super=0))) self.assert_('value=Login' in self.post(url, params.replace(is_super=1))) # Prepare self.login(self.userS) user = db.query(User).filter_by(username=self.userS['username']).first() token = get_token(self.get(self.get_url('user_index')).body) targetUser = db.query(User).filter_by(username=self.userN['username']).first() params = ReplaceableDict(token=token, targetUserID=targetUser.id, is_super=1) # Check that a bad token fails self.assertJSON(self.post(url, params.replace(token=token + 'x')), 0) # Check that a bad targetUserID fails self.assertJSON(self.post(url, params.replace(targetUserID=0)), 0) # Check that a bad is_super fails self.assertJSON(self.post(url, params.replace(is_super='xxx')), 0) # Check that a super user cannot promote or demote self self.assertJSON(self.post(url, params.replace(targetUserID=user.id, is_super=0)), 0) self.assertJSON(self.post(url, params.replace(targetUserID=user.id, is_super=1)), 0) # Check that a super user can promote or demote other users self.assertJSON(self.post(url, params.replace(is_super=1)), 1) self.assertJSON(self.post(url, params.replace(is_super=0)), 1)
def update_(request): 'Update account' params = request.params if params.get('token') != request.session.get_csrf_token(): return dict(isOk=0, message='Invalid token') userID = authenticated_userid(request) # If the user is trying to update account information, send confirmation email if 'username' in params: return save_user_(request, dict(params), 'update', db.query(User).get(userID)) # Load smsAddressAction = params.get('smsAddressAction') # If the user is adding an SMS address, if 'add' == smsAddressAction: # Make sure it is a valid email address validateEmail = validators.Email().to_python try: smsAddressEmail = validateEmail(params.get('smsAddressEmail', '')) except Invalid, error: return dict(isOk=0, message=str(error)) # Check for duplicates smsAddress = db.query(SMSAddress).filter( (SMSAddress.email == smsAddressEmail) & (SMSAddress.user_id == userID)).first() if smsAddress: return dict(isOk=0, message='You already added this SMS address') # Add it to the database smsAddress = SMSAddress(email=smsAddressEmail, user_id=userID, code=make_random_string(CODE_LEN)) db.add(smsAddress) # Send confirmation code get_mailer(request).send_to_queue(Message( recipients=[smsAddress.email], body=smsAddress.code)) # Return smsAddresses return dict(isOk=1, content=render('users/smsAddresses.mak', update(request), request))
def index(request): 'Show registered IMAP accounts' imapAccountQuery = db.query(IMAPAccount).options(joinedload(IMAPAccount.user)) personQuery = db.query(User.id, User.nickname) # statements = [Session.query(model.IMAPMessage.imap_account_id, sa.func.count('*').label('message_count')).filter(model.IMAPMessage.message_status>model.message_incomplete).group_by(model.IMAPMessage.imap_account_id).subquery()] # columns = [model.IMAPAccount] + [x.c.message_count for x in statements] # imapAccountQuery = Session.query(*columns).options(orm.eagerload(model.IMAPAccount.owner)) # for statement in statements: # imapAccountQuery = imapAccountQuery.outerjoin((statement, model.IMAPAccount.id==statement.c.imap_account_id)) return dict(imapAccountPacks=imapAccountQuery.all(), personPacks=personQuery.all())
def test_reset(self): 'Make sure that resetting the password works' url = self.get_url('user_reset') email = self.userN['email'] password_ = hash(self.userN['password']) # Trying to reset an email that does not exist returns an error self.assertJSON(self.post(url, dict(email=email + 'x')), 0) # Resetting the password does not immediately change the password self.assertJSON(self.post(url, dict(email=email)), 1) self.assertEqual(db.query(User).filter_by(email=email, password_=password_).count(), 1) # Apply change self.get(self.get_url('user_confirm', ticket=db.query(User_.ticket).filter_by(email=email).order_by(User_.when_expired.desc()).first()[0])) self.assertEqual(db.query(User).filter_by(email=email, password_=password_).count(), 0)
def _to_python(self, value, user): 'Check whether the value is unique' # If the user is new or the value changed, if not user or getattr(user, self.fieldName) != value: # Make sure the value is unique if db.query(User).filter(getattr(User, self.fieldName)==value).first(): # Raise raise Invalid(self.errorMessage, value, user) # Return return value
def test_update_smsAddress(self): 'Make sure that updating smsAddresses works' url = self.get_url('user_update') # Get token self.login(self.userN) token = get_token(self.get(url).unicode_body) params = ReplaceableDict(token=token, smsAddressAction='add', smsAddressEmail='*****@*****.**') # Add an smsAddress that is not a valid email address self.assertJSON(self.post(url, params.replace(smsAddressEmail='xxx')), 0) # Add an smsAddress that is a valid email address self.login(self.userN) smsAddressEmail = '*****@*****.**' self.assertJSON(self.post(url, params.replace(smsAddressEmail=smsAddressEmail)), 1) smsAddress1 = db.query(SMSAddress).filter_by(email=smsAddressEmail).first() self.login(self.userS) smsAddressEmail = '*****@*****.**' self.assertJSON(self.post(url, params.replace(smsAddressEmail=smsAddressEmail)), 1) smsAddress2 = db.query(SMSAddress).filter_by(email=smsAddressEmail).first() # Add a duplicate smsAddress self.assertJSON(self.post(url, params), 1) self.assertJSON(self.post(url, params), 0) params = ReplaceableDict(token=token, smsAddressAction='activate', smsAddressID=smsAddress1.id, smsAddressCode=smsAddress1.code) self.login(self.userN) # Activate an smsAddress that doesn't belong to the user self.assertJSON(self.post(url, params.replace(smsAddressID=smsAddress2.id, smsAddressCode=smsAddress2.code)), 0) # Activate an smsAddress with a bad code self.assertJSON(self.post(url, params.replace(smsAddressCode=smsAddress1.code + 'x')), 0) # Activate an smsAddress with a good code self.assertJSON(self.post(url, params), 1) params = ReplaceableDict(token=token, smsAddressAction='remove', smsAddressID=smsAddress1.id) # Remove an smsAddress that doesn't belong to the user self.assertJSON(self.post(url, params.replace(smsAddressID=smsAddress2.id)), 0) # Remove an smsAddress that does belong to the user self.assertJSON(self.post(url, params), 1) params = ReplaceableDict(token=token) # Send an invalid command self.assertJSON(self.post(url, params.replace(smsAddressAction='')), 0) self.assertJSON(self.post(url, params.replace(smsAddressAction='xxx')), 0)
def test_registration(self): 'Make sure that registration works' url = self.get_url('user_register') username, password, nickname, email = [self.userN[x].replace('2', '3') for x in 'username', 'password', 'nickname', 'email'] params = ReplaceableDict(username=username, password=password, nickname=nickname, email=email) # Make sure the registration page appears properly self.assert_('Registration' in self.get(url).unicode_body) # Register self.post(url, params) # Register with the same username but with different case self.post(url, params.replace(username=username.upper(), nickname=nickname + 'x', email=email + 'x')) # Register with the same nickname but with different case self.post(url, params.replace(username=username + 'x', nickname=nickname.upper(), email=email + 'x')) # Register with the same email but with different case self.post(url, params.replace(username=username + 'x', nickname=nickname + 'x', email=email.upper())) # Confirm registration self.get(self.get_url('user_confirm', ticket=db.query(User_.ticket).filter_by(email=email).order_by(User_.when_expired.desc()).first()[0])) # Make sure the user exists self.assertEqual(db.query(User).filter_by(email=email).count(), 1) # Make sure that conflicting registrations have been deleted self.assertEqual(db.query(User_).filter_by(password_=hash(password)).count(), 0)
def test_update(self): 'Make sure that updating credentials works' url = self.get_url('user_update') # Check that we only see the login page if the user is not logged in self.assert_('value=Login' in self.get(url).unicode_body) self.assert_('value=Login' in self.post(url).unicode_body) # Check that the update form is filled with the user's credentials self.login(self.userN) body = self.get(url).unicode_body self.assert_(self.userN['username'] in body) self.assert_(self.userN['nickname'] in body) self.assert_(self.userN['email'].lower() in body) token = get_token(body) # Updating credentials requires a token username, password, nickname, email = ['0' + self.userN[x] for x in 'username', 'password', 'nickname', 'email'] password_ = hash(password) params = ReplaceableDict(token=token, username=username, password=password, nickname=nickname, email=email) self.assertJSON(self.post(url, params.replace(token='')), 0) self.assertJSON(self.post(url, params), 1) # Make sure the credentials have not changed yet self.assertEqual(db.query(User).filter_by(username=username, password_=password_, nickname=nickname, email=email).count(), 0) # Make sure the credentials have changed after confirmation self.get(self.get_url('user_confirm', ticket=db.query(User_.ticket).filter_by(email=email).order_by(User_.when_expired.desc()).first()[0])) self.assertEqual(db.query(User).filter_by(username=username, password_=password_, nickname=nickname, email=email).count(), 1)
def reset(request): 'Reset password' # Get email email = request.params.get('email') # Try to load the user user = db.query(User).filter(User.email==email).first() # If the email is not in our database, if not user: return dict(isOk=0) # Reset account return save_user_(request, dict( username=user.username, password=make_random_string(PASSWORD_LEN_MAX), nickname=user.nickname, email=user.email), 'reset', user)
def add(request): 'Add IMAP account' params = request.params if params.get('token') != request.session.get_csrf_token(): return dict(isOk=0, message='Invalid token') accountUserID = params.get('accountUserID', 0) accountHost = params.get('accountHost', '') accountUsername = params.get('accountUsername', '') accountPassword = params.get('accountPassword', '') # Check user if not db.query(User).get(accountUserID): return dict(isOk=0, message='Could not find accountUserID=%s' % accountUserID) # Check account credentials using validators try: form = IMAPAccountForm().to_python(params) except Invalid, error: return dict(isOk=0, errorByID=error.unpack_errors())
def apply_user_(ticket): 'Finalize a change to a user account' # Load user_ = db.query(User_).filter( (User_.ticket == ticket) & (User_.when_expired >= datetime.datetime.utcnow())).first() # If the ticket is valid, if user_: # Apply the change and reset rejection_count db.merge(User( id=user_.user_id, username=user_.username, password_=user_.password_, nickname=user_.nickname, email=user_.email, rejection_count=0)) # Return return user_
def move(request): 'Move a user to a different group' params = request.params if params.get('token') != request.session.get_csrf_token(): return dict(isOk=0, message='Invalid token') userID = authenticated_userid(request) # Load targetUserID = params.get('targetUserID', 0) targetUser = db.query(User).get(targetUserID) is_super = params.get('is_super', 0) if not targetUser: return dict(isOk=0, message='Could not find targetUserID=%s' % targetUserID) if int(userID) == int(targetUserID): return dict(isOk=0, message='Cannot promote or demote yourself') try: is_super = bool(int(is_super)) except ValueError: return dict(isOk=0, message='Could not parse is_super=%s' % is_super) targetUser.is_super = is_super return dict(isOk=1)
def login_(request): 'Process login credentials' # Make shortcuts environ, params, registry = [getattr(request, x) for x in 'environ', 'params', 'registry'] username, password = [params.get(x, '').strip() for x in 'username', 'password'] if not username or not password: return dict(isOk=0) # Check username user = db.query(User).filter_by(username=username).first() if not user: return dict(isOk=0) # If the password is incorrect, increment and return rejection_count if user.password_ != hash(password): user.rejection_count += 1 return dict(isOk=0, rejection_count=user.rejection_count) # If there have been too many rejections, expect recaptcha if user.rejection_count >= REJECTION_LIMIT: rChallenge, rResponse = [params.get(x, '') for x in 'recaptcha_challenge', 'recaptcha_response'] rPrivate = registry.settings.get('recaptcha.private', '') clientIP = environ.get('HTTP_X_REAL_IP', environ.get('HTTP_X_FORWARDED_FOR', environ.get('REMOTE_ADDR'))) # If the response is not valid, say so if not captcha.submit(rChallenge, rResponse, rPrivate, clientIP).is_valid: return dict(isOk=0, rejection_count=user.rejection_count) # Save user try: user.offset = int(params.get('offset', MINUTES_OFFSET)) except ValueError: user.offset = MINUTES_OFFSET user.when_login = datetime.datetime.utcnow() user.rejection_count = 0 # Set headers to set cookie if not hasattr(request, 'response_headerlist'): request.response_headerlist = [] request.response_headerlist.extend(remember(request, user.id, tokens=format_tokens(user))) # Return return dict(isOk=1)
(SMSAddress.user_id == userID)).first() if smsAddress: return dict(isOk=0, message='You already added this SMS address') # Add it to the database smsAddress = SMSAddress(email=smsAddressEmail, user_id=userID, code=make_random_string(CODE_LEN)) db.add(smsAddress) # Send confirmation code get_mailer(request).send_to_queue(Message( recipients=[smsAddress.email], body=smsAddress.code)) # Return smsAddresses return dict(isOk=1, content=render('users/smsAddresses.mak', update(request), request)) # Make sure the smsAddressID belongs to the user smsAddressID = params.get('smsAddressID') smsAddress = db.query(SMSAddress).filter( (SMSAddress.id == smsAddressID) & (SMSAddress.user_id == userID)).first() if not smsAddress: return dict(isOk=0, message='Could not find smsAddressID=%s corresponding to userID=%s' % (smsAddressID, userID)) # If the user is activating an SMS address, if 'activate' == smsAddressAction: # If the code is not correct, return error message if params.get('smsAddressCode') != smsAddress.code: return dict(isOk=0, message='Code is not valid') # Clear code smsAddress.code = None return dict(isOk=1) # If the user is removing an SMS address, elif 'remove' == smsAddressAction: db.delete(smsAddress) return dict(isOk=1)
def index(request): 'Show information about people registered in the database' return dict(users=db.query(User).order_by(User.when_login.desc()).all())
def test_index(self): 'Assert that the user index page shows how many accounts are on file' url = self.get_url('user_index') # Make sure that the user index page is visible self.assert_('%s users' % db.query(User).count() in self.get(url).unicode_body)
def update(request): 'Show account update page' userID = authenticated_userid(request) user = db.query(User).options(joinedload(User.sms_addresses)).get(userID) return dict(user=user)