Пример #1
0
    def on_get(self, req, resp):
        if not req.context["user"]:
            raise HTTPBadRequest()

        if not req.context["user"].mfa_enabled:
            resp.append_header("Refresh", "5;url=/")

            return self.render_template(req,
                                        resp,
                                        "message_gate.html",
                                        gate_message=Message(
                                            "warning", "No MFA",
                                            "You do not have MFA enabled."),
                                        redirect_uri="/")

        if not req.context["session"].awaiting_mfa:
            resp.append_header("Refresh", "5;url=/")

            return self.render_template(
                req,
                resp,
                "message_gate.html",
                gate_message=Message(
                    "warning", "Already authenticated",
                    "You have already authenticated with MFA."),
                redirect_uri="/")

        self.render_template(req, resp, "mfa/challenge.html")
Пример #2
0
    def on_get(self, req, resp):
        params = {}

        if not req.get_param("post", store=params):
            resp.append_header("Refresh", "5;url=/admin/news/")

            return self.render_template(
                req, resp, "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Missing post ID", "Please include the ID of the post you want to edit"
                ),
                redirect_uri="/admin/news"
            )

        db_session = req.context["db_session"]

        try:
            post = db_session.query(NewsPost).filter_by(id=int(params["post"])).one()
        except NoResultFound:
            resp.append_header("Refresh", "5;url=/admin/news/")

            return self.render_template(
                req, resp, "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Error", "No such post: {}".format(params["post"])
                ),
                redirect_uri="/admin/news"
            )
        else:
            self.render_template(
                req, resp, "admin/news_create.html",
                post=post
            )
Пример #3
0
    def __call__(self, req, resp, product_id):
        db_session = req.context["db_session"]
        resp.append_header("Refresh", "5;url=/admin/products")

        try:
            product = db_session.query(Product).filter_by(
                id=int(product_id)).one()
        except NoResultFound:
            return self.render_template(
                req,
                resp,
                "admin/message_gate.html",
                gate_message=Message("danger", "Error",
                                     "No such product: {}".format(product_id)),
                redirect_uri="/admin/products")
        else:
            db_session.delete(product)

        return self.render_template(req,
                                    resp,
                                    "admin/message_gate.html",
                                    gate_message=Message(
                                        "info", "Product deleted",
                                        "Product has been deleted."),
                                    redirect_uri="/admin/products")
Пример #4
0
    def on_get(self, req, resp):
        params = {}
        resp.append_header("Refresh", "5;url=/admin/news/")

        if not req.get_param("post", store=params):
            return self.render_template(
                req, resp, "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Missing post ID", "Please include the ID of the post you want to delete"
                ),
                redirect_uri="/admin/news"
            )

        db_session = req.context["db_session"]

        try:
            post = db_session.query(NewsPost).filter_by(id=int(params["post"])).one()
        except NoResultFound:
            return self.render_template(
                req, resp, "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Error", "No such post: {}".format(params["post"])
                ),
                redirect_uri="/admin/news"
            )
        else:
            notify_post(post)

            return self.render_template(
                req, resp, "admin/message_gate.html",
                gate_message=Message(
                    "success", "Notifications scheduled", "Notifications for this post have been resent."
                ),
                redirect_uri="/admin/news"
            )
Пример #5
0
    def __call__(self, req, resp, key):
        db_session = req.context["db_session"]
        resp.append_header("Refresh", "5;url=/")

        try:
            code = db_session.query(EmailCode).filter_by(code=key).one()
        except NoResultFound:
            return self.render_template(
                req,
                resp,
                "message_gate.html",
                gate_message=Message(
                    "danger", "Unable to verify",
                    "Your account has expired or already been verified"),
                redirect_uri="/")
        else:
            code.user.email_verified = True
            db_session.delete(code)

            return self.render_template(
                req,
                resp,
                "message_gate.html",
                gate_message=Message(
                    "info", "Email verified",
                    "Your account has been verified - you may now log in."),
                redirect_uri="/")
