Exemple #1
0
    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
Exemple #2
0
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
Exemple #3
0
    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/")
Exemple #4
0
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
Exemple #5
0
    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
Exemple #6
0
    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/')