def operate(operation, type): user = check_permission() sudo = check_sudo(user) if not sudo: return flask.redirect("/dashboard/sudo") target_id = flask.request.args.get("target") if not target_id: flask.abort(400) hidden = True if operation == "delete" else False cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute( "UPDATE {0} SET hidden = %s WHERE {0}_id = %s ".format(type), (hidden, target_id)) cnx.commit() finally: cnx.close() referrer = "/" if type == "thread" else flask.request.referrer write_log(operation, user, {"type": type, "id": target_id}) return flask.redirect(referrer)
def logout(): referrer = flask.request.referrer try: referrer.index("/logout") except ValueError: pass else: referrer = "/" cookie = flask.request.cookies.get("session") if cookie == None: return flask.redirect(referrer) user_id = read_cookie(cookie) if user_id == None: return flask.redirect(referrer) cnx = get_pg_connection() response = flask.make_response(flask.redirect(referrer)) response.set_cookie("session", "", expires=0) response.set_cookie("sudo_mode", "", expires=0) write_log("logout", user_id, {"success": True}) return response
def new_thread(): now = datetime.datetime.now() try: userid = read_cookie(flask.request.cookies["session"]) except KeyError: flask.abort(401) if userid == None: flask.abort(401) try: title = flask.request.form["title"] category = flask.request.form["category"] renderer = flask.request.form["renderer"] content = flask.request.form["content"] is_draft = bool(int(flask.request.form["draft"])) except KeyError: flask.abort(400) thread_id = str(uuid.uuid4()).replace('-', '') post_id = str(uuid.uuid4()).replace('-', '') post_content_id = str(uuid.uuid4()).replace('-', '') cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute( "INSERT INTO thread VALUES (" "%s, %s, %s, %s, %s, FALSE, %s )", (thread_id, userid, category, now, title, bool(is_draft))) cursor.execute( "INSERT INTO post VALUES (" "%s, %s, %s, %s, FALSE, %s, %s)", (post_id, userid, thread_id, now, now, post_content_id)) cursor.execute( "INSERT INTO post_content VALUES (" "%s, %s, %s, %s, %s)", (post_content_id, post_id, renderer, content, now)) cnx.commit() write_log("new_thread", userid, { "success": True, "id": thread_id, "title": title }) finally: cnx.close() return flask.redirect("/thread/view/" + thread_id)
def registration(): if flask.request.method == "GET": referrer = flask.request.referrer return render_template("login.tmpl", title="注册", referrer=referrer, type="registration") try: username = flask.request.form["username"] password = flask.request.form["password"] email = flask.request.form["email"] referrer = flask.request.form["referrer"] except KeyError: flask.abort(400) cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute("SELECT * FROM users WHERE name = %s", (username, )) if cursor.fetchone() != None: write_log( "registration", "", { "success": False, "username": username, "reason": "user already exists" }) return render_template("login.tmpl", title="注册", referrer=referrer, error="用户 {} 已经存在".format(username)) user_id = str(uuid.uuid4()).replace('-', '').upper() salt = crypt.mksalt(crypt.METHOD_SHA256) hashed_password = hashlib.sha256( (password + salt).encode()).hexdigest().upper() cursor.execute( "INSERT INTO users VALUES ( " "%s, %s, %s, %s, %s, FALSE, FALSE, %s)", (user_id, username, email, hashed_password, username, salt)) cnx.commit() write_log("registration", user_id, {"success": True}) finally: cnx.close() cookie = create_cookie(user_id) response = flask.make_response(flask.redirect(referrer)) response.set_cookie("session", cookie, expires=32503680000) return response
def userinfo_update(): user = check_permission() sudo = check_sudo(user) if not sudo: return flask.redirect("/dashboard/sudo") try: userid = flask.request.form["id"] nick = flask.request.form["nick"] email = flask.request.form["email"] superuser = flask.request.form["superuser"] except KeyError: flask.abort(400) superuser = (superuser == "true") cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute( "SELECT nick, email, admin FROM users WHERE user_id = %s", (userid, )) oldnick, oldemail, oldadmin = cursor.fetchone() cursor.execute( "UPDATE users SET (nick, email, admin) = ( " "%s, %s, %s ) WHERE user_id = %s", (nick, email, superuser, userid)) cnx.commit() finally: cnx.close() log_data = { "operator": user, "original": { "nick": oldnick, "email": oldemail, "superuser": oldadmin }, "new": { "nick": nick, "email": email, "superuser": superuser } } write_log("update_profile", user, log_data) return flask.redirect("/dashboard/userinfo/{}".format(userid))
def category_merge(): user = check_permission() sudo = check_sudo(user) if not sudo: return flask.redirect("/dashboard/sudo") try: src_id = flask.request.form["src"] dst_id = flask.request.form["dst"] except KeyError: flask.abort(400) cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute('SELECT name FROM category WHERE category_id = %s', (src_id, )) src_name, = cursor.fetchone() cursor.execute('SELECT name FROM category WHERE category_id = %s', (dst_id, )) dst_name, = cursor.fetchone() cursor.execute('UPDATE thread SET category = %s WHERE category = %s', (dst_id, src_id)) cursor.execute('DELETE FROM category WHERE category_id = %s', (src_id, )) cnx.commit() finally: cnx.close() log_data = { "src": { "id": src_id, "name": src_name }, "dst": { "id": dst_id, "name": dst_name } } write_log("category_merge", user, log_data) return flask.redirect("/dashboard/category")
def reply(): now = datetime.datetime.now() try: userid = read_cookie(flask.request.cookies["session"]) except KeyError: flask.abort(401) if userid == None: flask.abort(401) try: renderer = flask.request.form["renderer"] content = flask.request.form["content"] thread_id = flask.request.form["thread_id"] except KeyError: flask.abort(400) post_id = str(uuid.uuid4()).replace('-', '') post_content_id = str(uuid.uuid4()).replace('-', '') cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute( "INSERT INTO post VALUES (" "%s, %s, %s, %s, FALSE, %s, %s)", (post_id, userid, thread_id, now, now, post_content_id)) cursor.execute( "INSERT INTO post_content VALUES (" "%s, %s, %s, %s, %s)", (post_content_id, post_id, renderer, content, now)) cnx.commit() write_log("new_reply", userid, { "success": True, "post_id": post_id, "content_id": post_content_id }) finally: cnx.close() return flask.redirect(flask.request.referrer)
def sudo(): user = check_permission() redis = get_redis_connection() failed_attempts = redis.get('sudo_fail_{}'.format(user)) failed_attempts = int(failed_attempts) if failed_attempts != None else 0 if failed_attempts >= 5: write_log("dashboard_access", user, { "success": False, "reason": "too many attemps" }) return render_template("dashboard/sudo.tmpl", error=True, chances=0) if flask.request.method == "GET": return render_template("dashboard/sudo.tmpl") password = flask.request.form.get("password") if password == None: flask.abort(400) cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute("SELECT salt FROM users WHERE user_id = %s", (user, )) salt = cursor.fetchone()[0] finally: cnx.close() hashed_password = hashlib.sha256( (password + salt).encode()).hexdigest().upper() cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute( "SELECT * FROM users WHERE user_id = %s AND password = %s", (user, hashed_password)) result = cursor.fetchone() finally: cnx.close() if result == None: write_log("dashboard_access", user, {"success": False}) redis = get_redis_connection() failed_attemps = int(redis.incr('sudo_fail_{}'.format(user))) redis.expire('sudo_fail_{}'.format(user), 300) ret = render_template("dashboard/sudo.tmpl", error=True, chances=max(5 - failed_attemps, 0)) return ret else: ret = flask.make_response(flask.redirect("/dashboard/")) ret.set_cookie("sudo_mode", create_cookie(user)) redis = get_redis_connection() redis.delete('sudo_fail_{}'.format(user)) write_log("dashboard_access", user, {"success": True}) return ret
def check_permission(): session = flask.request.cookies.get("session") if session == None or read_cookie(session) == None: write_log("dashboard_access", "", {"success": False}) flask.abort(401) user = read_cookie(session) cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute( "SELECT * FROM users WHERE user_id = %s AND admin = TRUE", (user, )) result = (cursor.fetchone() != None) finally: cnx.close() if not result: write_log("dashboard_access", user, {"success": False}) flask.abort(401) return user
def categories_new(): user = check_permission() sudo = check_sudo(user) if not sudo: return flask.redirect("/dashboard/sudo") name = flask.request.form.get("name") if not name: flask.abort(400) category_id = str(uuid.uuid4()).replace('-', '').upper() cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute("INSERT INTO category VALUES (%s, %s)", (category_id, name)) cnx.commit() finally: cnx.close() write_log("category_new", user, {"success": True, "category": name}) return flask.redirect('/dashboard/category')
def userinfo(): try: user = read_cookie(flask.request.cookies["session"]) except KeyError: return flask.redirect("/") if not user: flask.redirect("/") cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute( 'SELECT name, email, nick, salt FROM users WHERE user_id = %s', (user, )) name, email, nick, salt = cursor.fetchone() finally: cnx.close() if flask.request.method == "GET": return render_template("userinfo.tmpl", error=False, name=name, email=email, nick=nick, title="User Info") else: try: new_email = flask.request.form["email"] new_nick = flask.request.form["nick"] old_password = flask.request.form["old_password"] new_password = flask.request.form["new_password"] except: return flask.abort(400) if new_password != "": cnx = get_pg_connection() cursor = cnx.cursor() try: hashed_old_password = hashlib.sha256( (old_password + salt).encode()).hexdigest().upper() cursor.execute( "SELECT user_id FROM users WHERE user_id = %s AND password = %s", (user, hashed_old_password)) if not cursor.fetchone(): cnx.close() write_log("update_userinfo", user, { "success": False, "reason": "wrong password" }) return render_template("userinfo.tmpl", error=True, name=name, email=email, nick=nick, title="User Info") except: cnx.close() raise salt = crypt.mksalt(crypt.METHOD_SHA256) hashed_password = hashlib.sha256( (new_password + salt).encode()).hexdigest().upper() else: hashed_password = None cnx = get_pg_connection() try: cursor = cnx.cursor() if hashed_password: cursor.execute( "UPDATE users SET email = %s, nick = %s, password = %s, salt = %s WHERE user_id = %s", (new_email, new_nick, hashed_password, salt, user)) else: cursor.execute( "UPDATE users SET email = %s, nick = %s WHERE user_id = %s", (new_email, new_nick, user)) cnx.commit() finally: cnx.close() log_data = { "success": True, "nick": [nick, new_nick], "email": [email, new_email], "password_changed": new_password != "" } write_log("update_userinfo", user, log_data) return flask.redirect("/userinfo")
def edit(edit_type): try: renderer = flask.request.form["renderer"] content = flask.request.form["content"] referrer = flask.request.form["referrer"] post_id = flask.request.form["post_id"] except KeyError: flask.abort(400) user = read_cookie(flask.request.cookies["session"]) cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute( "SELECT post.author, users.admin, post.content FROM post, users " "WHERE post.post_id = %s AND users.user_id = %s " "AND (post.author = users.user_id OR users.admin = TRUE)", (post_id, user)) post_ret = cursor.fetchone() if not post_ret: cnx.close() flask.abort(401) _, _, old_content_id = post_ret except: cnx.close() raise if edit_type == "thread": try: thread_id = flask.request.form["thread_id"] title = flask.request.form["title"] category = flask.request.form["category"] is_draft = bool(int(flask.request.form["draft"])) except KeyError: flask.abort(400) cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute( "SELECT title, category, draft FROM thread " "WHERE thread_id = %s", (thread_id, )) old_title, old_category, old_draft = cursor.fetchone() except TypeError: flask.abort(400) new_content_id = str(uuid.uuid4()).replace('-', '') cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute( "INSERT INTO post_content VALUES (" "%s, %s, %s, %s, NOW())", (new_content_id, post_id, renderer, content)) cursor.execute( "UPDATE post SET content = %s, last_modified = NOW() WHERE post_id = %s", (new_content_id, post_id)) if edit_type == "thread": cursor.execute( "UPDATE thread SET title = %s, category = %s, draft = %s " "WHERE thread_id = %s", (title, category, is_draft, thread_id)) cnx.commit() except: traceback.print_exc() finally: cnx.close() log_data = { "success": True, "post_id": post_id, "type": edit_type, "rev": [old_content_id, new_content_id] } if edit_type == "thread": log_data["thread"] = { "title": [old_title, title], "category": [old_category, category], "draft": [old_draft, is_draft] } write_log("edit", user, log_data) return flask.redirect(referrer)
def login(): if flask.request.method == "GET": referrer = flask.request.referrer else: referrer = flask.request.form["referrer"] try: referrer.index("/login") except ValueError: pass else: referrer = "/" if flask.request.method == "GET": return render_template("login.tmpl", title="登录", referrer=flask.request.referrer, error=None, type="login") else: username = flask.request.form["username"] password = flask.request.form["password"] cnx = get_pg_connection() try: cursor = cnx.cursor() cursor.execute("SELECT salt FROM users WHERE name = %s", (username, )) salt = cursor.fetchone() if salt: salt = salt[0] else: error = "用户名或密码错误" write_log( "login", "", { "success": False, "username": username, "reason": "user does not exist" }) return render_template("login.tmpl", referrer=referrer, error=error, title="Login", type="login") hashed_password = hashlib.sha256( (password + salt).encode()).hexdigest().upper() cursor.execute( "SELECT user_id AS uid FROM users WHERE name = %s AND password = %s", (username, hashed_password)) ret = cursor.fetchone() if not ret: cnx.close() error = "用户名或密码错误" write_log( "login", "", { "success": False, "username": username, "reason": "wrong password" }) return render_template("login.tmpl", referrer=referrer, error=error, title="Login", type="login") finally: cnx.close() userid = ret[0] cookie = create_cookie(userid) response = flask.make_response(flask.redirect(referrer)) response.set_cookie("session", cookie, expires=32503680000) write_log("login", userid, {"success": True, "username": username}) return response