Пример #6
0
    def on_post(self, req, resp):
        user = req.context["user"]
        totp = pyotp.TOTP(user.mfa_token)
        code = req.get_param("code")

        if not code:
            return self.render_template(
                req,
                resp,
                "mfa/challenge.html",
                message=Message(
                    "danger", "Missing code",
                    "Please enter a code from your authenticator application to continue."
                ))

        if totp.verify(code):
            req.context["session"].awaiting_mfa = False
            resp.append_header("Refresh", "5;url=/")

            return self.render_template(
                req,
                resp,
                "message_gate.html",
                gate_message=Message(
                    "success", "Authenticated",
                    "You have logged in and authenticated successfully."),
                redirect_uri="/")
        else:
            db_session = req.context["db_session"]

            try:
                backup_code = db_session.query(BackupCode).filter_by(
                    code=code).one()
            except NoResultFound:
                return self.render_template(
                    req,
                    resp,
                    "mfa/challenge.html",
                    message=Message(
                        "danger", "Invalid code",
                        "The code you entered was invalid. Please try again!"))
            else:
                req.context["session"].awaiting_mfa = False
                db_session.delete(backup_code)

                resp.append_header("Refresh", "30;url=/")

                return self.render_template(
                    req,
                    resp,
                    "message_gate.html",
                    gate_message=Message(
                        "success", "Authenticated",
                        "You have logged in with a backup code. Please note that backup codes are single-use and this "
                        "one has been invalidated. Remember to keep track of the codes you've used, and regenerate "
                        "them as necessary!"),
                    redirect_uri="/")
Пример #7
0
    def __call__(self, req, resp, user_id):
        user_id = int(user_id)
        current_user = req.context["user"]

        if user_id == current_user.id:
            # Don't delete yourself!
            resp.append_header("Refresh", "5;url=/admin/users")

            return self.render_template(
                req,
                resp,
                "admin/message_gate.html",
                gate_message=Message("danger", "Error",
                                     "You may not delete your own account."),
                redirect_uri="/admin/users")

        db_session = req.context["db_session"]

        try:
            db_user = db_session.query(User).filter_by(id=user_id).one()
        except NoResultFound:
            resp.append_header("Refresh", "5;url=/admin/users")

            return self.render_template(
                req,
                resp,
                "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Unknown user",
                    "User with ID <code>{}</code> not found.".format(user_id)),
                redirect_uri="/admin/users")
        else:
            if db_user.username == self.manager.database.config.admin_username:
                return self.render_template(
                    req,
                    resp,
                    "admin/message_gate.html",
                    gate_message=Message(
                        "danger", "Error",
                        "You may not delete the configured default admin account."
                    ),
                    redirect_uri="/admin/users")

            db_session.delete(db_user)
            resp.append_header("Refresh", "5;url=/admin/users")

            return self.render_template(req,
                                        resp,
                                        "admin/message_gate.html",
                                        gate_message=Message(
                                            "success", "User deleted",
                                            "That user has been deleted."),
                                        redirect_uri="/admin/users")
Пример #8
0
    def __call__(self, req, resp, user_id):
        user_id = int(user_id)
        current_user = req.context["user"]

        if user_id == current_user.id:
            # Don't promote yourself! (What?)
            resp.append_header("Refresh", "5;url=/admin/users")

            return self.render_template(req,
                                        resp,
                                        "admin/message_gate.html",
                                        gate_message=Message(
                                            "danger", "Error",
                                            "You may not promote yourself."),
                                        redirect_uri="/admin/users")

        db_session = req.context["db_session"]

        try:
            db_user = db_session.query(User).filter_by(id=user_id).one()
        except NoResultFound:
            resp.append_header("Refresh", "5;url=/admin/users")

            return self.render_template(
                req,
                resp,
                "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Unknown user",
                    "User with ID <code>{}</code> not found.".format(user_id)),
                redirect_uri="/admin/users")
        else:
            resp.append_header("Refresh", "5;url=/admin/users")

            if not db_user.admin:
                db_user.admin = True

                return self.render_template(
                    req,
                    resp,
                    "admin/message_gate.html",
                    gate_message=Message("success", "User promoted",
                                         "That user has been promoted."),
                    redirect_uri="/admin/users")
            else:
                return self.render_template(
                    req,
                    resp,
                    "admin/message_gate.html",
                    gate_message=Message("danger", "Error",
                                         "That user is already an admin!"),
                    redirect_uri="/admin/users")
Пример #9
0
    def on_get(self, req, resp):
        user = req.context["user"]

        if not user:
            raise HTTPBadRequest()

        if not user.api_enabled:
            resp.append_header("Refresh", "5;url=/profile")

            return self.render_template(
                req,
                resp,
                "message_gate.html",
                gate_message=Message(
                    "danger", "No access",
                    "You don't have API access - please contact a member of staff if you need it."
                ),
                redirect_uri="/")

        db_session = req.context["db_session"]
        keys = {}

        for key in db_session.query(APIKey).filter_by(user_id=user.id).all():
            keys[key.key] = key.name

        self.render_template(req,
                             resp,
                             "users/api_keys.html",
                             user=user,
                             keys=keys)
