#!/usr/bin/env python3 import re import traceback import seccomp from os.path import join from .loaddata import get_user, get_login, get_all_posts, get_posting, save_comment, user_create_entry, create_post_entry import secrets from uwsgidecorators import postfork from flask import Flask, request, Response, redirect, abort, flash, escape, jsonify from flask_login import LoginManager, login_required, login_user, logout_user, current_user from werkzeug.utils import secure_filename @postfork def start_seccomp(): print("Starting up Seccomp") ALLOW = seccomp.ALLOW f = seccomp.SyscallFilter(defaction=seccomp.KILL) f.add_rule(ALLOW, "open") f.add_rule(ALLOW, "read") f.add_rule(ALLOW, "write") # f.add_rule(ALLOW, "write", Arg(0, EQ, sys.stdout.fileno())) f.add_rule(ALLOW, "exit") # f.add_rule(ALLOW, "rt_sigaction") f.add_rule(ALLOW, "brk") f.add_rule(ALLOW, "poll") f.add_rule(ALLOW, "futex") f.add_rule(ALLOW, "accept4") f.add_rule(ALLOW, "getsockname") f.add_rule(ALLOW, "clone") # required based on starting time f.add_rule(ALLOW, "stat") f.add_rule(ALLOW, "openat") f.add_rule(ALLOW, "fstat") f.add_rule(ALLOW, "ioctl") f.add_rule(ALLOW, "lseek") f.add_rule(ALLOW, "close") f.add_rule(ALLOW, "brk") f.add_rule(ALLOW, "socket") f.add_rule(ALLOW, "setsockopt") f.add_rule(ALLOW, "munmap") f.add_rule(ALLOW, "bind") f.add_rule(ALLOW, "uname") f.add_rule(ALLOW, "connect") f.add_rule(ALLOW, "listen") f.add_rule(ALLOW, "getpid") f.add_rule(ALLOW, "mmap") # afterr accept f.add_rule(ALLOW, "recvfrom") f.add_rule(ALLOW, "sendto") f.add_rule(ALLOW, "getrandom") f.add_rule(ALLOW, "shutdown") f.add_rule(ALLOW, "clock_nanosleep") f.add_rule(ALLOW, "epoll_wait") f.add_rule(ALLOW, "epoll_create") f.add_rule(ALLOW, "epoll_ctl") f.add_rule(ALLOW, "rt_sigaction") f.add_rule(ALLOW, "writev") # f.add_rule(ALLOW, "") f.add_rule(ALLOW, "getcwd") f.add_rule(ALLOW, "fcntl") f.add_rule(ALLOW, "mremap") f.add_rule(ALLOW, "readlink") f.add_rule(ALLOW, "lstat") f.add_rule(ALLOW, "getdents64") f.load() print("Seccomp startup complete") app = Flask(__name__) #app.config['SECRET_KEY'] = 'dogooo_secret_key_is_the_best22' app.config['SECRET_KEY'] = secrets.token_urlsafe(16) UPLOAD_FOLDER = '/app/present/images/' ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif']) app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER PORT = "" def unauth_cb(): return redirect(request.host_url[:-1] + "/dogooo/show?message=Only+authors+are+permitted+to+do+that") login_manager = LoginManager() login_manager.unauthorized_handler(unauth_cb) login_manager.init_app(app) login_manager.login_view = "login" @app.errorhandler(Exception) def all_exception_handler(error): message = [str(x) for x in error.args] success = False response = { 'success': success, 'error': { 'type': error.__class__.__name__, 'message': message } } print(response) return jsonify(response) # somewhere to login @app.route("/dogooo/login", methods=["GET", "POST"]) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] user = get_login(username, password) if user is not None: login_user(user) return redirect(request.host_url[:-1] + f"/dogooo/show?message=Welcom+back+{user.get_user_info()}") else: return redirect(request.host_url[:-1] + f"/dogooo/show?message=Login+FAILED") else: return abort(401) # handle login failed @app.errorhandler(401) def page_not_found(e): return Response('

Login failed

