예제 #1
0
def settings_view():
    settings = AccountService.get_settings(current_user.get_id())
    form = make_settings_form(settings)

    def render_form():
        return render_template("settings.tpl", settings=settings, form=form)

    if form.is_submitted():
        if not form.validate():
            flash_update_error()
            return render_form()

        new_password = form.new_password.data
        if new_password:
            if current_user["password"] == new_password:
                flash_update_error(form.new_password,
                                   "Same as current password")
                return render_form()
            AccountService.update(current_user.get_id(),
                                  AccountInterface(password=new_password))

        # Use the UserSettings class in order to update/set settings
        user_settings.set(current_user.get_id(), form.data)
        flash("Success! Your settings have been saved.")
    return render_form()
예제 #2
0
    def link(user_id: int, subject: Optional[str]):
        """
        Link the given account to the given openid subject

        :param user_id: user ID to link
        :param subject: openid subject to link to the account
        :return:
        """
        AccountService.update(user_id, AccountInterface(hash=subject))
예제 #3
0
def delete_hits():
    form = AdminDeleteForm()
    if form.validate():
        hit_threshold = form.hit_threshold.data
        delete_queue = ()

        # If admin has selected to delete from all keys
        if form.all_keys.data:
            # Select all files, where hits <= threshold.
            delete_queue = db.fetchall(
                "SELECT * FROM `files` WHERE `hits` <= %s", [hit_threshold]
            )
        else:
            # Select files from a user, where hits <= threshold
            user = AccountService.get_by_key(form.key.data)
            if user:
                delete_queue = db.fetchall(
                    "SELECT * FROM `files` WHERE `userid` = %s AND `hits` <= %s",
                    [user.get_id(), hit_threshold],
                )

        size, count, _ = FileService.delete_batch(delete_queue)
        return render_template(
            "delete.tpl",
            messages=[
                f"{count} items deleted. {functions.sizeof_fmt(size)} of disk space saved."
            ],
        )
    flash("There was an error processing your input.", "error")
    return redirect("/admin")
예제 #4
0
def gallery_auth(user_key):
    # Set a long cookie to grant a user access to a gallery
    form = GalleryAuthForm()
    if form.validate_on_submit():
        user = AccountService.get_by_key(user_key)
        resp = redirect(f"/gallery/{user_key}")
        GalleryService.set_auth_cookie(resp, user.get_id(), form.authcode.data,
                                       form.remember.data)
        return resp
    form.flash_errors()
    return render_template("gallery_auth.tpl", form=form)
예제 #5
0
 def get_or_create_account(self):
     try:
         user, is_authed = AccountService.get_or_create_account(
             self.key.data, self.password.data
         )
         if not user or not is_authed:
             self.key.errors.append("Key or password is incorrect")
     except Error as e:
         self.key.errors.append(e.error)
         return None, False
     return user, is_authed
예제 #6
0
def callback():
    if "error" in request.args:
        flash("There was a problem logging you in.", "error")
        logout_user()
    else:
        token = oauth.auth.authorize_access_token()
        id_token = oauth.auth.parse_id_token(token)
        pprint(dict(token=token, user=id_token))
        subject = id_token.get("sub")
        if subject:
            user = AccountService.get_by_subject(subject)
            if user:
                LoginForm.login(user)
            else:
                # subject is not assigned to an account already
                # go through the account linking flow
                session["oauth"] = id_token
                return redirect(url_for("oauth.link"))
    return redirect(url_for("static.login"))
예제 #7
0
    def validate_auth_cookie(user_id: int, settings: Optional[dict] = None) -> bool:
        """
        Validate a gallery auth cookie for the given user.

        :param user_id: ID of the user
        :param settings: user settings dict (pass in if already grabbed)
        :return: True if the auth cookie is valid or not needed, else False
        """
        if not settings:
            settings = AccountService.get_settings(user_id)
        get_user_setting = partial(get_dict, settings)
        if get_user_setting("block.value") and get_user_setting(
            "gallery_password.value"
        ):
            auth_cookie = GalleryService.get_auth_cookie(user_id)
            hex_pass = hashlib.sha1(
                get_user_setting("gallery_password.value").encode("utf-8")
            ).hexdigest()
            if not auth_cookie or not hex_pass == auth_cookie:
                return False
        return True
예제 #8
0
def api_upload_file(upload_type="file"):
    if upload_type not in ["file", "paste"]:
        # The type the user provided doesn't exist.
        raise json_error("This upload type does not exist")

    # support login thru the API
    key = request.form.get("key")
    password = request.form.get("password")
    if key and password and not current_user.is_authenticated:
        user, is_authed = AccountService.get_or_create_account(key, password)
        if user and is_authed:
            login_user(user)
        else:
            raise json_error("Incorrect key or password")

    user_id = current_user.get_id()

    is_file = upload_type == "file"
    file: Optional[Union[FileInterface, PasteInterface]] = None
    if is_file:
        file = submit_file(user_id)
    elif upload_type == "paste":
        file = submit_paste(user_id)

    if not file:
        raise json_error("Failed to upload file")

    shorturl = file["shorturl"]
    ext = file["ext"] if is_file else "paste"

    host = get_host()
    path = "/" + ("" if is_file else upload_type + "/")
    return json_response(
        type=ext,
        key="anon" if not user_id else current_user["key"],
        base=host,
        url=path + shorturl,
        full_url=host + path + shorturl,
    )
