def post(self, **post): try: data = Bunch(register_form.native(post)[0]) except Exception as e: if config.get('debug', False): raise return 'json:', dict(success=False, message=_("Unable to parse data."), data=post, exc=str(e)) if not data.username or not data.email or not data.password or data.password != data.pass2: return 'json:', dict(success=False, message=_("Missing data or passwords do not match."), data=data) #Make sure that the provided email address is a valid form for an email address v = EmailValidator() email = data.email email, err = v.validate(email) if err: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) #If the password isn't strong enough, reject it if(zxcvbn.password_strength(data.password).get("score") < MINIMUM_PASSWORD_STRENGTH): return 'json:', dict(success=False, message=_("Password provided is too weak. please add more characters, or include lowercase, uppercase, and special characters."), data=data) #Ensures that the provided username and email are lowercase user = User(data.username.lower(), data.email.lower(), active=True) user.password = data.password try: user.save() except ValidationError: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) except NotUniqueError: return 'json:', dict(success=False, message=_("Either the username or email address provided is already taken."), data=data) authenticate(user.username, data.password) return 'json:', dict(success=True, location="/")
def post(self, **post): try: data = Bunch(register_form.native(post)[0]) except Exception as e: if config.get('debug', False): raise return 'json:', dict(success=False, message=_("Unable to parse data."), data=post, exc=str(e)) if not data.username or not data.email or not data.password or data.password != data.pass2: return 'json:', dict( success=False, message=_("Missing data or passwords do not match."), data=data) #Make sure that the provided email address is a valid form for an email address v = EmailValidator() email = data.email email, err = v.validate(email) if err: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) #If the password isn't strong enough, reject it if (zxcvbn.password_strength(data.password).get("score") < MINIMUM_PASSWORD_STRENGTH): return 'json:', dict( success=False, message= _("Password provided is too weak. please add more characters, or include lowercase, uppercase, and special characters." ), data=data) #Ensures that the provided username and email are lowercase user = User(data.username.lower(), data.email.lower(), active=True) user.password = data.password try: user.save() except ValidationError: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) except NotUniqueError: return 'json:', dict( success=False, message= _("Either the username or email address provided is already taken." ), data=data) authenticate(user.username, data.password) return 'json:', dict(success=True, location="/")
def test_partial_collision(self): # check that with a colliding username, email is still migrated id1 = User(username="******", email="*****@*****.**").save().id id2 = User(username="******", email="*****@*****.**").save(validate=False).id failures = case_migration.migrate() self.assertEqual(len(User.objects), 2) self.check_user(id1, "user", "*****@*****.**") self.check_user(id2, "USER", "*****@*****.**") self.assertEqual(len(failures), 1)
def pull_character(self, info): """This always updates all information on the character, so that we do not end up with inconsistencies. There is some weirdness that, if a user already has a key with full permissions, and adds a limited one, we'll erase information on that character. We should probably check for and refresh info from the most-permissioned key instead of this.""" from brave.core.character.model import EVEAlliance, EVECorporation, EVECharacter try: char = EVECharacter(identifier=info.characterID).save() new = True except NotUniqueError: char = EVECharacter.objects(identifier=info.characterID)[0] new = False if char.owner and self.owner != char.owner: log.warning("Security violation detected. Multiple accounts trying to register character %s, ID %d. " "Actual owner is %s. User adding this character is %s.", char.name, info.characterID, EVECharacter.objects(identifier=info.characterID).first().owner, self.owner) self.violation = "Character" # Mark both accounts as duplicates of each other. User.add_duplicate(self.owner, char.owner) return try: if self.mask.has_access(api.char.CharacterSheet.mask): info = api.char.CharacterSheet(self, characterID=info.characterID) elif self.mask.has_access(api.char.CharacterInfoPublic.mask): info = api.char.CharacterInfoPublic(self, characterID=info.characterID) except Exception: log.warning("An error occured while querying data for key %s.", self.key) if new: char.delete() raise char.corporation, char.alliance = self.get_membership(info) char.name = info.name if 'name' in info else info.characterName char.owner = self.owner if self not in char.credentials: char.credentials.append(self) char.race = info.race if 'race' in info else None char.bloodline = (info.bloodLine if 'bloodLine' in info else info.bloodline if 'bloodline' in info else None) char.ancestry = info.ancestry if 'ancestry' in info else None char.gender = info.gender if 'gender' in info else None char.security = info.security if 'security' in info else None char.titles = [strip_tags(i.titleName) for i in info.corporationTitles.row] if 'corporationTitles' in info else [] char.roles = [i.roleName for i in info.corporationRoles.row] if 'corporationRoles' in info else [] char.save() return char
def test_email_collision(self): # check that colliding email is not modified id1 = User(username="******", email="*****@*****.**").save().id id2 = User(username="******", email="*****@*****.**").save(validate=False).id failures = case_migration.migrate() self.assertEqual(len(User.objects), 2) self.check_user(id1, "user1", "*****@*****.**") self.check_user(id2, "user2", "*****@*****.**") self.assertEqual(len(failures), 1)
def post(self, username=None, userMethod=None, ip=None, duplicate=None): # Have to be an admin to access admin pages. if not is_administrator: raise HTTPNotFound() # Seed the initial results. users = User.objects() # Limit to users with the specified username. if username: if userMethod == 'contains': users = users.filter(username__icontains=username) elif userMethod == 'starts': users = users.filter(username__istartswith=username) elif userMethod == 'is': users = users.filter(username__iexact=username) else: return 'json:', dict(success=False, message=_("You broke the web page. Good Job.")) # Limit to users with the specified IP address. if ip: users = users.filter(host=ip) # Limit to users with the specified duplicate status if duplicate.lower() == "ip": users = users.filter(other_accs_IP__exists=True) elif duplicate.lower() == "char": users = users.filter(other_accs_char_key__exists=True) return 'brave.core.admin.template.searchUser', dict(area='admin', result=users, success=True)
def post(self, username=None, userMethod=None, ip=None, duplicate=None): # Have to be an admin to access admin pages. if not is_administrator: raise HTTPNotFound() # Seed the initial results. users = User.objects() # Limit to users with the specified username. if username: if userMethod == 'contains': users = users.filter(username__icontains=username) elif userMethod == 'starts': users = users.filter(username__istartswith=username) elif userMethod == 'is': users = users.filter(username__iexact=username) else: return 'json:', dict( success=False, message=_("You broke the web page. Good Job.")) # Limit to users with the specified IP address. if ip: users = users.filter(host=ip) # Limit to users with the specified duplicate status if duplicate.lower() == "ip": users = users.filter(other_accs_IP__exists=True) elif duplicate.lower() == "char": users = users.filter(other_accs_char_key__exists=True) return 'brave.core.admin.template.searchUser', dict(area='admin', result=users, success=True)
def test_no_change_case(self): id = User(username="******", email="*****@*****.**").save().id case_migration.migrate() self.assertEqual(len(User.objects), 1) self.check_user(id, "user", "*****@*****.**")
def test_lowercased(self): id = User(username="******", email="*****@*****.**").save(validate=False).id case_migration.migrate() self.assertEqual(len(User.objects), 1) self.check_user(id, "user", "*****@*****.**")
def migrate(): failures = [] for u in User.objects(): username_success = ensure_lowercase(u, 'username') email_success = ensure_lowercase(u, 'email') if not username_success or not email_success: failures.append(u) return failures
def lookup(identifier): """Thaw current user data based on session-stored user ID.""" user = User.objects(id=identifier).first() if user: user.update(set__seen=datetime.utcnow()) # , set__host=request.remote_addr -- chicken-egg problem return user
def ensure_lowercase(u, field): if u[field] != u[field].lower(): try: updated = User.objects(id=u.id, **{field:u[field]}).update_one( **{'set__'+field: u[field].lower()}) if not updated: print("failure updating {} (raced user?): {}".format(field, u)) return False except OperationError: print("collision updating {}: {}".format(field, u)) return False return True
def authenticate(identifier, password): """Given an e-mail address (or Yubikey OTP) and password, authenticate a user.""" ts = time() # Record the query = dict(active=True) # Gracefully handle extended characters in passwords. # The password storage algorithm works in binary. if isinstance(password, unicode): password = password.encode('utf8') # Build the MongoEngine query to find if '@' in identifier: query[b'email'] = identifier elif len(identifier) == 44: query[b'otp'] = identifier[:12] else: query[b'username'] = identifier user = User.objects(**query).first() if not user or not User.password.check(user.password, password) or (user.rotp and len(user.otp) != 0 and not 'otp' in query): if user: LoginHistory(user, False, request.remote_addr).save() # Prevent basic timing attacks; always take at least one second to process. sleep(max(min(1 - (time() - ts), 0), 1)) return None # Validate Yubikey OTP if 'otp' in query: client = yubico.Yubico( config['yubico.client'], config['yubico.key'], boolean(config.get('yubico.secure', False)) ) try: status = client.verify(identifier, return_response=True) except: return None if not status: return None user.update(set__seen=datetime.utcnow()) # Record the fact the user signed in. LoginHistory(user, True, request.remote_addr).save() return user.id, user
def ensure_lowercase(u, field): if u[field] != u[field].lower(): try: updated = User.objects(id=u.id, **{ field: u[field] }).update_one(**{'set__' + field: u[field].lower()}) if not updated: print("failure updating {} (raced user?): {}".format(field, u)) return False except OperationError: print("collision updating {}: {}".format(field, u)) return False return True
def authenticate(identifier, password): """Given an e-mail address (or Yubikey OTP) and password, authenticate a user.""" ts = time() # Record the query = dict(active=True) # Gracefully handle extended characters in passwords. # The password storage algorithm works in binary. if isinstance(password, unicode): password = password.encode("utf8") # Build the MongoEngine query to find if "@" in identifier: query[b"email"] = identifier elif len(identifier) == 44: query[b"otp"] = identifier[:12] else: query[b"username"] = identifier user = User.objects(**query).first() if ( not user or not User.password.check(user.password, password) or (user.rotp and len(user.otp) != 0 and not "otp" in query) ): if user: LoginHistory(user, False, request.remote_addr).save() # Prevent basic timing attacks; always take at least one second to process. sleep(max(min(1 - (time() - ts), 0), 1)) return None # Validate Yubikey OTP if "otp" in query: client = yubico.Yubico( config["yubico.client"], config["yubico.key"], boolean(config.get("yubico.secure", False)) ) try: status = client.verify(identifier, return_response=True) except: return None if not status: return None user.update(set__seen=datetime.utcnow()) # Record the fact the user signed in. LoginHistory(user, True, request.remote_addr).save() # Update the user's host user.host = request.remote_addr # Check for other accounts with this IP address if len(User.objects(host=request.remote_addr)) > 1: # Quite possibly the worst code ever for u in User.objects(host=request.remote_addr): User.add_duplicate(user, u, IP=True) user.save() return user.id, user
def post(self, **post): try: data = Bunch(post) except Exception as e: if config.get('debug', False): raise return 'json:', dict(success=False, message=_("Unable to parse data."), data=post, exc=str(e)) query = dict(active=True) query[b'username'] = data.id user = User.objects(**query).first() if data.form == "changepassword": passwd_ok, error_msg = _check_password(data.passwd, data.passwd1) if not passwd_ok: return 'json:', dict(success=False, message=error_msg, data=data) if isinstance(data.old, unicode): data.old = data.old.encode('utf-8') if not User.password.check(user.password, data.old): return 'json:', dict(success=False, message=_("Old password incorrect."), data=data) #If the password isn't strong enough, reject it if (zxcvbn.password_strength(data.passwd).get("score") < MINIMUM_PASSWORD_STRENGTH): return 'json:', dict( success=False, message= _("Password provided is too weak. please add more characters, or include lowercase, uppercase, and special characters." ), data=data) user.password = data.passwd user.save() elif data.form == "addotp": if isinstance(data.password, unicode): data.password = data.password.encode('utf-8') identifier = data.otp client = yubico.Yubico(config['yubico.client'], config['yubico.key'], boolean(config.get('yubico.secure', False))) if not User.password.check(user.password, data.password): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) try: status = client.verify(identifier, return_response=True) except: return 'json:', dict(success=False, message=_("Failed to contact YubiCloud."), data=data) if not status: return 'json:', dict(success=False, message=_("Failed to verify key."), data=data) if not User.addOTP(user, identifier[:12]): return 'json:', dict(success=False, message=_("YubiKey already exists."), data=data) elif data.form == "removeotp": identifier = data.otp if not User.removeOTP(user, identifier[:12]): return 'json:', dict(success=False, message=_("YubiKey invalid."), data=data) elif data.form == "configureotp": if isinstance(data.password, unicode): data.password = data.password.encode('utf-8') rotp = True if 'rotp' in data else False if not User.password.check(user.password, data.password): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) user.rotp = rotp user.save() #Handle the user attempting to delete their account elif data.form == "deleteaccount": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') #Make the user enter their username so they know what they're doing. if not user.username == data.username.lower(): return 'json:', dict(success=False, message=_("Username incorrect."), data=data) #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) #Make them type "delete" exactly if not data.confirm == "delete": return 'json:', dict( success=False, message=_( "Delete was either misspelled or not lowercase."), data=data) #Delete the user account and then deauthenticate the browser session log.info("User %s authorized the deletion of their account.", user) user.delete() deauthenticate() #Redirect user to the root of the server instead of the settings page return 'json:', dict(success=True, location="/") #Handle the user attempting to change the email address associated with their account elif data.form == "changeemail": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) #Check that the two provided email addresses match if not data.newEmail.lower() == data.newEmailConfirm.lower(): return 'json:', dict( success=False, message=_("Provided email addresses do not match."), data=data) #Make sure that the provided email address is a valid form for an email address v = EmailValidator() email = data.newEmail email, err = v.validate(email) if err: return 'json:', dict( success=False, message=_("Invalid email address provided."), data=data) #Make sure that the new email address is not already taken count = User.objects.filter(**{ "email": data.newEmail.lower() }).count() if not count == 0: return 'json:', dict( success=False, message=_("The email address provided is already taken."), data=data) #Change the email address in the database and catch any email validation exceptions that mongo throws user.email = data.newEmail.lower() try: user.save() except ValidationError: return 'json:', dict( success=False, message=_("Invalid email address provided."), data=data) except NotUniqueError: return 'json:', dict( success=False, message=_("The email address provided is already taken."), data=data) #Handle the user attempting to merge 2 accounts together elif data.form == "mergeaccount": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') if isinstance(data.passwd2, unicode): data.passwd2 = data.passwd2.encode('utf-8') #Make the user enter their username so they know what they're doing. if user.username != data.username.lower( ) and user.username != data.username: return 'json:', dict(success=False, message=_("First username incorrect."), data=data) #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("First password incorrect."), data=data) #Make sure the user isn't trying to merge their account into itself. if data.username.lower() == data.username2.lower(): return 'json:', dict( success=False, message=_("You can't merge an account into itself."), data=data) #Make the user enter the second username so we can get the User object they want merged in. if not User.objects( username=data.username2.lower()) and not User.objects( username=data.username2): return 'json:', dict( success=False, message=_("Unable to find user by second username."), data=data) other = User.objects(username=data.username2).first() if not other: other = User.objects(username=data.username2.lower()).first() #Check whether the user's supplied password is correct if not User.password.check(other.password, data.passwd2): return 'json:', dict(success=False, message=_("Second password incorrect."), data=data) #Make them type "merge" exactly if data.confirm != "merge": return 'json:', dict( success=False, message=_("Merge was either misspelled or not lowercase."), data=data) log.info("User %s merged account %s into %s.", user.username, other.username, user.username) user.merge(other) #Redirect user to the root of the server instead of the settings page return 'json:', dict(success=True, location="/") else: return 'json:', dict(success=False, message=_("Form does not exist."), location="/") return 'json:', dict(success=True, location="/account/settings")
def pull_character(self, info): """This always updates all information on the character, so that we do not end up with inconsistencies. There is some weirdness that, if a user already has a key with full permissions, and adds a limited one, we'll erase information on that character. We should probably check for and refresh info from the most-permissioned key instead of this.""" from brave.core.character.model import EVEAlliance, EVECorporation, EVECharacter try: char = EVECharacter(identifier=info.characterID).save() new = True except NotUniqueError: char = EVECharacter.objects(identifier=info.characterID)[0] new = False if char.owner and self.owner != char.owner: log.warning( "Security violation detected. Multiple accounts trying to register character %s, ID %d. " "Actual owner is %s. User adding this character is %s.", char.name, info.characterID, EVECharacter.objects( identifier=info.characterID).first().owner, self.owner) self.violation = "Character" # Mark both accounts as duplicates of each other. User.add_duplicate(self.owner, char.owner) return try: if self.mask.has_access(api.char.CharacterSheet.mask): info = api.char.CharacterSheet(self, characterID=info.characterID) elif self.mask.has_access(api.char.CharacterInfoPublic.mask): info = api.char.CharacterInfoPublic( self, characterID=info.characterID) except Exception: log.warning("An error occured while querying data for key %s.", self.key) if new: char.delete() raise char.corporation, char.alliance = self.get_membership(info) char.name = info.name if 'name' in info else info.characterName char.owner = self.owner if self not in char.credentials: char.credentials.append(self) char.race = info.race if 'race' in info else None char.bloodline = (info.bloodLine if 'bloodLine' in info else info.bloodline if 'bloodline' in info else None) char.ancestry = info.ancestry if 'ancestry' in info else None char.gender = info.gender if 'gender' in info else None char.security = info.security if 'security' in info else None char.titles = [ strip_tags(i.titleName) for i in info.corporationTitles.row ] if 'corporationTitles' in info else [] char.roles = [i.roleName for i in info.corporationRoles.row ] if 'corporationRoles' in info else [] char.save() return char
def lookup_email(email): """get user by email address""" user = User.objects(email=email).first() return user
def check_user(self, id, username, email): u = User.objects(id=id)[0] self.assertEqual(u.username, username) self.assertEqual(u.email, email)
def post(self, **kw): data = Bunch(kw) try: data.key = int(data.key) if data.key <= int(config['core.minimum_key_id']): return 'json:', dict( success=False, message=_( "The key given (%d) must be above minimum reset floor value of %d. " "Please reset your EVE API Key." % (data.key, int(config['core.minimum_key_id']))), field='key') except ValueError: return 'json:', dict(success=False, message=_("Key ID must be a number."), field='key') record = EVECredential(data.key, data.code, owner=user.id) try: record.save() #Necessary to guarantee that the pull finished before returning. record.pull() characters = [] for character in record.characters: characters.append( dict(identifier=character.identifier, name=character.name)) if request.is_xhr: return 'json:', dict( success=True, message=_("Successfully added EVE API key."), identifier=str(record.id), key=record.key, code=record.code, characters=characters, violation=record.violation) except ValidationError: if request.is_xhr: return 'json:', dict( success=False, message= _("Validation error: one or more fields are incorrect or missing." ), ) except NotUniqueError: if EVECredential.objects(key=data.key): # Mark both of these accounts as duplicates to each other. acc = User.objects(username=user.username).first() other = EVECredential.objects(key=data.key).first().owner User.add_duplicate(acc, other) return 'json:', dict( success=False, message= _("This key has already been added to this or another account." ), ) raise HTTPFound(location='/key/')
def post(self, **post): try: data = Bunch(post) except Exception as e: if config.get('debug', False): raise return 'json:', dict(success=False, message=_("Unable to parse data."), data=post, exc=str(e)) query = dict(active=True) query[b'username'] = data.id query_user = User.objects(**query).first() if query_user.id != user.id: raise HTTPForbidden if data.form == "changepassword": passwd_ok, error_msg = _check_password(data.passwd, data.passwd1) if not passwd_ok: return 'json:', dict(success=False, message=error_msg, data=data) if isinstance(data.old, unicode): data.old = data.old.encode('utf-8') if not User.password.check(user.password, data.old): return 'json:', dict(success=False, message=_("Old password incorrect."), data=data) #If the password isn't strong enough, reject it if(zxcvbn.password_strength(data.passwd).get("score") < MINIMUM_PASSWORD_STRENGTH): return 'json:', dict(success=False, message=_("Password provided is too weak. please add more characters, or include lowercase, uppercase, and special characters."), data=data) user.password = data.passwd user.save() elif data.form == "addotp": if isinstance(data.password, unicode): data.password = data.password.encode('utf-8') identifier = data.otp client = yubico.Yubico( config['yubico.client'], config['yubico.key'], boolean(config.get('yubico.secure', False)) ) if not User.password.check(user.password, data.password): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) try: status = client.verify(identifier, return_response=True) except: return 'json:', dict(success=False, message=_("Failed to contact YubiCloud."), data=data) if not status: return 'json:', dict(success=False, message=_("Failed to verify key."), data=data) if not User.addOTP(user, identifier[:12]): return 'json:', dict(success=False, message=_("YubiKey already exists."), data=data) elif data.form == "removeotp": identifier = data.otp if not User.removeOTP(user, identifier[:12]): return 'json:', dict(success=False, message=_("YubiKey invalid."), data=data) elif data.form == "configureotp": if isinstance(data.password, unicode): data.password = data.password.encode('utf-8') rotp = True if 'rotp' in data else False if not User.password.check(user.password, data.password): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) user.rotp = rotp user.save() #Handle the user attempting to delete their account elif data.form == "deleteaccount": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') #Make the user enter their username so they know what they're doing. if not user.username == data.username.lower(): return 'json:', dict(success=False, message=_("Username incorrect."), data=data) #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) #Make them type "delete" exactly if not data.confirm == "delete": return 'json:', dict(success=False, message=_("Delete was either misspelled or not lowercase."), data=data) #Delete the user account and then deauthenticate the browser session log.info("User %s authorized the deletion of their account.", user) user.delete() deauthenticate() #Redirect user to the root of the server instead of the settings page return 'json:', dict(success=True, location="/") #Handle the user attempting to change the email address associated with their account elif data.form == "changeemail": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("Password incorrect."), data=data) #Check that the two provided email addresses match if not data.newEmail.lower() == data.newEmailConfirm.lower(): return 'json:', dict(success=False, message=_("Provided email addresses do not match."), data=data) #Make sure that the provided email address is a valid form for an email address v = EmailValidator() email = data.newEmail email, err = v.validate(email) if err: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) #Make sure that the new email address is not already taken count = User.objects.filter(**{"email": data.newEmail.lower()}).count() if not count == 0: return 'json:', dict(success=False, message=_("The email address provided is already taken."), data=data) #Change the email address in the database and catch any email validation exceptions that mongo throws user.email = data.newEmail.lower() try: user.save() except ValidationError: return 'json:', dict(success=False, message=_("Invalid email address provided."), data=data) except NotUniqueError: return 'json:', dict(success=False, message=_("The email address provided is already taken."), data=data) #Handle the user attempting to merge 2 accounts together elif data.form == "mergeaccount": if isinstance(data.passwd, unicode): data.passwd = data.passwd.encode('utf-8') if isinstance(data.passwd2, unicode): data.passwd2 = data.passwd2.encode('utf-8') #Make the user enter their username so they know what they're doing. if user.username != data.username.lower() and user.username != data.username: return 'json:', dict(success=False, message=_("First username incorrect."), data=data) #Check whether the user's supplied password is correct if not User.password.check(user.password, data.passwd): return 'json:', dict(success=False, message=_("First password incorrect."), data=data) #Make sure the user isn't trying to merge their account into itself. if data.username.lower() == data.username2.lower(): return 'json:', dict(success=False, message=_("You can't merge an account into itself."), data=data) #Make the user enter the second username so we can get the User object they want merged in. if not User.objects(username=data.username2.lower()) and not User.objects(username=data.username2): return 'json:', dict(success=False, message=_("Unable to find user by second username."), data=data) other = User.objects(username=data.username2).first() if not other: other = User.objects(username=data.username2.lower()).first() #Check whether the user's supplied password is correct if not User.password.check(other.password, data.passwd2): return 'json:', dict(success=False, message=_("Second password incorrect."), data=data) #Make them type "merge" exactly if data.confirm != "merge": return 'json:', dict(success=False, message=_("Merge was either misspelled or not lowercase."), data=data) log.info("User %s merged account %s into %s.", user.username, other.username, user.username) user.merge(other) #Redirect user to the root of the server instead of the settings page return 'json:', dict(success=True, location="/") else: return 'json:', dict(success=False, message=_("Form does not exist."), location="/") return 'json:', dict(success=True, location="/account/settings")
def post(self, **kw): data = Bunch(kw) try: data.key = int(data.key) if data.key <= int(config["core.minimum_key_id"]): return ( "json:", dict( success=False, message=_( "The key given (%d) must be above minimum reset floor value of %d. " "Please reset your EVE API Key." % (data.key, int(config["core.minimum_key_id"])) ), field="key", ), ) except ValueError: return "json:", dict(success=False, message=_("Key ID must be a number."), field="key") record = EVECredential(data.key, data.code, owner=user.id) try: record.save() # Necessary to guarantee that the pull finished before returning. record.pull() characters = [] for character in record.characters: characters.append(dict(identifier=character.identifier, name=character.name)) if request.is_xhr: return ( "json:", dict( success=True, message=_("Successfully added EVE API key."), identifier=str(record.id), key=record.key, code=record.code, characters=characters, violation=record.violation, ), ) except ValidationError: if request.is_xhr: return ( "json:", dict(success=False, message=_("Validation error: one or more fields are incorrect or missing.")), ) except NotUniqueError: if EVECredential.objects(key=data.key): # Mark both of these accounts as duplicates to each other. acc = User.objects(username=user.username).first() other = EVECredential.objects(key=data.key).first().owner User.add_duplicate(acc, other) return ( "json:", dict(success=False, message=_("This key has already been added to this or another account.")), ) raise HTTPFound(location="/key/")