Exemplo n.º 1
0
def two_factor_setup():
    """View function for two-factor setup.

    This is used both for GET to fetch forms and POST to actually set configuration
    (and send token).

    There are 3 cases for setting up:
    1) initial login and application requires 2FA
    2) changing existing 2FA information
    3) user wanting to enable or disable 2FA (assuming application doesn't require it)

    In order to CHANGE/ENABLE/DISABLE a 2FA information, user must be properly logged in
    AND have a 'fresh' authentication.

    For initial login when 2FA required of course user can't be logged in - in this
    case we need to have been sent some
    state via the session as part of login to show a) who and b) that they successfully
    authenticated.
    """
    form_class = _security.two_factor_setup_form

    if request.is_json:
        if request.content_length:
            form = form_class(MultiDict(request.get_json()),
                              meta=suppress_form_csrf())
        else:
            form = form_class(formdata=None, meta=suppress_form_csrf())
    else:
        form = form_class(meta=suppress_form_csrf())

    if not current_user.is_authenticated:
        # This is the initial login case
        # We can also get here from setup if they want to change TODO: how?
        if not all(k in session for k in
                   ["tf_user_id", "tf_state"]) or session["tf_state"] not in [
                       "setup_from_login", "validating_profile"
                   ]:
            # illegal call on this endpoint
            tf_clean_session()
            return _tf_illegal_state(form, _security.login_url)

        user = _datastore.find_user(fs_uniquifier=session["tf_user_id"])
        if not user:
            tf_clean_session()
            return _tf_illegal_state(form, _security.login_url)

    else:
        # Caller is changing their TFA profile. This requires a 'fresh' authentication
        if not check_and_update_authn_fresh(
                config_value("FRESHNESS"),
                config_value("FRESHNESS_GRACE_PERIOD"),
                get_request_attr("fs_authn_via"),
        ):
            return _security._reauthn_handler(
                config_value("FRESHNESS"),
                config_value("FRESHNESS_GRACE_PERIOD"))
        user = current_user

    if form.validate_on_submit():
        # Before storing in DB and therefore requiring 2FA we need to
        # make sure it actually works.
        # Requiring 2FA is triggered by having BOTH tf_totp_secret and
        # tf_primary_method in the user record (or having the application
        # global config TWO_FACTOR_REQUIRED)
        # Until we correctly validate the 2FA - we don't set primary_method in
        # user model but use the session to store it.

        pm = form.setup.data
        session[
            "tf_totp_secret"] = _security._totp_factory.generate_totp_secret()
        session["tf_primary_method"] = pm
        session["tf_state"] = "validating_profile"

        json_response = {
            "tf_state": "validating_profile",
            "tf_primary_method": pm,
        }

        if pm == "disable":
            tf_disable(user)
            after_this_request(view_commit)
            if not _security._want_json(request):
                do_flash(*get_message("TWO_FACTOR_DISABLED"))
                return redirect(get_url(_security.post_login_view))

        elif pm == "sms" or pm == "email":
            if pm == "sms":
                user.tf_phone_number = form.sms.phone.data
                _datastore.put(user)
                after_this_request(view_commit)

            msg = user.tf_send_security_token(
                method=pm,
                totp_secret=session["tf_totp_secret"],
                phone_number=getattr(user, "tf_phone_number", None),
            )
            if msg:
                # send code didn't work
                form.setup.errors = list()
                form.setup.errors.append(msg)
                if _security._want_json(request):
                    return base_render_json(form,
                                            include_user=False,
                                            error_status_code=500)
        elif pm == "authenticator":
            authr_setup_values = user.tf_get_authenticator_values(
                session["tf_totp_secret"])

            # is this insecure if we go through base_render_json?
            json_response.update(
                dict(
                    authr_qrcode=authr_setup_values["image"],
                    authr_key=authr_setup_values["key"],
                    authr_username=authr_setup_values["username"],
                    authr_issuer=authr_setup_values["issuer"],
                ))

        code_form = _security.two_factor_verify_code_form()
        if not _security._want_json(request):
            return _security.render_template(
                config_value("TWO_FACTOR_SETUP_TEMPLATE"),
                two_factor_setup_form=form,
                two_factor_verify_code_form=code_form,
                **json_response,
                **_ctx("tf_setup"),
            )
        return base_render_json(form,
                                include_user=False,
                                additional=json_response)

    # We get here on GET and POST with failed validation.
    # For things like phone number - we've already done one POST
    # that succeeded and now it failed - so retain the initial info
    choices = config_value("TWO_FACTOR_ENABLED_METHODS")
    if not config_value("TWO_FACTOR_REQUIRED"):
        choices.append("disable")

    if _security._want_json(request):
        # Provide information application/UI might need to render their own form/input
        json_response = {
            "tf_required": config_value("TWO_FACTOR_REQUIRED"),
            "tf_primary_method": getattr(user, "tf_primary_method", None),
            "tf_phone_number": getattr(user, "tf_phone_number", None),
            "tf_available_methods": choices,
        }
        return base_render_json(form,
                                include_user=False,
                                additional=json_response)

    code_form = _security.two_factor_verify_code_form()
    return _security.render_template(
        config_value("TWO_FACTOR_SETUP_TEMPLATE"),
        two_factor_setup_form=form,
        two_factor_verify_code_form=code_form,
        choices=choices,
        chosen_method=form.setup.data,
        two_factor_required=config_value("TWO_FACTOR_REQUIRED"),
        **_ctx("tf_setup"),
    )
