Esempio n. 1
0
 def validate_email(self, field):
     field.data = field.data.lower()  # Convert to lowercase
     existing = UserEmail.get(email=field.data)
     if existing is not None:
         raise wtforms.ValidationError(Markup(
             u'This email address is already registered. Do you want to <a href="{loginurl}">login</a> instead?'.format(
                 loginurl=escape(url_for('.login')))))
Esempio n. 2
0
def get_user_extid(service, userdata):
    """
    Retrieves a 'user', 'extid' and 'useremail' from the given service and userdata.
    """
    provider = login_registry[service]
    extid = getextid(service=service, userid=userdata['userid'])

    user = None
    useremail = None

    if userdata.get('email'):
        useremail = UserEmail.get(email=userdata['email'])

    if extid is not None:
        user = extid.user
    # It is possible at this time that extid.user and useremail.user are different.
    # We do not handle it here, but in the parent function login_service_postcallback.
    elif useremail is not None and useremail.user is not None:
        user = useremail.user
    else:
        # Cross-check with all other instances of the same LoginProvider (if we don't have a user)
        # This is (for eg) for when we have two Twitter services with different access levels.
        for other_service, other_provider in login_registry.items():
            if other_service != service and other_provider.__class__ == provider.__class__:
                other_extid = getextid(service=other_service, userid=userdata['userid'])
                if other_extid is not None:
                    user = other_extid.user
                    break

    # TODO: Make this work when we have multiple confirmed email addresses available
    return user, extid, useremail
Esempio n. 3
0
def get_user_extid(service, userdata):
    """
    Retrieves a 'user', 'extid' and 'useremail' from the given service and userdata.
    """
    provider = login_registry[service]
    extid = getextid(service=service, userid=userdata['userid'])

    user = None
    useremail = None

    if userdata.get('email'):
        useremail = UserEmail.get(email=userdata['email'])

    if extid is not None:
        user = extid.user
    # It is possible at this time that extid.user and useremail.user are different.
    # We do not handle it here, but in the parent function login_service_postcallback.
    elif useremail is not None and useremail.user is not None:
        user = useremail.user
    else:
        # Cross-check with all other instances of the same LoginProvider (if we don't have a user)
        # This is (for eg) for when we have two Twitter services with different access levels.
        for other_service, other_provider in login_registry.items():
            if other_service != service and other_provider.__class__ == provider.__class__:
                other_extid = getextid(service=other_service,
                                       userid=userdata['userid'])
                if other_extid is not None:
                    user = other_extid.user
                    break

    # TODO: Make this work when we have multiple confirmed email addresses available
    return user, extid, useremail
Esempio n. 4
0
 def validate_email(self, field):
     field.data = field.data.lower()  # Convert to lowercase
     existing = UserEmail.get(email=field.data)
     if existing is not None:
         raise wtforms.ValidationError(
             Markup(
                 u'This email address is already registered. Do you want to <a href="{loginurl}">login</a> instead?'
                 .format(loginurl=escape(url_for('.login')))))
Esempio n. 5
0
 def validate_email(self, field):
     field.data = field.data.lower()  # Convert to lowercase
     existing = UserEmail.get(email=field.data)
     if existing is not None:
         if existing.user == g.user:
             raise forms.ValidationError(_("You have already registered this email address"))
         else:
             raise forms.ValidationError(_("This email address has already been claimed"))
     existing = UserEmailClaim.get(email=field.data, user=g.user)
     if existing is not None:
         raise forms.ValidationError(_("This email address is pending verification"))
Esempio n. 6
0
 def validate_email(self, field):
     field.data = field.data.lower()  # Convert to lowercase
     existing = UserEmail.get(email=field.data)
     if existing is not None:
         if existing.user == g.user:
             raise wtforms.ValidationError(
                 "You have already registered this email address.")
         else:
             raise wtforms.ValidationError(
                 "This email address has already been claimed.")
     existing = UserEmailClaim.get(email=field.data, user=g.user)
     if existing is not None:
         raise wtforms.ValidationError(
             "This email address is pending verification.")
Esempio n. 7
0
 def validate_email(self, field):
     field.data = field.data.lower()  # Convert to lowercase
     existing = UserEmail.get(email=field.data)
     if existing is not None:
         if existing.user == current_auth.user:
             raise forms.ValidationError(
                 _("You have already registered this email address"))
         else:
             raise forms.ValidationError(
                 _("This email address has already been claimed"))
     existing = UserEmailClaim.get_for(user=current_auth.user,
                                       email=field.data)
     if existing is not None:
         raise forms.ValidationError(
             _("This email address is pending verification"))
