コード例 #1
0
def validate(json, args):
    """
    Ensure the json object contains all the keys needed to satisfy
    its endpoint (and isnt empty)
    """
    if not json:
        raise BBJParameterError(
            "JSON input is empty. This method requires the following "
            "arguments: {}".format(", ".join(args)))

    for arg in args:
        if arg not in json.keys():
            raise BBJParameterError(
                "Required parameter {} is absent from the request. "
                "This method requires the following arguments: {}".format(
                    arg, ", ".join(args)))
コード例 #2
0
def thread_get(connection, thread_id, messages=True, op_only=False):
    """
    Fetch the thread_id from the database. Formatting is be handled
    elsewhere.

    MESSAGES, if False, will omit the inclusion of a thread's messages
    and only get its metadata, such as title, author, etc.
    """
    c = connection.cursor()
    thread = c.execute("SELECT * FROM threads WHERE thread_id = ?",
                       (thread_id, )).fetchone()

    if not thread:
        raise BBJParameterError("Thread does not exist.")
    thread = schema.thread(*thread)

    if messages or op_only:
        query = "SELECT * FROM messages WHERE thread_id = ? %s"
        c.execute(
            query % ("AND post_id = 0" if op_only else "ORDER BY post_id"),
            (thread_id, ))
        # create a list where each post_id matches its list[index]
        thread["messages"] = [
            schema.message(*values) for values in c.fetchall()
        ]

    return thread
コード例 #3
0
def user_resolve(connection, name_or_id, externalize=False, return_false=True):
    """
    Accepts a name or id and returns the full user object for it.

    EXTERNALIZE determines whether to strip the object of private data.

    RETURN_FALSE determines whether to raise an exception or just
    return bool False if the user doesn't exist
    """
    user = connection.execute(
        """
         SELECT * FROM users
         WHERE user_name = ?
            OR user_id = ? """, (name_or_id, name_or_id)).fetchone()

    if user:
        user = schema.user_internal(*user)
        if externalize:
            return user_externalize(user)
        return user

    if return_false:
        return False
    raise BBJParameterError("Requested user element ({})"
                            " is not registered".format(name_or_id))
コード例 #4
0
def do_formatting(format_spec, messages):
    if not format_spec:
        return None

    elif format_spec == "sequential":
        method = formatting.sequential_expressions

    else:
        raise BBJParameterError("invalid formatter specification")

    formatting.apply_formatting(messages, method)
    return True
コード例 #5
0
def message_edit_query(connection, author, thread_id, post_id):
    """
    Perform all the neccesary sanity checks required to edit a post
    and then return the requested message object without any changes.
    """
    user = user_resolve(connection, author)
    thread = thread_get(connection, thread_id)

    try:
        message = thread["messages"][post_id]
    except IndexError:
        raise BBJParameterError("post_id out of bounds for requested thread")

    if not user["is_admin"]:
        if not user["user_id"] == message["author"]:
            raise BBJUserError(
                "non-admin attempt to edit another user's message")

        elif (time() - message["created"]) > 86400:
            raise BBJUserError("message is too old to edit (24hr limit)")

    return message
コード例 #6
0
    def wrapper(self, *args, **kwargs):
        response = None
        debug = app_config["debug"]
        try:
            connection = sqlite3.connect(dbname)
            # read in the body from the request to a string...
            if cherrypy.request.method == "POST":
                read_in = str(cherrypy.request.body.read(), "utf8")
                if not read_in:
                    # the body may be empty, not all methods require input
                    body = {}
                else:
                    body = json.loads(read_in)
                    if not isinstance(body, dict):
                        raise BBJParameterError("Non-JSONObject input")
                    # lowercase all of its top-level keys
                    body = {key.lower(): value for key, value in body.items()}
            else:
                body = {}

            username = cherrypy.request.headers.get("User")
            auth = cherrypy.request.headers.get("Auth")

            if (username and not auth) or (auth and not username):
                raise BBJParameterError(
                    "User or Auth was given without the other.")

            elif not username and not auth:
                user = db.anon

            else:
                user = db.user_resolve(connection, username)
                if not user:
                    raise BBJUserError("User %s is not registered" % username)

                elif auth.lower() != user["auth_hash"].lower():
                    raise BBJException(5,
                                       "Invalid authorization key for user.")

            # api_methods may choose to bind a usermap into the thread_data
            # which will send it off with the response
            cherrypy.thread_data.usermap = {}
            value = function(self, body, connection, user)
            response = schema.response(value, cherrypy.thread_data.usermap)

        except BBJException as e:
            response = e.schema

        except json.JSONDecodeError as e:
            response = schema.error(0, str(e))

        except Exception as e:
            error_id = uuid1().hex
            response = schema.error(
                1,
                "Internal server error: code {} {}".format(error_id, repr(e)))
            with open("logs/exceptions/" + error_id, "a") as log:
                traceback.print_tb(e.__traceback__, file=log)
                log.write(repr(e))
            print("logged code 1 exception " + error_id)

        finally:
            connection.close()
            return json.dumps(response)
コード例 #7
0
def validate(keys_and_values):
    """
    The line of defense against garbage user input.

    Recieves an iterable containing iterables, where [0]
    is a string representing the value type, and [1]
    is the value to compare against a set of rules for
    it's type. The function returns the boolean value
    True when everything is okay, or raises a BBJException
    to be handled by higher levels of the program if something
    is wrong (immediately stopping execution at the db level)
    """
    for key, value in keys_and_values:

        if key == "user_name":
            if not value:
                raise BBJUserError("Username may not be empty.")

            elif contains_nonspaces(value):
                raise BBJUserError(
                    "Username cannot contain whitespace characters besides spaces."
                )

            elif not value.strip():
                raise BBJUserError(
                    "Username must contain at least one non-space character")

            elif len(value) > 24:
                raise BBJUserError("Username is too long (max 24 chars)")

        elif key == "auth_hash":
            if not value:
                raise BBJParameterError("auth_hash may not be empty")

            elif len(value) != 64:
                raise BBJParameterError("Client error: invalid SHA-256 hash.")

        elif key == "quip":
            if contains_nonspaces(value):
                raise BBJUserError(
                    "Quip cannot contain whitespace characters besides spaces."
                )

            elif len(value) > 120:
                raise BBJUserError("Quip is too long (max 120 chars)")

        elif key == "bio":
            if len(value) > 4096:
                raise BBJUserError("Bio is too long (max 4096 chars)")

        elif key == "title":
            if not value:
                raise BBJUserError("Title cannot be empty")

            elif contains_nonspaces(value):
                raise BBJUserError(
                    "Titles cannot contain whitespace characters besides spaces."
                )

            elif not value.strip():
                raise BBJUserError(
                    "Title must contain at least one non-space character")

            elif len(value) > 120:
                raise BBJUserError("Title is too long (max 120 chars)")

        elif key == "body":
            if not value:
                raise BBJUserError("Post body cannot be empty")

        elif key == "color":
            if value in range(0, 7):
                continue
            raise BBJParameterError(
                "Color specification out of range (int 0-6)")

    return True