Exemplo n.º 2
0
async def legal_privacy():
    return redirect('/legal/#privacy-policy')
Exemplo n.º 3
0
async def logout():
    discord_session.revoke()
    return redirect('/' if not request.referrer else request.referrer)
Exemplo n.º 4
0
 async def login():
     authorization_url, state = flow.authorization_url()
     session["state"] = state
     return redirect(authorization_url)
Exemplo n.º 5
0
async def redirect_to_login(*_):
    await flash("You need to be logged in to view this page", "red")
    return redirect(url_for("login.login"))
Exemplo n.º 6
0
async def search():
    return redirect(url_for('index'))
Exemplo n.º 7
0
async def index():
    if not session.get('username'):
        return redirect(url_for("me.web_login"))
    return await render_template('manage.html',bot_name=bot_name, group_name=group_name)
Exemplo n.º 8
0
async def Code():
    data = await discord.callback()
    redirect_to = data.get("redirect", "/home")
    return redirect(redirect_to)
Exemplo n.º 9
0
async def logout():
    session.pop('logged_in', None)
    await flash('You were logged out...')
    return redirect(url_for('posts'))
Exemplo n.º 10
0
async def index():
    return redirect('/home')
Exemplo n.º 11
0
async def logout():
    discord.revoke()
    return redirect(url_for(".index"))
Exemplo n.º 12
0
async def root():
    return quart.redirect("/index")
Exemplo n.º 13
0
async def before_request():
    if not current_user.is_authenticated:
        return redirect(url_for('auth.login'))
Exemplo n.º 14
0
def two_factor_token_validation():
    """View function for two-factor token validation

    Two cases:
    1) normal login case - everything setup correctly; normal 2FA validation
       In this case - user not logged in -
       but 'tf_state' == 'ready' or 'validating_profile'
    2) validating after CHANGE/ENABLE 2FA. In this case user logged in/authenticated

    """

    form_class = _security.two_factor_verify_code_form

    if request.is_json:
        form = form_class(MultiDict(request.get_json()),
                          meta=suppress_form_csrf())
    else:
        form = form_class(meta=suppress_form_csrf())

    changing = current_user.is_authenticated
    if not changing:
        # This is the normal login case OR initial setup
        if (not all(k in session for k in ["tf_user_id", "tf_state"])
                or session["tf_state"] not in ["ready", "validating_profile"]
                or
            (session["tf_state"] == "validating_profile"
             and not all(k in session
                         for k in ["tf_primary_method", "tf_totp_secret"]))):
            # illegal call on this endpoint
            tf_clean_session()
            return _tf_illegal_state(form, _security.login_url)

        user = _datastore.find_user(fs_uniquifier=session["tf_user_id"])
        form.user = user
        if not user:
            tf_clean_session()
            return _tf_illegal_state(form, _security.login_url)

        if session["tf_state"] == "ready":
            pm = user.tf_primary_method
            totp_secret = user.tf_totp_secret
        else:
            pm = session["tf_primary_method"]
            totp_secret = session["tf_totp_secret"]
    else:
        # Changing TFA profile - user is already authenticated.
        if (not all(k in session for k in ["tf_state", "tf_primary_method"])
                or session["tf_state"] != "validating_profile"):
            tf_clean_session()
            # logout since this seems like attack-ish/logic error
            logout_user()
            return _tf_illegal_state(form, _security.login_url)
        pm = session["tf_primary_method"]
        totp_secret = session["tf_totp_secret"]
        form.user = current_user

    form.primary_method = pm
    form.tf_totp_secret = totp_secret
    if form.validate_on_submit():
        # Success - log in user and clear all session variables
        remember = session.pop("tf_remember_login", None)
        completion_message = complete_two_factor_process(
            form.user, pm, totp_secret, changing, remember)

        after_this_request(view_commit)

        if not _security._want_json(request):
            after_this_request(
                partial(
                    tf_set_validity_token_cookie,
                    fs_uniquifier=form.user.fs_uniquifier,
                    remember=remember,
                ))
            do_flash(*get_message(completion_message))

            return redirect(get_post_login_redirect())

        if (not config_value("TWO_FACTOR_ALWAYS_VALIDATE")
                and remember) and _security._want_json(request):
            token = generate_tf_validity_token(form.user.fs_uniquifier)
            json_response = {"tf_validity_token": token}
            return base_render_json(form, additional=json_response)
    # GET or not successful POST
    if _security._want_json(request):
        return base_render_json(form)

    # if we were trying to validate a new method
    if changing:
        setup_form = _security.two_factor_setup_form()

        return _security.render_template(
            config_value("TWO_FACTOR_SETUP_TEMPLATE"),
            two_factor_setup_form=setup_form,
            two_factor_verify_code_form=form,
            choices=config_value("TWO_FACTOR_ENABLED_METHODS"),
            **_ctx("tf_setup"),
        )

    # if we were trying to validate an existing method
    else:
        rescue_form = _security.two_factor_rescue_form()

        return _security.render_template(
            config_value("TWO_FACTOR_VERIFY_CODE_TEMPLATE"),
            two_factor_rescue_form=rescue_form,
            two_factor_verify_code_form=form,
            problem=None,
            **_ctx("tf_token_validation"),
        )
