Пример #1
0
def get_comments(sql_cursor, thread_id, since_comment_id):

    if not db.thread_exists(sql_cursor, thread_id):
        raise NonExistentThreadError(thread_id)

    # XXX: do we need to check if since_comment_id is valid..?
    return 200, {"comments": db.comments_since(sql_cursor, thread_id, since_comment_id)}
Пример #2
0
def post_comment(sql_cursor, thread_id, request_json, captcha_token):

    captcha_id = request_json["captcha_id"] if "captcha_id" in request_json else None
    post_json = request_json["post"] if "post" in request_json else None

    if captcha_token is None:
        raise MissingTokenError()

    # exists and not stale
    if not db.is_valid_captcha(sql_cursor, captcha_id):
        raise NonExistentCaptchaError(captcha_id)

    if not db.thread_exists(sql_cursor, thread_id):
        raise NonExistentThreadError(thread_id)

    if not is_token_valid(sql_cursor, captcha_id, captcha_token):
        raise InvalidTokenError()

    if not is_post_valid(post_json):
        raise InvalidPostError(post_json)

    title, comment_body, author_name = post_json["title"], post_json["body"], post_json["name"]
    # optional email field, argon2 hash it
    # TODO: check if valid! (potentially this https://stackoverflow.com/a/28982264 or https://stackoverflow.com/a/14485817)
    email = post_json["email"] if "email" in post_json else None
    email_hash = hash_email(email) if email is not None else None

    # TODO: get ip address to store

    # consume captcha token, plus post the comment to the database
    comment_id = db.submit_post(sql_cursor, thread_id, captcha_id, title,
                                author_name, comment_body, email_hash)

    return 200, {"captcha_id": captcha_id, "comment_id": comment_id}
Пример #3
0
def make_captcha(sql_cursor, thread_id, challenge_type):
    """
    @param thread_id: threads.id that the captcha is associated with
    @param challenge_type: either text/....
        determines what kind of challenge will be returned

    @return status code, json output tuple

    This function generates a captcha, and returns the json
        to send back to the requesting user.
    This captcha challenge is stored in the db for later comparison.
    """

    if not db.thread_exists(sql_cursor, thread_id):
        raise NonExistentThreadError(thread_id)

    # generate unique ID for each captcha
    captcha_id = secrets.token_urlsafe(settings.ID_BYTES)

    hint, answers = get_challenge(challenge_type)
    db.store_challenge(sql_cursor, captcha_id, thread_id, hint, answers)

    ret_json = {"id": captcha_id, "captcha": hint}

    return 200, ret_json
Пример #4
0
def validate_captcha(sql_cursor, thread_id, request_json):
    """
    Given a user provided attempt, check whether we grant them a token or not
    """

    provided_attempt = request_json["answer"] if "answer" in request_json else None
    captcha_id = request_json["id"] if "id" in request_json else None

    if provided_attempt is None:
        raise NonExistentAnswerError()

    # exists and not stale
    if not db.is_valid_captcha(sql_cursor, captcha_id) or\
       not db.is_challenge_available(sql_cursor, captcha_id):
        raise NonExistentCaptchaError(captcha_id)

    if not db.thread_exists(sql_cursor, thread_id):
        raise NonExistentThreadError(thread_id)

    attempt_number = db.get_attempt_count(sql_cursor, captcha_id) + 1

    # sanity check that we're not in a state where we didn't clean up captcha_id
    #   after too many attempts
    if attempt_number > settings.MAX_ATTEMPTS:
        raise RuntimeError("captcha_id ({}) not removed after too many attempts".format(captcha_id))

    # check if valid answer and increment number of attempts
    is_valid = db.crossvalidate_answer(sql_cursor, captcha_id, provided_attempt)
    if is_valid:
        expiry, captcha_token = generate_captcha_token(sql_cursor, captcha_id)
        ret_json = {"id": captcha_id, "status": "ok",
                    "key": {"token": captcha_token, "expiry": expiry}}
        return 200, ret_json

    # failed on the last try?
    if attempt_number == settings.MAX_ATTEMPTS:
        # delete all data relating to this captcha_id
        db.remove_captcha(sql_cursor, captcha_id)
        # tell them they need to start from another captcha
        return 200, {"id": captcha_id, "status": "restart"}

    return 200, {"id": captcha_id, "status": "try again"}
Пример #5
0
def make_del_token(sql_cursor, thread_id, comment_id, request_json):
    # we check the email was set - we don't care if the email isn't valid, because it *shouldn't* exist in the db anyway
    # and will fail at the step of sending an email even if it somehow exists in the db
    email = request_json["email"] if "email" in request_json else None
    if email is None:
        raise InvalidEmailError()

    if not db.thread_exists(sql_cursor, thread_id):
        raise NonExistentThreadError(thread_id)

    if not db.comment_exists(sql_cursor, comment_id, thread_id):
        raise NonExistentCommentError(comment_id, thread_id)

    # create actual delete token (and store in DB)
    delete_token_id, delete_token_secret = generate_delete_token(sql_cursor, email, comment_id, thread_id)

    # TODO: remove
    print("delete token id", delete_token_id, "secret:", delete_token_secret)

    # TODO: send email to user (build the token string)
    # should contain a link: https://blog.pat.sh/comments/:thread_id/delete/:comment_id/?deltoken=:delete_token_id.delete_token_secret
    raise NotImplementedError("need to send the email to the user")

    return 200, {"success": "success"}