Пример #10
0
    def on_post(self, req, resp):
        user = req.context["user"]
        db_session = req.context["db_session"]

        db_session.query(BackupCode).filter_by(user=user).delete(
            synchronize_session="fetch")

        backup_codes = []

        for i in range(10):
            token = secrets.token_urlsafe(24)
            db_session.add(BackupCode(user=user, code=token))
            backup_codes.append(token)

        celery.send_task("send_email",
                         args=["backup_codes", user.email, "MFA backup codes"],
                         kwargs={"codes": backup_codes})

        resp.append_header("Refresh", "5;url=/settings")

        return self.render_template(
            req,
            resp,
            "message_gate.html",
            gate_message=Message("success", "New codes generated",
                                 "New backup codes have been emailed to you."),
            redirect_uri="/settings")
Пример #11
0
    def __call__(self, req, resp, user_id):
        user_id = int(user_id)
        db_session = req.context["db_session"]

        try:
            db_user = db_session.query(User).filter_by(id=user_id).one()
        except NoResultFound:
            resp.append_header("Refresh", "5;url=/admin/users")

            return self.render_template(
                req,
                resp,
                "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Unknown user",
                    "User with ID <code>{}</code> not found.".format(user_id)),
                redirect_uri="/admin/users")
        else:
            resp.append_header("Refresh", "5;url=/admin/users")

            if db_user.mfa_token:
                db_session.query(BackupCode).filter_by(user=db_user).delete(
                    synchronize_session="fetch")

                db_user.mfa_token = None
                db_user.mfa_enabled = False

                return self.render_template(
                    req,
                    resp,
                    "admin/message_gate.html",
                    gate_message=Message(
                        "success", "MFA disabled",
                        "You have disabled MFA for {}".format(
                            db_user.username)),
                    redirect_uri="/admin/users")
            else:
                return self.render_template(
                    req,
                    resp,
                    "admin/message_gate.html",
                    gate_message=Message(
                        "warning", "MFA already disabled",
                        "That user does not have MFA enabled."),
                    redirect_uri="/admin/users")
Пример #12
0
    def __call__(self, req, resp, user_id):
        user_id = int(user_id)
        db_session = req.context["db_session"]

        try:
            db_user = db_session.query(User).filter_by(id=user_id).one()
        except NoResultFound:
            resp.append_header("Refresh", "5;url=/admin/users")

            return self.render_template(
                req,
                resp,
                "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Unknown user",
                    "User with ID <code>{}</code> not found.".format(user_id)),
                redirect_uri="/admin/users")
        else:
            resp.append_header("Refresh", "5;url=/admin/users")

            if not db_user.api_enabled:
                db_user.api_enabled = True

                return self.render_template(
                    req,
                    resp,
                    "admin/message_gate.html",
                    gate_message=Message(
                        "success", "API access granted",
                        "You have granted API access for {}".format(
                            db_user.username)),
                    redirect_uri="/admin/users")
            else:
                return self.render_template(
                    req,
                    resp,
                    "admin/message_gate.html",
                    gate_message=Message("warning", "MFA already disabled",
                                         "That user already has API access."),
                    redirect_uri="/admin/users")
Пример #13
0
    def on_get(self, req, resp):
        params = {}
        resp.append_header("Refresh", "5;url=/admin/news/")

        if not req.get_param("post", store=params):
            return self.render_template(
                req,
                resp,
                "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Missing post ID",
                    "Please include the ID of the post you want to relink"),
                redirect_uri="/admin/news")

        db_session = req.context["db_session"]

        try:
            post = db_session.query(NewsPost).filter_by(
                id=int(params["post"])).one()
        except NoResultFound:
            return self.render_template(req,
                                        resp,
                                        "admin/message_gate.html",
                                        gate_message=Message(
                                            "danger", "Error",
                                            "No such post: {}".format(
                                                params["post"])),
                                        redirect_uri="/admin/news")
        else:
            celery.send_task("link_comments", args=[post.id])

            return self.render_template(req,
                                        resp,
                                        "admin/message_gate.html",
                                        gate_message=Message(
                                            "success", "Relinking scheduled",
                                            "This post is being relinked."),
                                        redirect_uri="/admin/news")
