This commit is contained in:
maaa 2023-07-09 22:00:15 +02:00
parent f7d22cf36c
commit ad0fdeba35
8 changed files with 198 additions and 8 deletions

74
main
View File

@ -10,6 +10,8 @@ from itertools import groupby
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
from flask import Flask, render_template, request, url_for, flash, redirect, session, make_response, send_from_directory, stream_with_context, Response, request from flask import Flask, render_template, request, url_for, flash, redirect, session, make_response, send_from_directory, stream_with_context, Response, request
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
# read config file # read config file
config = configparser.ConfigParser() config = configparser.ConfigParser()
@ -26,6 +28,14 @@ app = Flask(__name__)
app.config["SECRET_KEY"] = SECRET_KEY app.config["SECRET_KEY"] = SECRET_KEY
app.config["MAX_CONTENT_LENGTH"] = int(UPLOAD_LIMIT) * 1000 * 1000 app.config["MAX_CONTENT_LENGTH"] = int(UPLOAD_LIMIT) * 1000 * 1000
limiter = Limiter(
get_remote_address,
app = app,
default_limits = ["3 per second"],
storage_uri = "memory://",
strategy = "fixed-window"
)
if SECRET_KEY == "placeholder": if SECRET_KEY == "placeholder":
print("[WARNING] Secret key is not set") print("[WARNING] Secret key is not set")
@ -85,8 +95,8 @@ app.jinja_env.globals.update(getUser=get_user)
def check_username_taken(username): def check_username_taken(username):
conn = get_db_connection() conn = get_db_connection()
post = conn.execute("SELECT * FROM users WHERE username = ?", post = conn.execute("SELECT * FROM users WHERE lower(username) = ?",
(username,)).fetchone() (username.lower(),)).fetchone()
conn.close() conn.close()
if post is None: if post is None:
return "error" return "error"
@ -125,6 +135,53 @@ def main():
else: else:
return render_template("main.html", posts=posts) return render_template("main.html", posts=posts)
@app.route("/@<pageusername>", methods=("GET", "POST"))
def user(pageusername):
usersession = request.cookies.get("session_DO_NOT_SHARE")
checkusername = check_username_taken(pageusername)
if not checkusername == "error":
pageuser = get_user(checkusername)
if usersession:
userCookie = get_session(usersession)
user = get_user(userCookie["id"])
return render_template("user.html", userdata=user, createddate=datetime.datetime.utcfromtimestamp(int(str(pageuser["created"]).split(".")[0])).strftime("%Y-%m-%d"), pageuser=pageuser)
else:
return render_template("user.html", createddate=datetime.datetime.utcfromtimestamp(int(str(pageuser["created"]).split(".")[0])).strftime("%Y-%m-%d"), pageuser=pageuser)
else:
return """<img src="https://http.cat/images/404.jpg">""", 404
@app.route("/@<pageusername>/edit", methods=("GET", "POST"))
def edituser(pageusername):
usersession = request.cookies.get("session_DO_NOT_SHARE")
checkusername = check_username_taken(pageusername)
if not checkusername == "error":
pageuser = get_user(checkusername)
if usersession:
userCookie = get_session(usersession)
user = get_user(userCookie["id"])
if pageuser["username"] == user["username"]:
if request.method == "POST":
code = request.form["code"].replace("Content-Security-Policy", "")
conn = get_db_connection()
conn.execute("UPDATE users SET htmldescription = ? WHERE id = ?",
(code, user["id"]))
conn.commit()
conn.close()
return redirect("/@" + user["username"])
else:
return render_template("edituser.html", userdata=user, pageuser=pageuser)
else:
return """<img src="https://http.cat/images/403.jpg">""", 403
else:
return """<img src="https://http.cat/images/403.jpg">""", 403
else:
return """<img src="https://http.cat/images/404.jpg">""", 404
@app.route("/api/frontpage", methods=("GET", "POST")) @app.route("/api/frontpage", methods=("GET", "POST"))
def apifrontpage(): def apifrontpage():
conn = get_db_connection() conn = get_db_connection()
@ -332,6 +389,7 @@ def post():
@app.route("/api/comment", methods=("GET", "POST")) @app.route("/api/comment", methods=("GET", "POST"))
@limiter.limit("1/second", override_defaults=False)
def comment(): def comment():
usersession = request.cookies.get("session_DO_NOT_SHARE") usersession = request.cookies.get("session_DO_NOT_SHARE")
if usersession: if usersession:
@ -377,12 +435,13 @@ def cdn(filename):
@app.route("/signup", methods=("GET", "POST")) @app.route("/signup", methods=("GET", "POST"))
@limiter.limit("5/minute", override_defaults=False)
def signup(): def signup():
usersession = request.cookies.get("session_DO_NOT_SHARE") usersession = request.cookies.get("session_DO_NOT_SHARE")
if usersession: if usersession:
return redirect(url_for("main")) return redirect(url_for("main"))
if request.method == "POST": if request.method == "POST":
if not check_username_taken(str(request.form["username"]).lower()) == "error": if not check_username_taken(request.form["username"]) == "error":
flash("Username already taken :3") flash("Username already taken :3")
return redirect(url_for("signup")) return redirect(url_for("signup"))
@ -397,8 +456,8 @@ def signup():
hashedpassword = generate_password_hash(request.form["password"]) hashedpassword = generate_password_hash(request.form["password"])
conn = get_db_connection() conn = get_db_connection()
conn.execute("INSERT INTO users (username, password, created) VALUES (?, ?, ?)", conn.execute("INSERT INTO users (username, password, created, htmldescription) VALUES (?, ?, ?, ?)",
(request.form["username"], hashedpassword, str(time.time()))) (request.form["username"], hashedpassword, str(time.time()), ""))
conn.commit() conn.commit()
conn.close() conn.close()
@ -408,6 +467,7 @@ def signup():
@app.route("/login", methods=("GET", "POST")) @app.route("/login", methods=("GET", "POST"))
@limiter.limit("10/minute", override_defaults=False)
def login(): def login():
usersession = request.cookies.get("session_DO_NOT_SHARE") usersession = request.cookies.get("session_DO_NOT_SHARE")
if usersession: if usersession:
@ -508,6 +568,10 @@ def page_not_found(e):
def page_not_found(e): def page_not_found(e):
return """<img src="https://http.cat/images/400.jpg">""", 400 return """<img src="https://http.cat/images/400.jpg">""", 400
@app.errorhandler(429)
def page_not_found(e):
return """<img src="https://http.cat/images/429.jpg">""", 429
@app.errorhandler(404) @app.errorhandler(404)
def page_not_found(e): def page_not_found(e):
return """<img src="https://http.cat/images/404.jpg">""", 404 return """<img src="https://http.cat/images/404.jpg">""", 404