Exemplo n.º 15
0
def us_signin():
    """
    Unified sign in view.
    This takes an identity (as configured in USER_IDENTITY_ATTRIBUTES)
    and a passcode (password or OTP).

    Allow already authenticated users. For GET this is useful for
    single-page-applications on refresh - session still active but need to
    access user info and csrf-token.
    For POST - redirects to POST_LOGIN_VIEW (forms) or returns 400 (json).
    """

    if current_user.is_authenticated and request.method == "POST":
        # Just redirect current_user to POST_LOGIN_VIEW (or next).
        # While its tempting to try to logout the current user and login the
        # new requested user - that simply doesn't work with CSRF.

        # While this is close to anonymous_user_required - it differs in that
        # it uses get_post_login_redirect which correctly handles 'next'.
        # TODO: consider changing anonymous_user_required to also call
        # get_post_login_redirect - not sure why it never has?
        if _security._want_json(request):
            payload = json_error_response(
                errors=get_message("ANONYMOUS_USER_REQUIRED")[0])
            return _security._render_json(payload, 400, None, None)
        else:
            return redirect(get_post_login_redirect())

    form_class = _security.us_signin_form

    if request.is_json:
        if request.content_length:
            form = form_class(MultiDict(request.get_json()),
                              meta=suppress_form_csrf())
        else:
            form = form_class(formdata=None, meta=suppress_form_csrf())
    else:
        form = form_class(meta=suppress_form_csrf())
    form.submit.data = True

    if form.validate_on_submit():
        # Require multi-factor is it is enabled, and the method
        # we authenticated with requires it and either user has requested MFA or it is
        # required.
        remember_me = form.remember.data if "remember" in form else None
        if (config_value("TWO_FACTOR")
                and form.authn_via in config_value("US_MFA_REQUIRED") and
            (config_value("TWO_FACTOR_REQUIRED") or is_tf_setup(form.user))):
            return tf_login(form.user,
                            remember=remember_me,
                            primary_authn_via=form.authn_via)

        after_this_request(_commit)
        login_user(form.user, remember=remember_me, authn_via=[form.authn_via])

        if _security._want_json(request):
            return base_render_json(form, include_auth_token=True)

        return redirect(get_post_login_redirect())

    # Here on GET or failed POST validate
    code_methods = _compute_code_methods()
    if _security._want_json(request):
        payload = {
            "available_methods": config_value("US_ENABLED_METHODS"),
            "code_methods": code_methods,
            "identity_attributes": get_identity_attributes(),
        }
        return base_render_json(form, include_user=False, additional=payload)

    if current_user.is_authenticated:
        # Basically a no-op if authenticated - just perform the same
        # post-login redirect as if user just logged in.
        return redirect(get_post_login_redirect())

    # On error - wipe code
    form.passcode.data = None
    return _security.render_template(
        config_value("US_SIGNIN_TEMPLATE"),
        us_signin_form=form,
        available_methods=config_value("US_ENABLED_METHODS"),
        code_methods=code_methods,
        skip_login_menu=True,
        **_security._run_ctx_processor("us_signin"))