Пример #14
0
    def step_one(self, req, resp):
        password = req.get_param("password")
        user = req.context["user"]

        if not password:
            return self.render_template(
                req,
                resp,
                "mfa/setup/step_one.html",
                message=Message("danger", "Missing Password",
                                "Please enter your password to continue."))

        password = base64.b64encode(
            hashlib.sha256(password.encode("utf-8")).digest())

        if not bcrypt.checkpw(password, user.password.encode("UTF-8")):
            return self.render_template(
                req,
                resp,
                "mfa/setup/step_one.html",
                message=Message("danger", "Incorrect Password",
                                "The password you entered was incorrect."))

        user.mfa_token = pyotp.random_base32()
        totp = pyotp.TOTP(user.mfa_token)
        uri = totp.provisioning_uri("{}@glowstone.net".format(user.username),
                                    issuer_name="Glowstone")

        image = qrcode.make(uri)
        buffer = BytesIO()

        image.save(buffer, format="PNG")
        qr_code = base64.b64encode(buffer.getvalue()).decode("UTF-8")

        return self.render_template(req,
                                    resp,
                                    "mfa/setup/step_two.html",
                                    qr_code=qr_code)
Пример #15
0
    def on_get(self, req, resp):
        resp.append_header("Refresh", "5;url=/")

        if not req.context["user"]:
            return self.render_template(req,
                                        resp,
                                        "message_gate.html",
                                        gate_message=Message(
                                            "danger", "Error",
                                            "You are not logged in"),
                                        redirect_uri="/")

        db_session = req.context["db_session"]
        token = req.cookies["token"]

        try:
            session = db_session.query(Session).filter_by(token=token).one()
        except NoResultFound:
            return self.render_template(req,
                                        resp,
                                        "message_gate.html",
                                        gate_message=Message(
                                            "danger", "Error",
                                            "You are not logged in"),
                                        redirect_uri="/")
        else:
            db_session.delete(session)
            resp.unset_cookie("token")
            req.context["user"] = None

            return self.render_template(req,
                                        resp,
                                        "message_gate.html",
                                        gate_message=Message(
                                            "info", "Logged out",
                                            "You have been logged out."),
                                        redirect_uri="/")
Пример #16
0
    def on_get(self, req, resp):
        if req.context["user"]:
            resp.append_header("Refresh", "5;url=/")
            return self.render_template(
                req, resp, "message_gate.html",
                gate_message=Message(
                    "danger", "Already logged in",
                    "You're already logged in!"
                ),
                redirect_uri="/"
            )

        self.render_template(
            req, resp,
            "register.html", error=None, csrf=resp.csrf
        )
Пример #17
0
    def on_get(self, req, resp):
        if not req.context["user"]:
            raise HTTPBadRequest()

        if not req.context["user"].mfa_enabled:
            resp.append_header("Refresh", "5;url=/settings")

            return self.render_template(req,
                                        resp,
                                        "message_gate.html",
                                        gate_message=Message(
                                            "warning", "No MFA",
                                            "You do not have MFA enabled."),
                                        redirect_uri="/settings")

        self.render_template(req, resp, "mfa/confirm_disable.html")
Пример #18
0
    def on_post(self, req, resp):
        params = {}
        db_session = req.context["db_session"]

        req.get_param("twitter_app_key", store=params)
        req.get_param("twitter_app_secret", store=params)
        req.get_param("discord_webhook_url", store=params)

        req.get_param("nodebb_api_key", store=params)
        req.get_param("nodebb_base_url", store=params)
        req.get_param("nodebb_category_id", store=params)
        req.get_param("nodebb_default_user_id", store=params)

        req.get_param("github_client_id", store=params)
        req.get_param("github_client_secret", store=params)

        if "nodebb_base_url" in params and params["nodebb_base_url"][-1] == "/":
            params["nodebb_base_url"] = params["nodebb_base_url"][:-1]

        for key, value in params.items():
            if not value:
                continue

            try:
                setting = db_session.query(Setting).filter_by(key=key).one()
            except NoResultFound:
                setting = Setting(key=key, value=value)
                db_session.add(setting)
            else:
                if not value:
                    db_session.delete(setting)
                else:
                    setting.value = value

        resp.append_header("Refresh", "5;url=/admin/settings")

        return self.render_template(
            req,
            resp,
            "admin/message_gate.html",
            gate_message=Message("info", "Settings updated",
                                 "Application settings have been updated."),
            redirect_uri="/admin/settings")
Пример #19
0
    def on_post(self, req, resp):
        user = req.context["user"]
        db_session = req.context["db_session"]

        db_session.query(BackupCode).filter_by(user=user).delete(
            synchronize_session="fetch")

        user.mfa_enabled = False
        user.mfa_token = None

        celery.send_task("send_email",
                         args=["mfa_disabled", user.email, "MFA disabled"],
                         kwargs={})

        resp.append_header("Refresh", "5;url=/settings")

        return self.render_template(req,
                                    resp,
                                    "message_gate.html",
                                    gate_message=Message(
                                        "success", "MFA disabled",
                                        "You have disabled MFA."),
                                    redirect_uri="/settings")