Esempio n. 8
0
def login_service_postcallback(service, userdata):
    """
    Called from :func:login_service_callback after receiving data from the upstream login service
    """
    # 1. Check whether we have an existing UserExternalId
    user, extid, useremail = get_user_extid(service, userdata)
    # If extid is not None, user.extid == user, guaranteed.
    # If extid is None but useremail is not None, user == useremail.user
    # However, if both extid and useremail are present, they may be different users

    if extid is not None:
        extid.oauth_token = userdata.get('oauth_token')
        extid.oauth_token_secret = userdata.get('oauth_token_secret')
        extid.oauth_token_type = userdata.get('oauth_token_type')
        extid.username = userdata.get('username')
        # TODO: Save refresh token and expiry date where present
        extid.oauth_refresh_token = userdata.get('oauth_refresh_token')
        extid.oauth_expiry_date = userdata.get('oauth_expiry_date')
        extid.oauth_refresh_expiry = userdata.get(
            'oauth_refresh_expiry')  # TODO: Check this
        extid.last_used_at = db.func.utcnow()
    else:
        # New external id. Register it.
        extid = UserExternalId(
            user=user,  # This may be None right now. Will be handled below
            service=service,
            userid=userdata['userid'],
            username=userdata.get('username'),
            oauth_token=userdata.get('oauth_token'),
            oauth_token_secret=userdata.get('oauth_token_secret'),
            oauth_token_type=userdata.get('oauth_token_type'),
            last_used_at=db.func.utcnow()
            # TODO: Save refresh token
        )

    if user is None:
        if current_auth:
            # Attach this id to currently logged-in user
            user = current_auth.user
            extid.user = user
        else:
            # Register a new user
            user = register_internal(None, userdata.get('fullname'), None)
            extid.user = user
            if userdata.get('username'):
                if valid_username(userdata['username']) and user.is_valid_name(
                        userdata['username']):
                    # Set a username for this user if it's available
                    user.username = userdata['username']
    else:  # We have an existing user account from extid or useremail
        if current_auth and current_auth.user != user:
            # Woah! Account merger handler required
            # Always confirm with user before doing an account merger
            session['merge_buid'] = user.buid
        elif useremail and useremail.user != user:
            # Once again, account merger required since the extid and useremail are linked to different users
            session['merge_buid'] = useremail.user.buid

    # Check for new email addresses
    if userdata.get('email') and not useremail:
        user.add_email(userdata['email'])

    # If there are multiple email addresses, add any that are not already claimed.
    # If they are already claimed by another user, this calls for an account merge
    # request, but we can only merge two users at a time. Ask for a merge if there
    # isn't already one pending
    if userdata.get('emails'):
        for email in userdata['emails']:
            existing = UserEmail.get(email)
            if existing:
                if existing.user != user and 'merge_buid' not in session:
                    session['merge_buid'] = existing.user.buid
            else:
                user.add_email(email)

    if userdata.get('emailclaim'):
        emailclaim = UserEmailClaim(user=user, email=userdata['emailclaim'])
        db.session.add(emailclaim)
        send_email_verify_link(emailclaim)

    # Is the user's fullname missing? Populate it.
    if not user.fullname and userdata.get('fullname'):
        user.fullname = userdata['fullname']

    if not current_auth:  # If a user isn't already logged in, login now.
        login_internal(user)
        flash(
            _("You have logged in via {service}").format(
                service=login_registry[service].title),
            'success',
        )
    next_url = get_next_url(session=True)

    db.session.add(extid)  # If we made a new extid, add it to the session now
    db.session.commit()

    # Finally: set a login method cookie and send user on their way
    if not current_auth.user.is_profile_complete():
        login_next = url_for('.account_new', next=next_url)
    else:
        login_next = next_url

    if 'merge_buid' in session:
        return set_loginmethod_cookie(
            redirect(url_for('.account_merge', next=login_next), code=303),
            service)
    else:
        return set_loginmethod_cookie(redirect(login_next, code=303), service)
Esempio n. 9
0
 def validate_email(self, field):
     field.data = field.data.lower()  # Convert to lowercase
     existing = UserEmail.get(email=field.data)
     if existing is not None and existing.user != self.edit_obj:
         raise wtforms.ValidationError("This email address has been claimed by another user")
Esempio n. 10
0
 def validate_email(self, field):
     existing = UserEmail.get(email=field.data)
     if existing is not None and existing.user != self.edit_obj:
         raise forms.ValidationError(_("This email address has been claimed by another user"))
Esempio n. 11
0
 def validate_email(self, field):
     existing = UserEmail.get(email=field.data)
     if existing is not None and existing.user != self.edit_obj:
         raise forms.ValidationError(
             _("This email address has been claimed by another user"))