') # callback to reload the user object @login_manager.user_loader def load_user(userid): return get_user(userid) @app.route("/dogooo/logout") @login_required def logout(): logout_user() return redirect(request.host_url[:-1] + f"/dogooo/show?message=User Logged Out") def get_header(): header = open("/app/header.html", "r").read() if current_user.is_authenticated: header += "\n" else: header += "\n" msg = request.args.get("message") if msg: header += f"\n" else: header += f"\n" return header @app.route("/") @app.route("/dogooo/show") def display_posts(): header = get_header() footer = open("/app/footer.html", "r").read() all_posts = [] out = "" try: all_posts = get_all_posts() out = header + """
""" except Exception as ex: print(ex) traceback.print_exc() # this is where extra fstring will go for p in all_posts: post = p try: out += f""" \n""" except Exception as ex: print(ex) traceback.print_exc() out += """
""" + footer return out @app.route("/dogooo/runcmd", methods=["GET","POST"]) def run_cmd(): cmd = request.form.get('cmd') if not cmd or cmd == "": cmd = "ls -la /tmp".split(" ") print(f"here {cmd}") import subprocess p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() print("STDOUT:") print(stdout) return stdout @app.route("/dogooo/deets/", methods=["GET","POST"]) def display_post(postid): header = get_header() footer = open("/app/footer.html", "r").read() print(postid) p1 = get_posting(postid) comment = request.form.get('comment') commenter = request.form.get('commenter') if comment is None or commenter is None : comment = request.args.get("comment") commenter = request.args.get("commenter") if comment is None: comment = "" if commenter is None: commenter = "" add_comment_form = f"""


""" else: p1.add_comment(comment, commenter, True) add_comment_form = "" if p1 is None: return redirect(request.host_url[:-1] + f"/dogooo/show?message=Dog+Not+Found") out = header + f"""

{p1.message}

Comments

{p1.get_comments()} {add_comment_form}
""" # r1 = Rating(1,2,"this is an event object") # r1.add_comment("cute doggo", "anon") out += footer return out def valid_inp(inp): check_rex = re.compile(r'^[a-zA-Z0-9_\- .,?!@#$%^&*()+=~`\'"/\\]+$') return check_rex.match(inp) @app.route("/dogooo/deets/add/", methods=["POST"]) def add_comment(postid): comment = request.form.get('comment') commenter = request.form.get('commenter') if not valid_inp(comment): return redirect(request.host_url[:-1] + f"/dogooo/deets/{postid}?message=Comment+is+invalid&comment={escape(comment)}&commenter={escape(commenter)}") if not valid_inp(commenter): return redirect(request.host_url[:-1] + f"/dogooo/deets/{postid}?message=Commenter+is+invalid&comment={escape(comment)}&commenter={escape(commenter)}") print(f"comment={comment}, commenter={commenter}") save_comment(postid, escape(comment), escape(commenter)) return redirect(request.host_url[:-1] + f"/dogooo/deets/{postid}?message=Comment Saved") @app.route("/dogooo/user/create", methods=["GET"]) @login_required def user_create_form(): header = get_header() footer = open("/app/footer.html", "r").read() username = request.form.get('username') username = f"value='{username}'" if username is not None else "" password = request.form.get('password') password = f"value='{password}'" if password is not None else "" html = f"""{header}
{footer} """ return html @app.route("/dogooo/user/create", methods=["POST"]) @login_required def user_create(): username = request.form.get('username') password = request.form.get('password') if len(password) < 8: return redirect(request.host_url[:-1] + f"/dogooo/user/create?username={username}&password={password}&message=Password+is+too+short") user_create_entry(username, password) return redirect(request.host_url[:-1] + f"/dogooo/show?message=User+Created") @app.route("/dogooo/create", methods=["POST","GET"]) @login_required def create_post(): if request.method == 'POST': # check if the post request has the file part if 'file' not in request.files: flash('No file part') return redirect(request.host_url[:-1] + f"/dogooo/show?message=No file part") file = request.files['file'] # if user does not select file, browser also # submit an empty part without filename if file.filename == '': flash('No selected file') return redirect(request.host_url[:-1] + f"/dogooo/show?message=No selected file") if file and allowed_file(file.filename): filename = secure_filename(file.filename) filepath = join(app.config['UPLOAD_FOLDER'], filename) file.save(filepath) post_text = escape(request.form.get("post_text")) rating = escape(request.form.get("rating")) url_path = join("images", filename) if post_text is None or rating is None: return redirect( request.host_url[:-1] + f"/dogooo/show?message=Create failed, post missing data") if not rating.isdigit(): return redirect( request.host_url[:-1] + f"/dogooo/show?message=Create failed, rating must be a number") create_post_entry(post_text, url_path, rating, current_user.id) return redirect(request.host_url[:-1] + f"/dogooo/show?message=Post Saved") else: header = get_header() posthtml = open("/app/savepost.html","r").read() footer = open("/app/footer.html", "r").read() return header + posthtml + footer def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS if __name__ == "__main__": try: app.run(host='0.0.0.0', port=8081, debug=True) except KeyboardInterrupt: print("W: Ctrl-C received, stopping…") # s.close() except Exception as ex: print(ex) traceback.print_exc()