View File

@ -1,3 +1,4 @@
flask flask
Flask-Limiter
werkzeug werkzeug
waitress waitress

View File

@ -9,7 +9,8 @@ CREATE TABLE users (
username TEXT NOT NULL, username TEXT NOT NULL,
password TEXT NOT NULL, password TEXT NOT NULL,
banned TEXT NOT NULL DEFAULT 0, banned TEXT NOT NULL DEFAULT 0,
administrator INTEGER NOT NULL DEFAULT 0 administrator INTEGER NOT NULL DEFAULT 0,
htmldescription TEXT NOT NULL
); );
CREATE TABLE posts ( CREATE TABLE posts (

View File

@ -25,7 +25,32 @@ body {
.postDiv { .postDiv {
padding-top: 120px; padding-top: 120px;
} }
.profileDiv {
padding-left: 10px;
padding-right: 10px;
}
.profileIFrame {
border: solid;
border-width: 0;
border-top-width: 1px;
border-color: rgb(241, 241, 241);
width: 100%;
height: calc(100vh - 295px);
}
.profileDiv .badgeDiv p {
background-color: black;
border-radius: 99px;
color: white;
padding: 5px;
padding-left: 10px;
padding-right: 10px;
display: inline;
}
.editThing .htmlBox {
width: calc(100% - 10px);
height: 300px;
text-align: top;
}
.accountform { .accountform {
margin-left: 20%; margin-left: 20%;
margin-right: 20%; margin-right: 20%;
@ -85,6 +110,7 @@ body {
.post img { .post img {
min-height: 200px; min-height: 200px;
max-height: 300px; max-height: 300px;
max-width: 100%;
border-radius: 10px; border-radius: 10px;
} }
@ -131,6 +157,11 @@ body {
color: rgb(175, 175, 175); color: rgb(175, 175, 175);
} }
.usernamelink {
color: black;
text-decoration: none;
}
.hidden { .hidden {
display: none; display: none;
} }

41
templates/edituser.html Normal file
View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<title>burgercat</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
</head>
<body>
<div class="navbar">
<h1>burgercat</h1>
<a class="selected" href="/">home</a>
<a href="/post">post</a>
{% if userdata %}
<a href="/settings/logout" class="right r">log out</a>
<a href="/settings" class="right">{{ userdata.username }}</a>
{% else %}
<a href="/signup" class="right r">sign up</a>
<a href="/login" class="right">log in</a>
{% endif %}
</div>
<div class="postDiv">
<div class="profileDiv">
{% if userdata %}
{% if pageuser.id == userdata.id %}
<h2>edit mode</h2>
<form class="editThing" method="post" enctype="multipart/form-data">
<textarea class="htmlBox" name="code" type="text" placeholder="<p>Hello World!</p>">{{ userdata.htmldescription }}</textarea>
<br><br>
<input class="submit" type="submit" value="save">
</form>
{% endif %}
{% endif %}
</div>
</div>
</body>
</html>

View File

@ -31,7 +31,7 @@
<div class="postDiv"> <div class="postDiv">
{% for post in posts %} {% for post in posts %}
<div class="post" id="post"> <div class="post" id="post">
<p class="username">{{ getUser(post["creator"])["username"] }}</p> <p><a href='/@{{ getUser(post["creator"])["username"] }}' class="username usernamelink">{{ getUser(post["creator"])["username"] }}</a></p>
<p class="date" id='timestamp_{{post["id"]}}'> </p> <p class="date" id='timestamp_{{post["id"]}}'> </p>
{% if userdata %} {% if userdata %}
{% if userdata.administrator == 1 %} {% if userdata.administrator == 1 %}

View File

@ -30,6 +30,7 @@
{% endif %} {% endif %}
Logged in as {{ userdata.username }} Logged in as {{ userdata.username }}
<br><br> <br><br>
<a href="/@{{ userdata.username }}">View my public profile</a><br>
<a href="/settings/logout">Log out</a> <a href="/settings/logout">Log out</a>
</div> </div>
</div> </div>

51
templates/user.html Normal file
View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<title>burgercat</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self' fonts.gstatic.com fonts.googleapis.com" />
</head>
<body>
<div class="navbar">
<h1>burgercat</h1>
<a class="selected" href="/">home</a>
<a href="/post">post</a>
{% if userdata %}
<a href="/settings/logout" class="right r">log out</a>
<a href="/settings" class="right">{{ userdata.username }}</a>
{% else %}
<a href="/signup" class="right r">sign up</a>
<a href="/login" class="right">log in</a>
{% endif %}
</div>
<div class="postDiv">
<div class="profileDiv">
<h2>{{ pageuser.username }}</h2>
<div class="badgeDiv">
{% if pageuser.administrator == 1 %}
<p>Administrator</p>
{% endif %}
</div>
<p>Joined on {{ createddate }}</p>
{% if userdata %}
{% if pageuser.id == userdata.id %}
<a style="color: rgb(104, 104, 104); text-decoration: none;" href="/@{{ userdata.username }}/edit">edit page</a>
<br><br>
{% endif %}
{% endif %}
</div>
<iframe class="profileIFrame" sandbox="" srcdoc="{{ pageuser.htmldescription }}"></iframe>
</div>
<style>
body {
overflow-y: hidden
}
</style>
</body>
</html>