Esempio n. 12
0
def login_service_postcallback(service, userdata):
    """
    Called from :func:login_service_callback after receiving data from the upstream login service
    """
    # 1. Check whether we have an existing UserExternalId
    user, extid, useremail = get_user_extid(service, userdata)
    # If extid is not None, user.extid == user, guaranteed.
    # If extid is None but useremail is not None, user == useremail.user
    # However, if both extid and useremail are present, they may be different users

    if extid is not None:
        extid.oauth_token = userdata.get('oauth_token')
        extid.oauth_token_secret = userdata.get('oauth_token_secret')
        extid.oauth_token_type = userdata.get('oauth_token_type')
        extid.username = userdata.get('username')
        # TODO: Save refresh token and expiry date where present
        extid.oauth_refresh_token = userdata.get('oauth_refresh_token')
        extid.oauth_expiry_date = userdata.get('oauth_expiry_date')
        extid.oauth_refresh_expiry = userdata.get('oauth_refresh_expiry')  # TODO: Check this
        extid.last_used_at = db.func.utcnow()
    else:
        # New external id. Register it.
        extid = UserExternalId(
            user=user,  # This may be None right now. Will be handled below
            service=service,
            userid=userdata['userid'],
            username=userdata.get('username'),
            oauth_token=userdata.get('oauth_token'),
            oauth_token_secret=userdata.get('oauth_token_secret'),
            oauth_token_type=userdata.get('oauth_token_type'),
            last_used_at=db.func.utcnow()
            # TODO: Save refresh token
            )

    if user is None:
        if current_auth:
            # Attach this id to currently logged-in user
            user = current_auth.user
            extid.user = user
        else:
            # Register a new user
            user = register_internal(None, userdata.get('fullname'), None)
            extid.user = user
            if userdata.get('username'):
                if valid_username(userdata['username']) and user.is_valid_name(userdata['username']):
                    # Set a username for this user if it's available
                    user.username = userdata['username']
    else:  # We have an existing user account from extid or useremail
        if current_auth and current_auth.user != user:
            # Woah! Account merger handler required
            # Always confirm with user before doing an account merger
            session['merge_buid'] = user.buid
        elif useremail and useremail.user != user:
            # Once again, account merger required since the extid and useremail are linked to different users
            session['merge_buid'] = useremail.user.buid

    # Check for new email addresses
    if userdata.get('email') and not useremail:
        user.add_email(userdata['email'])

    # If there are multiple email addresses, add any that are not already claimed.
    # If they are already claimed by another user, this calls for an account merge
    # request, but we can only merge two users at a time. Ask for a merge if there
    # isn't already one pending
    if userdata.get('emails'):
        for email in userdata['emails']:
            existing = UserEmail.get(email)
            if existing:
                if existing.user != user and 'merge_buid' not in session:
                    session['merge_buid'] = existing.user.buid
            else:
                user.add_email(email)

    if userdata.get('emailclaim'):
        emailclaim = UserEmailClaim(user=user, email=userdata['emailclaim'])
        db.session.add(emailclaim)
        send_email_verify_link(emailclaim)

    # Is the user's fullname missing? Populate it.
    if not user.fullname and userdata.get('fullname'):
        user.fullname = userdata['fullname']

    if not current_auth:  # If a user isn't already logged in, login now.
        login_internal(user)
        flash(_(u"You have logged in via {service}").format(service=login_registry[service].title), 'success')
    next_url = get_next_url(session=True)

    db.session.add(extid)  # If we made a new extid, add it to the session now
    db.session.commit()

    # Finally: set a login method cookie and send user on their way
    if not current_auth.user.is_profile_complete():
        login_next = url_for('.account_new', next=next_url)
    else:
        login_next = next_url

    if 'merge_buid' in session:
        return set_loginmethod_cookie(redirect(url_for('.account_merge', next=login_next), code=303), service)
    else:
        return set_loginmethod_cookie(redirect(login_next, code=303), service)
Esempio n. 13
0
 def validate_email(self, field):
     field.data = field.data.lower()  # Convert to lowercase
     existing = UserEmail.get(email=field.data)
     if existing is not None and existing.user != self.edit_obj:
         raise wtforms.ValidationError(
             "This email address has been claimed by another user")