예제 #9
0
    def get_potential_name(userinfo, errors=None):
        """
        Get the potential account name for the given openid userinfo.

        :param userinfo: openid userinfo
        :param errors: list of errors to append to
        :return: tuple of (name, errors)
        """
        if not errors:
            errors = []
        subject = userinfo["sub"]
        potential_name = userinfo.get("preferred_username", subject)
        existing_user = AccountService.get_by_key(potential_name)
        if existing_user:
            # user with potential name exists already, use subject instead
            errors.append(
                f'User "{potential_name}" already exists, please authenticate as them or choose another username'
            )
            potential_name = subject

        # trim to 30 chars to fit in db
        # TODO: update key/password db length?
        potential_name = potential_name[:30]
        return potential_name, errors
예제 #10
0
def gallery_view(user_key=None):
    form_filter = GallerySortForm(request.args)
    case = form_filter.case.data
    query = form_filter.query.data

    if form_filter.validate():
        page = form_filter.page.data
        query_in = form_filter.in_.data
        active_sort = form_filter.sort.data
        entry_filter = FileType(form_filter.filter.data)
    else:
        # return a generic error if validation failed
        return render_template("error.tpl",
                               error="There were no results for this search.")

    user = AccountService.get_by_key(user_key)
    # anonymous account, hide gallery
    if not user or user.get_id() == 0:
        return render_template("error.tpl",
                               error="Specified key does not exist.")

    # Check the users settings to see if they have specified
    # gallery access restrictions
    settings = AccountService.get_settings(user.get_id())
    if not GalleryService.validate_auth_cookie(user.get_id(),
                                               settings=settings):
        # if cookie , show password incorrect message
        if GalleryService.get_auth_cookie(user.get_id()):
            flash("Incorrect gallery password", "error")
        return redirect(f"/gallery/auth/{user_key}")

    search_in = search_modes[query_in][1]
    sort_by = sort_modes[active_sort]

    # where clauses
    sql_search = []
    # parameters for the where clauses
    params = []

    if query:
        # Ensure case-sensitive searching with a binary conversion
        collate = " COLLATE utf8_bin" if case else ""
        sql_search.append(f"`{search_in}`{collate} LIKE %s")
        params.append("%" + query + "%")

    # filter results by file type
    if entry_filter != FileType.ALL:
        sql_search.append(f"`type` = %s")
        params.append(entry_filter.value)

    # function that creates a search query given a "what" clause.
    # used to get the total file count, then later
    # use the same query to get the files themselves
    def get_search_query(sub):
        return f"SELECT {sub} FROM `files` WHERE {' AND '.join(sql_search + [''])} `userid` = %s ORDER BY `{sort_by[1]}` {sort_by[2]}"

    params.append(user.get_id())

    total_entries = db.fetchone(get_search_query("COUNT(`id`) AS `total`"),
                                params)["total"]

    # generate pages with a useful pagination class
    pagination = functions.Pagination(page, 30, total_entries)

    if page > pagination.pages:
        if pagination.pages == 0:
            return render_template(
                "error.tpl", error="There were no results for this search.")
        else:
            return render_template("error.tpl",
                                   error="This page does not exist.")

    # fetch the files given a pagination limit (only fetch files for given page)
    results: Tuple[FileInterface, ...] = db.fetchall(
        f"{get_search_query('*')} LIMIT {pagination.limit}", params)

    files = []
    for row in results:
        file = {
            "url": row["shorturl"],
            "hits": row["hits"],
            "time": {
                "epoch": row["date"].timestamp(),
                "timestamp": row["date"].strftime("%d/%m/%Y @ %H:%M:%S"),
            },
            "ext": row["ext"],
            "original": row["original"],
            "type": FileType(row["type"]),
        }
        if file["type"] == FileType.PASTE:
            paste: PasteInterface = PasteService.get_by_id(row["original"])
            file["content"] = paste["content"]
            file["name"] = paste["name"] or row["shorturl"]
            file["size"] = len(file["content"].split("\n"))

            # get latest revision for paste
            latest_rev = PasteService.get_latest_revision(paste)
            if latest_rev:
                file["content"] = latest_rev["paste"]
                # add latest commit hash to url
                file["url"] = row["shorturl"] + ":" + latest_rev["commit"]
        else:
            file["size"] = functions.sizeof_fmt(row["size"])
            if file["type"] == FileType.IMAGE:
                file["resolution"] = (row["width"], row["height"])
        files.append(file)

    usage = None
    tally = db.fetchone(get_search_query("SUM(`size`) AS `total`"), params)
    if tally and tally.get("total"):
        usage = functions.sizeof_fmt(float(tally["total"]))

    form_delete = GalleryDeleteForm()

    return render_template(
        "gallery.tpl",
        key=user_key,
        pages=pagination,
        usage=usage,
        entries=total_entries,
        active_sort=active_sort,
        search={
            "query": query,
            "in": query_in,
            "case": case
        },
        files=files,
        xhr=request.headers.get("X-AJAX", "false") == "true",
        show_ext=get_dict(settings, "ext.value"),
        hl=functools.partial(functions.highlight_text,
                             search=query,
                             case_sensitive=case),
        form_delete=form_delete,
        form_filter=form_filter,
        url_for_page=url_for_page,
    )