Пример #20
0
    def on_get(self, req, resp):
        db_session = req.context["db_session"]
        products_count = db_session.query(Product).count()

        if products_count == 0:
            resp.append_header("Refresh", "10;url=/")

            return self.render_template(
                req,
                resp,
                "message_gate.html",
                gate_message=Message(
                    "danger", "WIP",
                    "The downloads area is under construction. Come back later!"
                ),
                redirect_uri="/")
        else:
            products = db_session.query(Product).order_by(
                Product.order, Product.id).all()
            default_product = products[0]

            raise HTTPTemporaryRedirect("/downloads/{}".format(
                default_product.id))
Пример #21
0
    def on_post(self, req, resp):
        params = {}

        if not req.get_param("username", store=params) or not req.get_param("password", store=params):
            return self.render_template(
                req, resp, "login.html",
                message=Message("danger", "Login failed", "Please enter both a username and password."),
                csrf=resp.csrf
            )

        params["password"] = base64.b64encode(hashlib.sha256(params["password"].encode("utf-8")).digest())

        db_session = req.context["db_session"]

        try:
            user = db_session.query(User).filter_by(username=params["username"]).one()
        except NoResultFound:
            return self.render_template(
                req, resp, "login.html",
                message=Message("danger", "Login failed", "Incorrect username or password - please try again."),
                csrf=resp.csrf
            )
        else:
            if not bcrypt.checkpw(params["password"], user.password.encode("UTF-8")):
                return self.render_template(
                    req, resp, "login.html",
                    message=Message("danger", "Login failed", "Incorrect username or password - please try again."),
                    csrf=resp.csrf
                )
            if not user.email_verified:
                return self.render_template(
                    req, resp, "login.html",
                    message=Message(
                        "danger",
                        "Login failed",
                        "This user account has not been verified - please check your email for more information, or "
                        "contact one of the developers for help."
                    ),
                    csrf=resp.csrf
                )
            # Login is OK!
            token = secrets.token_urlsafe(24)
            expires = datetime.datetime.now() + datetime.timedelta(days=30)
            age = (expires - datetime.datetime.now()).seconds

            session = Session(user=user, token=token, expires=expires, awaiting_mfa=user.mfa_enabled)
            db_session.add(session)

            resp.set_cookie("token", token, max_age=age, secure=False)
            req.context["user"] = user

            if not user.mfa_enabled:
                resp.append_header("Refresh", "5;url=/")

                return self.render_template(
                    req, resp, "message_gate.html",
                    gate_message=Message("info", "Logged in", "You have been logged in successfully."),
                    redirect_uri="/"
                )
            else:
                return self.render_template(req, resp, "mfa/challenge.html")
Пример #22
0
    def on_post(self, req, resp):
        params = {}

        if not req.get_param("title", store=params) \
                or not req.get_param("content", store=params):
            resp.append_header("Refresh", "5;url=/admin/news/create")

            return self.render_template(
                req,
                resp,
                "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Missing parameters",
                    "Please input both the post title and content."),
                redirect_uri="/admin/news/create")

        req.get_param("action", store=params)

        markdown = Markdown(params["content"])
        db_session = req.context["db_session"]

        resp.append_header("Refresh", "5;url=/admin/news")

        if not req.get_param("post_id", store=params):
            post = NewsPost(user=req.context["user"],
                            posted=datetime.datetime.now(),
                            title=params["title"],
                            markdown=markdown.markdown,
                            html=markdown.html,
                            summary=markdown.summary,
                            published=(params["action"] == "publish"))

            db_session.add(post)
            db_session.commit()

            if post.published:
                notify_post(post)

            if post.published:
                message = "News post created: {}".format(params["title"])
            else:
                message = "Draft created: {}".format(params["title"])

            return self.render_template(req,
                                        resp,
                                        "admin/message_gate.html",
                                        gate_message=Message(
                                            "info", "Post created", message),
                                        redirect_uri="/admin/news")
        else:
            try:
                post = db_session.query(NewsPost).filter_by(
                    id=int(params["post_id"])).one()
            except NoResultFound:
                return self.render_template(req,
                                            resp,
                                            "admin/message_gate.html",
                                            gate_message=Message(
                                                "danger", "Error",
                                                "No such post: {}".format(
                                                    params["post_id"])),
                                            redirect_uri="/admin/news")
            else:
                was_published = bool(post.published)

                post.title = params["title"]
                post.markdown = markdown.markdown
                post.html = markdown.html
                post.summary = markdown.summary
                post.published = params["action"] == "publish"

                if was_published == post.published:
                    if post.published:
                        message = "News post edited: {}".format(
                            params["title"])
                    else:
                        message = "Draft edited: {}".format(params["title"])
                else:
                    if was_published:
                        message = "News post unpublished: {}".format(
                            params["title"])
                    else:
                        message = "Draft published: {}".format(params["title"])

                return self.render_template(req,
                                            resp,
                                            "admin/message_gate.html",
                                            gate_message=Message(
                                                "info", "Post edited",
                                                message),
                                            redirect_uri="/admin/news")