Exemplo n.º 16
0
async def nadd():
    form = await request.form
    if form["inputbar"]:
        addNote(form["inputbar"])

    return redirect(url_for("home"))
Exemplo n.º 17
0
def us_verify_link():
    """
    Used to verify a magic email link. GET only
    """
    if not all(v in request.args for v in ["email", "code"]):
        m, c = get_message("API_ERROR")
        if _security.redirect_behavior == "spa":
            return redirect(get_url(_security.login_error_view, qparams={c:
                                                                         m}))
        do_flash(m, c)
        return redirect(url_for_security("us_signin"))

    user = _datastore.find_user(email=request.args.get("email"))
    if not user or not user.active:
        if not user:
            m, c = get_message("USER_DOES_NOT_EXIST")
        else:
            m, c = get_message("DISABLED_ACCOUNT")
        if _security.redirect_behavior == "spa":
            return redirect(get_url(_security.login_error_view, qparams={c:
                                                                         m}))
        do_flash(m, c)
        return redirect(url_for_security("us_signin"))

    totp_secrets = _datastore.us_get_totp_secrets(user)
    if "email" not in totp_secrets or not _security._totp_factory.verify_totp(
            token=request.args.get("code"),
            totp_secret=totp_secrets["email"],
            user=user,
            window=config_value("US_TOKEN_VALIDITY"),
    ):
        m, c = get_message("INVALID_CODE")
        if _security.redirect_behavior == "spa":
            return redirect(
                get_url(
                    _security.login_error_view,
                    qparams=user.get_redirect_qparams({c: m}),
                ))
        do_flash(m, c)
        return redirect(url_for_security("us_signin"))

    if (config_value("TWO_FACTOR")
            and "email" in config_value("US_MFA_REQUIRED")
            and (config_value("TWO_FACTOR_REQUIRED") or is_tf_setup(user))):
        # tf_login doesn't know anything about "spa" etc. In general two-factor
        # isn't quite ready for SPA. So we return an error via a redirect rather
        # than mess up SPA applications. To be clear - this simply doesn't
        # work - using a magic link w/ 2FA - need to use code.
        if _security.redirect_behavior == "spa":
            return redirect(
                get_url(
                    _security.login_error_view,
                    qparams=user.get_redirect_qparams({"tf_required": 1}),
                ))
        return tf_login(user, primary_authn_via="email")

    login_user(user, authn_via=["email"])
    after_this_request(_commit)
    if _security.redirect_behavior == "spa":
        # We do NOT send the authentication token here since the only way to
        # send it would be via a query param and that isn't secure. (logging and
        # possibly HTTP Referer header).
        # This means that this can only work if sessions are active which sort of
        # makes sense - otherwise you need to use /us-signin with a code.
        return redirect(
            get_url(_security.post_login_view,
                    qparams=user.get_redirect_qparams()))

    do_flash(*get_message("PASSWORDLESS_LOGIN_SUCCESSFUL"))
    return redirect(get_post_login_redirect())
Exemplo n.º 18
0
async def nedit():
    form = await request.form
    print(form)
    if form["editNote"] and form["inputbar"]:
        editNote(form["editNote"], form["inputbar"])
    return redirect(url_for("home"))
Exemplo n.º 19
0
def logout():
    # clear session cookie
    session.pop('logged_in', None)
    return redirect(url_for('index'))
Exemplo n.º 20
0
async def ndel():
    form = await request.form
    if form["deleteNote"]:
        delNote(form["deleteNote"])
    return redirect(url_for("home"))
Exemplo n.º 21
0
async def redir_to_static_site():
    if "localhost" not in request.url:
        return redirect("https://files.pycode.tk/", status_code=301)
    return "test"
Exemplo n.º 22
0
async def home():
    return redirect('https://syllabics.app/', status_code=301)
Exemplo n.º 23
0
 async def logout():
     session.clear()
     return redirect("/landing")
Exemplo n.º 24
0
async def about():
    return redirect('/#why-camus')
