Beispiel #1
0
def fetch(app, environ, request, uri):

    rv = list(app.db.comments.fetch(uri))
    if not rv:
        raise NotFound

    for item in rv:

        key = item['email'] or item['remote_addr']
        val = app.cache.get('hash', key.encode('utf-8'))

        if val is None:
            val = str(pbkdf2(key, app.salt, 1000, 6))
            app.cache.set('hash', key.encode('utf-8'), val)

        item['hash'] = val

        for key in set(item.keys()) - FIELDS:
            item.pop(key)

    if request.args.get('plain', '0') == '0':
        for item in rv:
            item['text'] = app.markdown(item['text'])

    return Response(json.dumps(rv), 200, content_type='application/json')
Beispiel #2
0
def fetch(app, environ, request, uri):

    rv = list(app.db.comments.fetch(uri))
    if not rv:
        raise NotFound

    for item in rv:

        key = item['email'] or item['remote_addr']
        val = app.cache.get('hash', key)

        if val is None:
            val = str(pbkdf2(key, app.salt, 1000, 6))
            app.cache.set('hash', key, val)

        item['hash'] = val

        for key in set(item.keys()) - FIELDS:
            item.pop(key)

    if request.args.get('plain', '0') == '0':
        for item in rv:
            item['text'] = app.markdown(item['text'])

    return Response(json.dumps(rv), 200, content_type='application/json')
Beispiel #3
0
def new(app, environ, request, uri):

    data = request.get_json()

    for field in set(data.keys()) - set(['text', 'author', 'website', 'email', 'parent']):
        data.pop(field)

    if "text" not in data or data["text"] is None or len(data["text"]) < 3:
        raise BadRequest("no text given")

    if "id" in data and not isinstance(data["id"], int):
        raise BadRequest("parent id must be an integer")

    if len(data.get("email") or "") > 254:
        raise BadRequest("http://tools.ietf.org/html/rfc5321#section-4.5.3")

    for field in ("author", "email"):
        if data.get(field):
            data[field] = cgi.escape(data[field])

    data['mode'] = (app.conf.getboolean('moderation', 'enabled') and 2) or 1
    data['remote_addr'] = utils.anonymize(str(request.remote_addr))

    with app.lock:
        if uri not in app.db.threads:
            for host in app.conf.getiter('general', 'host'):
                with http.curl('GET', host, uri) as resp:
                    if resp and resp.status == 200:
                        title = parse.title(resp.read())
                        break
            else:
                return Response('URI does not exist', 404)

            app.db.threads.new(uri, title)
            logger.info('new thread: %s -> %s', uri, title)
        else:
            title = app.db.threads[uri].title

    try:
        with app.lock:
            rv = app.db.comments.add(uri, data)
    except db.IssoDBException:
        raise Forbidden

    host = list(app.conf.getiter('general', 'host'))[0].rstrip("/")
    href = host + uri + "#isso-%i" % rv["id"]

    deletion = host + environ["SCRIPT_NAME"] + "/delete/" + app.sign(str(rv["id"]))
    activation = None

    if app.conf.getboolean('moderation', 'enabled'):
        activation = host + environ["SCRIPT_NAME"] + "/activate/" + app.sign(str(rv["id"]))

    app.notify(title, notify.format(rv, href, utils.anonymize(str(request.remote_addr)),
                                    activation_key=activation, deletion_key=deletion))

    # save checksum of text into cookie, so mallory can't modify/delete a comment, if
    # he add a comment, then removed it but not the signed cookie.
    checksum = hashlib.md5(rv["text"].encode('utf-8')).hexdigest()

    rv["text"] = app.markdown(rv["text"])
    rv["hash"] = str(pbkdf2(rv['email'] or rv['remote_addr'], app.salt, 1000, 6))

    app.cache.set('hash', (rv['email'] or rv['remote_addr']).encode('utf-8'), rv['hash'])

    for key in set(rv.keys()) - FIELDS:
        rv.pop(key)

    # success!
    logger.info('comment created: %s', json.dumps(rv))

    cookie = functools.partial(dump_cookie,
        value=app.sign([rv["id"], checksum]),
        max_age=app.conf.getint('general', 'max-age'))

    resp = Response(json.dumps(rv), 202 if rv["mode"] == 2 else 201, content_type='application/json')
    resp.headers.add("Set-Cookie", cookie(str(rv["id"])))
    resp.headers.add("X-Set-Cookie", cookie("isso-%i" % rv["id"]))
    return resp
Beispiel #4
0
def new(app, environ, request, uri):

    data = request.get_json()

    for field in set(data.keys()) - set(
        ['text', 'author', 'website', 'email', 'parent']):
        data.pop(field)

    if not data.get("text"):
        raise BadRequest("no text given")

    if "id" in data and not isinstance(data["id"], int):
        raise BadRequest("parent id must be an integer")

    for field in ("author", "email"):
        if data.get(field):
            data[field] = cgi.escape(data[field])

    data['mode'] = (app.conf.getboolean('moderation', 'enabled') and 2) or 1
    data['remote_addr'] = utils.anonymize(str(request.remote_addr))

    with app.lock:
        if uri not in app.db.threads:
            for host in app.conf.getiter('general', 'host'):
                with http.curl('GET', host, uri) as resp:
                    if resp and resp.status == 200:
                        title = parse.title(resp.read())
                        break
            else:
                return Response('URI does not exist', 404)

            app.db.threads.new(uri, title)
            logger.info('new thread: %s -> %s', uri, title)
        else:
            title = app.db.threads[uri].title

    try:
        with app.lock:
            rv = app.db.comments.add(uri, data)
    except db.IssoDBException:
        raise Forbidden

    host = list(app.conf.getiter('general', 'host'))[0].rstrip("/")
    href = host + uri + "#isso-%i" % rv["id"]

    deletion = host + environ["SCRIPT_NAME"] + "/delete/" + app.sign(
        str(rv["id"]))
    activation = None

    if app.conf.getboolean('moderation', 'enabled'):
        activation = host + environ["SCRIPT_NAME"] + "/activate/" + app.sign(
            str(rv["id"]))

    app.notify(
        title,
        notify.format(rv,
                      href,
                      utils.anonymize(str(request.remote_addr)),
                      activation_key=activation,
                      deletion_key=deletion))

    # save checksum of text into cookie, so mallory can't modify/delete a comment, if
    # he add a comment, then removed it but not the signed cookie.
    checksum = hashlib.md5(rv["text"].encode('utf-8')).hexdigest()

    rv["text"] = app.markdown(rv["text"])
    rv["hash"] = str(
        pbkdf2(rv.get('email') or rv['remote_addr'], app.salt, 1000, 6))

    for key in set(rv.keys()) - FIELDS:
        rv.pop(key)

    # success!
    logger.info('comment created: %s', json.dumps(rv))

    resp = Response(json.dumps(rv),
                    202 if rv["mode"] == 2 else 201,
                    content_type='application/json')
    resp.set_cookie(str(rv["id"]),
                    app.sign([rv["id"], checksum]),
                    max_age=app.conf.getint('general', 'max-age'))
    return resp