Пример #23
0
    def on_post(self, req, resp):
        if req.context["user"]:
            resp.append_header("Refresh", "5;url=/")
            return self.render_template(
                req, resp, "message_gate.html",
                gate_message=Message(
                    "danger", "Already logged in",
                    "You're already logged in!"
                ),
                redirect_uri="/"
            )

        params = {}

        if not req.get_param("g-recaptcha-response", store=params):
            return self.render_template(
                req, resp, "register.html",
                message=Message(
                    "danger", "Failed CAPTCHA",
                    "Unfortunately, we were not able to verify you by CAPTCHA. Please try again."
                ),
                csrf=resp.csrf
            )

        http = Session()
        captcha_response = http.post(
            RECAPTCHA_URL, data={
                "secret": self.manager.database.config.recaptcha_secret,
                "response": params["g-recaptcha-response"]
            }
        ).json()

        if not captcha_response["success"]:
            return self.render_template(
                req, resp, "register.html",
                message=Message(
                    "danger", "Failed CAPTCHA",
                    "Unfortunately, we were not able to verify you by CAPTCHA. Please try again."
                ),
                csrf=resp.csrf
            )

        if not req.get_param("username", store=params) \
                or not req.get_param("email", store=params) \
                or not req.get_param("password", store=params) \
                or not req.get_param("confirm_password", store=params):

            return self.render_template(
                req, resp, "register.html",
                message=Message("danger", "Missing input", "Please fill out the entire form"),
                csrf=resp.csrf
            )

        if not params["password"] == params["confirm_password"]:
            return self.render_template(
                req, resp, "register.html",
                message=Message("danger", "Passwords do not match", "Please ensure that your passwords match"),
                csrf=resp.csrf
            )

        db_session = req.context["db_session"]

        try:
            db_session.query(User).filter_by(username=params["username"]).one()
        except NoResultFound:
            pass
        else:
            return self.render_template(
                req, resp, "register.html",
                message=Message("danger", "User already exists", "That username is already taken - please try another"),
                csrf=resp.csrf
            )

        try:
            db_session.query(User).filter_by(email=params["email"]).one()
        except NoResultFound:
            pass
        else:
            return self.render_template(
                req, resp, "register.html",
                message=Message("danger", "Email already used", "An account already exists for that email address"),
                csrf=resp.csrf
            )

        password = base64.b64encode(hashlib.sha256(params["password"].encode("utf-8")).digest())
        hashed_password = bcrypt.hashpw(password, bcrypt.gensalt()).decode("utf-8")

        user = User(
            username=params["username"], password=hashed_password, created=datetime.datetime.now(),
            email=params["email"], email_verified=not self.db.config.email["use"],
            admin=(params["username"] == self.manager.database.config.admin_username)
        )

        db_session.add(user)

        resp.append_header("Refresh", "10;url=/")

        if self.db.config.email["use"]:
            key = secrets.token_urlsafe(32)
            email_code = EmailCode(
                user=user, code=key
            )

            db_session.add(email_code)

            celery.send_task(
                "send_email",
                args=["email_verification", user.email, "Email verification"],
                kwargs={"verify_url": "/login/verify/{}".format(key)}
            )

            return self.render_template(
                req, resp, "message_gate.html",
                gate_message=Message(
                    "info", "Registered", "Your account has been registered - please check your email to verify it!"
                ),
                redirect_uri="/"
            )

        return self.render_template(
            req, resp, "message_gate.html",
            gate_message=Message(
                "info", "Registered", "Your account has been registered successfully."
            ),
            redirect_uri="/"
        )