Exemplo n.º 25
0
async def bot_support():
    return redirect('https://discord.gg/f3MaASW')
Exemplo n.º 26
0
async def chat_index():
    return redirect('/', code=307)
Exemplo n.º 27
0
async def legal_tos():
    return redirect('/legal/#terms')
Exemplo n.º 28
0
 async def redir():
     return redirect(request.args["path"])
Exemplo n.º 29
0
async def callback():
    data = await discord_session.callback()
    await discord_session.fetch_user()
    return redirect("/" if not request.referrer else request.referrer)
Exemplo n.º 30
0
def reset_password(token):
    """View function that handles a reset password request.

    This is usually called via GET as part of an email link and redirects to
    a reset-password form
    It is called via POST to actually update the password (and then redirects to
    a post reset/login view)
    If in either case the token is either invalid or expired it redirects to
    the 'forgot-password' form.

    In the case of non-form based configuration:
    For GET normal case - redirect to RESET_VIEW?token={token}&email={email}
    For GET invalid case - redirect to RESET_ERROR_VIEW?error={error}&email={email}
    For POST normal/successful case - return 200 with new authentication token
    For POST error case return 400 with form.errors
    """

    expired, invalid, user = reset_password_token_status(token)
    form_class = _security.reset_password_form
    if request.is_json:
        form = form_class(MultiDict(request.get_json()),
                          meta=suppress_form_csrf())
    else:
        form = form_class(meta=suppress_form_csrf())
    form.user = user

    if request.method == "GET":
        if not user or invalid:
            m, c = get_message("INVALID_RESET_PASSWORD_TOKEN")
            if _security.redirect_behavior == "spa":
                return redirect(
                    get_url(_security.reset_error_view, qparams={c: m}))
            do_flash(m, c)
            return redirect(url_for_security("forgot_password"))
        if expired:
            send_reset_password_instructions(user)
            m, c = get_message(
                "PASSWORD_RESET_EXPIRED",
                email=user.email,
                within=_security.reset_password_within,
            )
            if _security.redirect_behavior == "spa":
                return redirect(
                    get_url(
                        _security.reset_error_view,
                        qparams=user.get_redirect_qparams({c: m}),
                    ))
            do_flash(m, c)
            return redirect(url_for_security("forgot_password"))

        # All good - for SPA - redirect to the ``reset_view``
        if _security.redirect_behavior == "spa":
            return redirect(
                get_url(
                    _security.reset_view,
                    qparams=user.get_redirect_qparams({"token": token}),
                ))
        # for forms - render the reset password form
        return _security.render_template(
            config_value("RESET_PASSWORD_TEMPLATE"),
            reset_password_form=form,
            reset_password_token=token,
            **_ctx("reset_password"),
        )

    # This is the POST case.
    m = None
    if not user or invalid:
        invalid = True
        m, c = get_message("INVALID_RESET_PASSWORD_TOKEN")
        if not _security._want_json(request):
            do_flash(m, c)

    if expired:
        send_reset_password_instructions(user)
        m, c = get_message(
            "PASSWORD_RESET_EXPIRED",
            email=user.email,
            within=_security.reset_password_within,
        )
        if not _security._want_json(request):
            do_flash(m, c)

    if invalid or expired:
        if _security._want_json(request):
            return _security._render_json(json_error_response(m), 400, None,
                                          None)
        else:
            return redirect(url_for_security("forgot_password"))

    if form.validate_on_submit():
        after_this_request(view_commit)
        update_password(user, form.password.data)
        if config_value("TWO_FACTOR") and (
                config_value("TWO_FACTOR_REQUIRED") or
            (form.user.tf_totp_secret and form.user.tf_primary_method)):
            return tf_login(user, primary_authn_via="reset")
        login_user(user, authn_via=["reset"])
        if _security._want_json(request):
            login_form = _security.login_form()
            login_form.user = user
            return base_render_json(login_form, include_auth_token=True)
        else:
            do_flash(*get_message("PASSWORD_RESET"))
            return redirect(
                get_url(_security.post_reset_view)
                or get_url(_security.post_login_view))

    # validation failure case - for forms - we try again including the token
    # for non-forms -  we just return errors and assume caller remembers token.
    if _security._want_json(request):
        return base_render_json(form)
    return _security.render_template(
        config_value("RESET_PASSWORD_TEMPLATE"),
        reset_password_form=form,
        reset_password_token=token,
        **_ctx("reset_password"),
    )