Esempio n. 14
0
def login_service_postcallback(service, userdata):
    user, extid, useremail = get_user_extid(service, userdata)

    if extid is not None:
        extid.oauth_token = userdata.get("oauth_token")
        extid.oauth_token_secret = userdata.get("oauth_token_secret")
        extid.oauth_token_type = userdata.get("oauth_token_type")
        extid.username = userdata.get("username")
        # TODO: Save refresh token and expiry date where present
        extid.oauth_refresh_token = userdata.get("oauth_refresh_token")
        extid.oauth_expiry_date = userdata.get("oauth_expiry_date")
        extid.oauth_refresh_expiry = userdata.get("oauth_refresh_expiry")  # TODO: Check this
    else:
        # New external id. Register it.
        extid = UserExternalId(
            user=user,  # This may be None right now. Will be handled below
            service=service,
            userid=userdata["userid"],
            username=userdata.get("username"),
            oauth_token=userdata.get("oauth_token"),
            oauth_token_secret=userdata.get("oauth_token_secret"),
            oauth_token_type=userdata.get("oauth_token_type")
            # TODO: Save refresh token
        )
        db.session.add(extid)

    if user is None:
        if g.user:
            # Attach this id to currently logged-in user
            user = g.user
            extid.user = user
        else:
            # Register a new user
            user = register_internal(None, userdata.get("fullname"), None)
            extid.user = user
            if userdata.get("username"):
                if valid_username(userdata["username"]) and user.is_valid_username(userdata["username"]):
                    # Set a username for this user if it's available
                    user.username = userdata["username"]
    else:  # This id is attached to a user
        if g.user and g.user != user:
            # Woah! Account merger handler required
            # Always confirm with user before doing an account merger
            session["merge_userid"] = user.userid

    # Check for new email addresses
    if userdata.get("email") and not useremail:
        user.add_email(userdata["email"])

    # If there are multiple email addresses, add any that are not already claimed.
    # If they are already claimed by another user, this calls for an account merge
    # request, but we can only merge two users at a time. Ask for a merge if there
    # isn't already one pending
    if userdata.get("emails"):
        for email in userdata["emails"]:
            existing = UserEmail.get(email)
            if existing:
                if existing.user != user and "merge_userid" not in session:
                    session["merge_userid"] = existing.user.userid
            else:
                user.add_email(email)

    if userdata.get("emailclaim"):
        emailclaim = UserEmailClaim(user=user, email=userdata["emailclaim"])
        db.session.add(emailclaim)
        send_email_verify_link(emailclaim)

    # Is the user's fullname missing? Populate it.
    if not user.fullname and userdata.get("fullname"):
        user.fullname = userdata["fullname"]

    if not g.user:  # If a user isn't already logged in, login now.
        login_internal(user)
        flash(_(u"You have logged in via {service}").format(service=login_registry[service].title), "success")
    next_url = get_next_url(session=True)

    db.session.commit()

    # Finally: set a login method cookie and send user on their way
    if not user.is_profile_complete():
        login_next = url_for(".profile_new", next=next_url)
    else:
        login_next = next_url

    if "merge_userid" in session:
        return set_loginmethod_cookie(redirect(url_for(".profile_merge", next=login_next), code=303), service)
    else:
        return set_loginmethod_cookie(redirect(login_next, code=303), service)
Esempio n. 15
0
def confirm_email(md5sum, secret):
    emailclaim = UserEmailClaim.get_by(md5sum=md5sum, verification_code=secret)
    if emailclaim is not None:
        if 'verify' in emailclaim.permissions(current_auth.user):
            existing = UserEmail.get(email=emailclaim.email)
            if existing is not None:
                claimed_email = emailclaim.email
                claimed_user = emailclaim.user
                db.session.delete(emailclaim)
                db.session.commit()
                if claimed_user != current_auth.user:
                    return render_message(
                        title=_("Email address already claimed"),
                        message=Markup(
                            _(
                                "The email address <code>{email}</code> has already been verified by another user"
                            ).format(email=escape(claimed_email))
                        ),
                    )
                else:
                    return render_message(
                        title=_("Email address already verified"),
                        message=Markup(
                            _(
                                "Hello <strong>{fullname}</strong>! "
                                "Your email address <code>{email}</code> has already been verified"
                            ).format(
                                fullname=escape(claimed_user.fullname),
                                email=escape(claimed_email),
                            )
                        ),
                    )

            useremail = emailclaim.user.add_email(
                emailclaim.email,
                primary=emailclaim.user.email is None,
                type=emailclaim.type,
                private=emailclaim.private,
            )
            db.session.delete(emailclaim)
            UserEmailClaim.all(useremail.email).delete(synchronize_session=False)
            db.session.commit()
            user_data_changed.send(current_auth.user, changes=['email'])
            return render_message(
                title=_("Email address verified"),
                message=Markup(
                    _(
                        "Hello <strong>{fullname}</strong>! "
                        "Your email address <code>{email}</code> has now been verified"
                    ).format(
                        fullname=escape(emailclaim.user.fullname),
                        email=escape(useremail.email),
                    )
                ),
            )
        else:
            return render_message(
                title=_("This was not for you"),
                message=_(
                    "You’ve opened an email verification link that was meant for another user. "
                    "If you are managing multiple accounts, please login with the correct account "
                    "and open the link again"
                ),
                code=403,
            )
    else:
        return render_message(
            title=_("Expired confirmation link"),
            message=_(
                "The confirmation link you clicked on is either invalid or has expired"
            ),
            code=404,
        )