Пример #24
0
    def on_post(self, req, resp):
        params = {}

        user = req.context["user"]
        db_session = req.context["db_session"]

        keys = {}

        if not user:
            raise HTTPBadRequest()

        if not user.api_enabled:
            resp.append_header("Refresh", "5;url=/profile")

            return self.render_template(
                req,
                resp,
                "message_gate.html",
                gate_message=Message(
                    "danger", "No access",
                    "You don't have API access - please contact a member of staff if you need it."
                ),
                redirect_uri="/")

        for key in db_session.query(APIKey).filter_by(user_id=user.id).all():
            keys[key.key] = key.name

        if not req.get_param("action", store=params):
            raise HTTPBadRequest()

        if params["action"] == "create":
            if len(keys) >= 10:
                return self.render_template(
                    req,
                    resp,
                    "users/api_keys.html",
                    user=user,
                    keys=keys,
                    message=Message(
                        "danger", "Too many keys",
                        "You already have 10 api keys! If you need more, contact staff directly."
                    ))

            if not req.get_param("name", store=params) or not params["name"]:
                return self.render_template(
                    req,
                    resp,
                    "users/api_keys.html",
                    user=user,
                    keys=keys,
                    message=Message(
                        "danger", "Missing name",
                        "Please supply a name for your new API key"))

            new_key = APIKey(user=user,
                             name=params["name"],
                             key=secrets.token_urlsafe(32))
            db_session.add(new_key)

            keys[new_key.key] = new_key.name

            return self.render_template(
                req,
                resp,
                "users/api_keys.html",
                user=user,
                keys=keys,
                message=Message(
                    "success", "Key created",
                    "New API key \"{}\" created successfully.".format(
                        new_key.name)))
        elif params["action"] == "delete":
            if not req.get_param("key", store=params):
                raise HTTPBadRequest()

            if params["key"] not in keys:
                return self.render_template(
                    req,
                    resp,
                    "users/api_keys.html",
                    user=user,
                    keys=keys,
                    message=Message("danger", "No such key",
                                    "Unknown key: {}.".format(params["key"])))

            old_key = db_session.query(APIKey).filter_by(
                key=params["key"]).one()
            db_session.delete(old_key)
            del keys[params["key"]]

            return self.render_template(
                req,
                resp,
                "users/api_keys.html",
                user=user,
                keys=keys,
                message=Message(
                    "success", "Key deleted",
                    "API key \"{}\" deleted successfully.".format(
                        old_key.name)))
        else:
            raise HTTPBadRequest()
Пример #25
0
    def step_two(self, req, resp):
        user = req.context["user"]
        totp = pyotp.TOTP(user.mfa_token)
        code = req.get_param("code")
        db_session = req.context["db_session"]

        if not code:
            uri = totp.provisioning_uri("{}@glowstone.net".format(
                user.username),
                                        issuer_name="Glowstone")

            image = qrcode.make(uri)
            buffer = BytesIO()

            image.save(buffer, format="PNG")
            qr_code = base64.b64encode(buffer.getvalue()).decode("UTF-8")

            return self.render_template(
                req,
                resp,
                "mfa/setup/step_two.html",
                message=Message(
                    "danger", "Missing code",
                    "Please enter a code from your authenticator application to continue."
                ),
                qr_code=qr_code)

        if totp.verify(code):
            backup_codes = []

            for i in range(10):
                token = secrets.token_urlsafe(24)
                db_session.add(BackupCode(user=user, code=token))
                backup_codes.append(token)

            celery.send_task(
                "send_email",
                args=["backup_codes", user.email, "MFA backup codes"],
                kwargs={"codes": backup_codes})

            user.mfa_enabled = True

            return self.render_template(req, resp, "mfa/setup/complete.html")
        else:
            uri = totp.provisioning_uri("{}@glowstone.net".format(
                user.username),
                                        issuer_name="Glowstone")

            image = qrcode.make(uri)
            buffer = BytesIO()

            image.save(buffer, format="PNG")
            qr_code = base64.b64encode(buffer.getvalue()).decode("UTF-8")

            return self.render_template(
                req,
                resp,
                "mfa/setup/step_two.html",
                message=Message(
                    "danger", "Invalid code",
                    "The auth code you provided was invalid - please try again."
                ),
                qr_code=qr_code)
Пример #26
0
    def on_post(self, req, resp):
        params = {}
        db_session = req.context["db_session"]

        if not req.get_param("product_name", store=params) \
                or not req.get_param("product_order", store=params) \
                or not req.get_param("github_url", store=params) \
                or not req.get_param("circleci_url", store=params) \
                or not req.get_param("visibility", store=params):

            if req.get_param("product_id", store=params):
                resp.append_header("Refresh", "/admin/products/edit?product={}".format(params["product_id"]))

                return self.render_template(
                    req, resp, "admin/message_gate.html",
                    gate_message=Message("danger", "Missing input", "Please fill out the entire form"),
                    redirect_uri="/admin/products/edit?product={}".format(params["product_id"])
                )

            resp.append_header("Refresh", "/admin/products/create")

            return self.render_template(
                req, resp, "admin/message_gate.html",
                gate_message=Message("danger", "Missing input", "Please fill out the entire form"),
                redirect_uri="/admin/products/create"
            )

        resp.append_header("Refresh", "5;url=/admin/products")

        if not req.get_param("product_id", store=params):
            product = Product(
                name=params["product_name"], order=params["product_order"], hidden=params["visibility"] == "Hidden",
                url_github=params["github_url"], url_circleci=params["circleci_url"], branches=[]
            )
            db_session.add(product)

            return self.render_template(
                req, resp, "admin/message_gate.html",
                gate_message=Message(
                    "info", "Product created", "Your product has been created."
                ),
                redirect_uri="/admin/products"
            )

        try:
            product = db_session.query(Product).filter_by(id=int(params["product_id"])).one()
        except NoResultFound:
            return self.render_template(
                req, resp, "admin/message_gate.html",
                gate_message=Message(
                    "danger", "Error", "No such product: {}".format(params["post_id"])
                ),
                redirect_uri="/admin/products"
            )
        else:
            product.name = params["product_name"]
            product.order = int(params["product_order"])
            product.hidden = params["visibility"] == "Hidden"
            product.url_github = params["github_url"]
            product.url_circleci = params["circleci_url"]

            return self.render_template(
                req, resp, "admin/message_gate.html",
                gate_message=Message(
                    "info", "Product edited", "Your product has been edited."
                ),
                redirect_uri="/admin/products"
            )
Пример #27
0
    def on_post(self, req, resp):
        params = {}
        errors = []
        updated = []

        user = req.context["user"]
        user_email = user.email

        if not req.get_param("password", store=params):
            return self.render_template(
                req,
                resp,
                "users/settings.html",
                message=Message(
                    "danger", "Missing password",
                    "Please enter your current password to make changes."),
                user=user)

        params["password"] = base64.b64encode(
            hashlib.sha256(params["password"].encode("utf-8")).digest())

        db_session = req.context["db_session"]

        if not bcrypt.checkpw(params["password"],
                              user.password.encode("UTF-8")):
            return self.render_template(
                req,
                resp,
                "users/settings.html",
                message=Message("danger", "Incorrect password",
                                "The password you entered was incorrect."),
                user=user)

        if not errors:
            if req.get_param("new_password", store=params):
                if not req.get_param("new_password_again", store=params):
                    errors.append("Please confirm your new password.")
                elif not params["new_password"] == params["new_password_again"]:
                    errors.append("Your new passwords do not match.")
                else:
                    password = base64.b64encode(
                        hashlib.sha256(
                            params["new_password"].encode("utf-8")).digest())
                    hashed_password = bcrypt.hashpw(
                        password, bcrypt.gensalt()).decode("utf-8")

                    user.password = hashed_password
                    updated.append("Password")

        if not errors:
            if req.get_param("email", store=params) and params["email"]:
                key = secrets.token_urlsafe(32)
                email_code = EmailCode(user=user, code=key)

                db_session.add(email_code)

                celery.send_task(
                    "send_email",
                    args=[
                        "email_verification", user.email, "Email verification"
                    ],
                    kwargs={"verify_url": "/login/verify/{}".format(key)})

                user.email = params["email"]
                user.email_verified = False

                updated.append("Email")

        if errors:
            return self.render_template(
                req,
                resp,
                "users/settings.html",
                message=Message(
                    "danger", "Error",
                    "The following problems were found - nothing has been changed. <br /><ul>{}</ul>"
                    .format("".join("<li>{}</li>".format(error)
                                    for error in errors))),
                user=user)

        if updated:
            updated = ", ".join(updated)

            celery.send_task(
                "send_email",
                args=["settings_changed", user_email, "Settings Changed"],
                kwargs={"settings": updated})

            resp.append_header("Refresh", "10;url=/profile")

            return self.render_template(
                req,
                resp,
                "message_gate.html",
                gate_message=Message(
                    "info", "Updated",
                    "You have updated the following settings: {}<br />If you updated your email, "
                    "remember to verify it - or you won't be able to log in!".
                    format(updated)),
                redirect_uri="/profile")

        return self.render_template(req,
                                    resp,
                                    "users/settings.html",
                                    message=Message(
                                        "warning", "No changes",
                                        "You didn't change any settings."),
                                    user=user)