def load(app): # upgrade() app.db.create_all() CHALLENGE_CLASSES["steam"] = SteamChallenge register_plugin_assets_directory( app, base_path="/plugins/steam_challenge/assets/" ) register_user_page_menu_bar("Steam Keys", "steamkeys") blueprint = Blueprint( "steam_challenge", __name__, template_folder="templates", static_folder="assets" ) @blueprint.route("/steamkeys", methods=["GET", "POST"]) @require_verified_emails @authed_only def view_keys(): user = get_current_user() chals = SteamChallengeModel.query.filter_by(first_solver=user.account_id).order_by(SteamChallengeModel.id.asc()).all() my_keys = [] for chal in chals: d = SteamChallenge.read(chal) d["steam_key"] = chal.steam_key d["steam_gamename"] = chal.steam_gamename my_keys.append(d) return render_template("steamkeys.html", keys=my_keys) app.register_blueprint(blueprint)
def load(app): # upgrade() app.db.create_all() CHALLENGE_CLASSES['lah'] = LahChallengeClass register_plugin_assets_directory(app, base_path='/plugins/lah_challenges/assets/') global APP_REF APP_REF = app scheduler.start() atexit.register(lambda: scheduler.shutdown()) app.register_blueprint(lah_print) register_user_page_menu_bar("Unlocking", "/unlock") register_plugin_script("/plugins/lah_challenges/assets/lah_challenge_injector.js")
def load(app): #https://github.com/blueimp/JavaScript-MD5/ #https://github.com/Caligatio/jsSHA #https://github.com/beatgammit/base64-js/ register_plugin_assets_directory(app, base_path='/plugins/CTFd-hasher/assets/') #abc - only works on modified server. #register_user_page_menu_bar(name='Hasher', route='/CTFd-hasher', target='_blank') register_user_page_menu_bar(name='Hasher', route='/CTFd-hasher') @app.route('/CTFd-hasher', methods=['GET']) def hash(): return render_template('page.html', content=""" <script src='/themes/original/static/js/vendor/jquery.min.js' type='text/javascript'></script> <script src='/plugins/CTFd-hasher/assets/md5.min.js' type='text/javascript'></script> <script src='/plugins/CTFd-hasher/assets/base64js.min.js' type='text/javascript'></script> <script src='/plugins/CTFd-hasher/assets/sha.js' type='text/javascript'></script> <h1>Hash a value</h1> <input id='valuetohash' style='width: 80%;'></input> <button id='hash'>go</button><br/><br/> <textarea id='output' style='width: 80%;'></textarea> <button id='copy' style='position:relative; top: -8px;'>copy</button> <script> $(function() { $('#hash').click( function() { var val = $('#valuetohash').val().trim(); //var hash = md5(val); var shaObj = new jsSHA('SHA-256', 'TEXT'); shaObj.update(val); var hash = shaObj.getHash('B64'); $('#output').html(hash); } ); $('#copy').click( function() { var $temp = $('<input>'); $('body').append($temp); $temp.val($('#output').text()).select(); document.execCommand('copy'); $temp.remove(); } ); }); </script> """) utils.hasher = hash
def load(app): dir_path = os.path.dirname(os.path.realpath(__file__)) db.create_all() register_plugin_assets_directory( app, base_path="/plugins/CTFd-pwn-college-plugin/assets/") CHALLENGE_CLASSES["docker"] = DockerChallenge FLAG_CLASSES["user"] = UserFlag ssh_key_template_path = os.path.join(dir_path, "assets", "ssh_key", "settings.html") override_template("settings.html", open(ssh_key_template_path).read()) app.view_functions["views.settings"] = ssh_key_settings Forms.keys = {"SSHKeyForm": SSHKeyForm} scoreboard_template_path = os.path.join(dir_path, "assets", "scoreboard", "scoreboard.html") override_template("scoreboard.html", open(scoreboard_template_path).read()) app.view_functions["scoreboard.listing"] = scoreboard_listing blueprint = Blueprint("pwncollege_api", __name__) api = Api(blueprint, version="v1", doc=current_app.config.get("SWAGGER_UI")) api.add_namespace(docker_namespace, "/docker") api.add_namespace(user_flag_namespace, "/user_flag") api.add_namespace(ssh_key_namespace, "/ssh_key") api.add_namespace(download_namespace, "/download") api.add_namespace(terminal_namespace, "/terminal") api.add_namespace(binary_ninja_namespace, "/binary_ninja") api.add_namespace(belts_namespace, "/belts") app.register_blueprint(blueprint, url_prefix="/pwncollege_api/v1") app.register_blueprint(download) app.register_blueprint(terminal) register_user_page_menu_bar("Terminal", "/terminal") app.register_blueprint(grades) register_user_page_menu_bar("Grades", "/grades") register_admin_plugin_menu_bar("Grades", "/grades/all")
def test_register_user_page_menu_bar(): """ Test that the register_user_page_menu_bar() properly inserts into HTML and get_user_page_menu_bar() returns the proper list. """ app = create_ctfd() with app.app_context(): register_user_page_menu_bar(title='test_user_menu_link', route='/test_user_href') with app.test_client() as client: r = client.get('/') output = r.get_data(as_text=True) assert '/test_user_href' in output assert 'test_user_menu_link' in output menu_item = get_user_page_menu_bar()[0] assert menu_item.title == 'test_user_menu_link' assert menu_item.route == '/test_user_href' destroy_ctfd(app)
def test_register_user_page_menu_bar(): """ Test that the register_user_page_menu_bar() properly inserts into HTML and get_user_page_menu_bar() returns the proper list. """ app = create_ctfd() with app.app_context(): register_user_page_menu_bar(title="test_user_menu_link", route="/test_user_href") with app.test_client() as client: r = client.get("/") output = r.get_data(as_text=True) assert "/test_user_href" in output assert "test_user_menu_link" in output with app.test_request_context(): menu_item = get_user_page_menu_bar()[0] assert menu_item.title == "test_user_menu_link" assert menu_item.route == "/test_user_href" destroy_ctfd(app)
def load(app): CTFd_API_v1.add_namespace(cases_namespace, '/acm_chall/cases') CTFd_API_v1.add_namespace(submissions_namespace, '/acm_chall/submissions') CTFd_API_v1.add_namespace(challenge_namespace, '/acm_chall/challenge') app.register_blueprint( views, url_prefix='/acm_chall' ) app.db.create_all() CHALLENGE_CLASSES["icpc_dynamic"] = DynICPCChallenge register_plugin_assets_directory( app, base_path="/plugins/ctfd-acm-challenges/assets/" ) register_admin_plugin_menu_bar( 'ACM Challenges', '/acm_chall/admin/judge_queue' ) register_user_page_menu_bar( 'ACM Status', '/acm_chall/judge_queue' ) def poll(): try: id, lang, callback = running.get(timeout=1) with app.app_context(): ExecutorBase.get_executor( id, lang, callback ).run() except Empty: pass except KeyboardInterrupt: pass scheduler = APScheduler() scheduler.init_app(app) scheduler.start() scheduler.add_job(id='acm-executor', func=poll, trigger="interval", seconds=10)
def load(app): app.db.create_all() announcements_blueprint = Blueprint('announcements_blueprint', __name__, template_folder='templates') register_user_page_menu_bar('Announcements', 'announcements') @announcements_blueprint.route('/admin/announcements', methods=['GET', 'POST']) @admins_only def view_admin_announcements(): msg = '' msg_type = '' if (request.form.get('action', '') == 'hide' or request.form.get( 'action', '') == 'show') and request.form.get('id', '') != '': action = request.form['action'] id = int(request.form['id']) announcements_obj = Announcements.query.get(id) if announcements_obj: if action == 'hide': announcements_obj.hidden = True elif action == 'show': announcements_obj.hidden = False db.session.commit() elif request.form.get( 'action', '') == 'delete' and request.form.get('id', '') != '': action = request.form['action'] id = int(request.form['id']) announcements_obj = Announcements.query.get(id) db.session.delete(announcements_obj) db.session.commit() msg = 'Message deleted.' msg_type = 'info' elif request.form.get('action', '') == 'add' and request.form.get( 'headline', '') != '' and request.form.get('body', '') != '': if request.form.get('hidden', '') == 'on': hidden = True else: hidden = False announcements_obj = Announcements( headline=request.form['headline'], hidden=hidden, body=request.form['body'], date=datetime.datetime.now()) db.session.add(announcements_obj) db.session.commit() # send e-mail if request.form.get('emailnotification', '') == 'on': # get team emails teams = Teams.query.filter_by() body = request.form['headline'] + "\n\n" + request.form['body'] # send mails to all teams if utils.can_send_mail(): for team in teams: utils.sendmail(team.email, body) msg += 'E-Mails sent.\n' else: msg += 'Can\'t send e-mails. Please check your configuration.\n' msg += 'Message added.' msg_type = 'info' elif request.form.get('action', '') == 'update' and request.form.get( 'headline', '') != '' and request.form.get( 'body', '') != '' and request.form.get('id', '') != '': if request.form.get('hidden', '') == 'on': hidden = True else: hidden = False if request.form.get('updateDate', '') == 'on': update_date = True else: update_date = False id = int(request.form['id']) announcements_obj = Announcements.query.get(id) if announcements_obj: announcements_obj.headline = request.form['headline'] announcements_obj.hidden = hidden announcements_obj.body = request.form['body'] if update_date: announcements_obj.date = datetime.datetime.now() db.session.commit() msg = 'Message updated.' msg_type = 'info' announcements_res = Announcements.query.order_by( Announcements.date.desc()).all() return render_template('admin_announcements.html', announcements_res=announcements_res, msg=msg, msg_type=msg_type) @announcements_blueprint.route('/admin/announcements/edit', methods=['POST']) @admins_only def view_admin_announcements_edit(): if request.form.get('id', '') != '': id = int(request.form['id']) announcements_obj = Announcements.query.get(id) if announcements_obj: return render_template('admin_announcements_edit.html', announcements=announcements_obj) return redirect(url_for('admin/announcements')) @announcements_blueprint.route('/announcements', methods=['GET', 'POST']) def view_announcements(): announcements_res = Announcements.query.order_by( Announcements.date.desc()).all() # check if there are any announcements (maybe all hidden) no_announcements = True for msg in announcements_res: if msg.hidden == False: no_announcements = False break return render_template('announcements.html', announcements_res=announcements_res, no_announcements=no_announcements) app.register_blueprint(announcements_blueprint)
def load(app): # Create new locking_challenge table if necessary app.db.create_all() app.register_blueprint(support_ticket_templates) app.register_blueprint(support_ticket_static, url_prefix='/support-ticket') register_user_page_menu_bar('Support Ticket', 'support-ticket') # register_plugin_assets_directory(app, base_path="/plugins/CTFd_Support_Ticket/static/") if not os.path.exists(app.config['UPLOAD_FOLDER'] + '/support_ticket'): os.mkdir(app.config['UPLOAD_FOLDER'] + '/support_ticket') ticket_upload = (app.config['UPLOAD_FOLDER'] + '/support_ticket/') def get_challenges_by_categories(): user = get_current_user() challenges = (Challenges.query.filter( and_(Challenges.state != "hidden", Challenges.state != "locked")).order_by( Challenges.value).all()) if user: solve_ids = (Solves.query.with_entities( Solves.challenge_id).filter_by( account_id=user.account_id).order_by( Solves.challenge_id.asc()).all()) solve_ids = set([value for value, in solve_ids]) # TODO: Convert this into a re-useable decorator if is_admin(): pass else: if config.is_teams_mode() and get_current_team() is None: abort(403) else: solve_ids = set() response = [] for challenge in challenges: if challenge.requirements: requirements = challenge.requirements.get("prerequisites", []) anonymize = challenge.requirements.get("anonymize") prereqs = set(requirements) if solve_ids >= prereqs: pass else: if anonymize: response.append({ "id": challenge.id, "name": "???", "category": "???" }) # Fallthrough to continue continue response.append({ "id": challenge.id, "name": challenge.name, "category": challenge.category }) # Sort into categories categories = set(map(lambda x: x['category'], response)) cats = [] for c in categories: cats.append({ 'name': c, 'challenges': [j for j in response if j['category'] == c] }) db.session.close() return cats def get_ticket_for_user(): user = get_current_user() tickets = (SupportTickets.query.filter( and_(SupportTickets.user_id == user.account_id)).order_by( SupportTickets.state)) ticket_list = [] for ticket in tickets: ticket_list.append({ 'id': ticket.id, 'challenge_cat': ticket.challenge_cat, 'challenge_name': ticket.challenge_name, 'state': ticket.state }) return ticket_list def get_ticket_for_admin(): tickets = SupportTickets.query.all() ticket_list = [] for ticket in tickets: ticket_list.append({ 'id': ticket.id, 'challenge_cat': ticket.challenge_cat, 'challenge_name': ticket.challenge_name, 'creator': ticket.user, 'state': ticket.state }) return ticket_list def get_user_access(user): users = Users.query.all() admin_users = [] user_users = [] for u in users: if u.type == "admin": admin_users.append(u.name) elif u.type == "user": user_users.append(u.name) if user in admin_users: user = user + " (Admin)" return user elif user in user_users: user = user + " (User)" return user def upload_file(ticket_id, message_id, user, files): if not os.path.exists(ticket_upload + str(ticket_id)): os.mkdir(ticket_upload + str(ticket_id)) time = datetime.now().time().strftime("%H:%M") for file in files: filename_temp = filename = secure_filename(file.filename) '''if os.path.exists(ticket_upload + str(ticket_id) + '/' + filename_temp): data = { "user_id": user.id, "title": "Upload Failed", "content": "The file that you just uploaded already exist please change the name and try again." } send_notification(data=data, type="alert") return''' exist = True place = 0 while exist: if os.path.exists(ticket_upload + str(ticket_id) + '/' + filename_temp): place += 1 temp = filename.split('.') filename_temp = '{name}({place}).{ext}'.format( name=temp[0], place=place, ext=temp[1]) else: filename = filename_temp exist = False file.save(ticket_upload + str(ticket_id) + '/' + filename) size = os.stat( (ticket_upload + str(ticket_id) + '/' + filename)).st_size uploaded_file = SupportTicketFiles( ticket_id=ticket_id, message_id=message_id, sender=user.name, time_sent=time, path=(ticket_upload + str(ticket_id) + '/' + filename), filename=filename, size=size) db.session.add(uploaded_file) db.session.commit() def send_notification(data, type, sound=True): data["sound"] = sound data["type"] = type schema = NotificationSchema() result = schema.load(data) if result.errors: return {"success": False, "errors": result.errors}, 400 db.session.add(result.data) db.session.commit() response = schema.dump(result.data) response.data["type"] = type response.data["sound"] = sound print(response.data) current_app.events_manager.publish(data=response.data, type="notification") print("Success") @app.route('/support-ticket', methods=['GET', 'POST']) @during_ctf_time_only @require_verified_emails @check_challenge_visibility @require_team def user_tickets(): if is_admin(): return render_template('support_ticket_page.html', ticket_list=get_ticket_for_admin(), access="Admin") else: return render_template('support_ticket_page.html', ticket_list=get_ticket_for_user(), access="User") @app.route('/support-ticket/new', methods=['GET', 'POST']) def new_ticket(): if request.method == 'POST': user = get_current_user() category = request.form['category'] challenge = request.form['challenge'] issue = request.form['issue'] files = request.files.getlist('file') ticket = SupportTickets(user=user.name, user_id=user.account_id, challenge_cat=category, challenge_name=challenge, description=issue) db.session.add(ticket) db.session.commit() time = datetime.now().time().strftime("%H:%M") initial_message = SupportTicketConversation(ticket_id=ticket.id, sender=user.name, time_sent=time, message=issue) db.session.add(initial_message) db.session.commit() if files[0]: files = request.files.getlist('file') upload_file(ticket.id, initial_message.id, user, files) return redirect('/support-ticket') ticket = SupportTickets.query.all() ids = [] for t in ticket: ids.append(t.id) ticket_id = 1 for i in range(1, len(ids)): if i not in ids: ticket_id = i break return render_template( 'support_ticket_new_page.html', challenge_categories=get_challenges_by_categories(), ticket_id=ticket_id) @app.route('/support-ticket/view/<int:ticket_id>', methods=['GET', 'POST']) def view_ticket(ticket_id): if request.method == 'POST': ticket = SupportTickets.query.filter_by(id=ticket_id) message = request.form['message'] time = datetime.now().time().strftime("%H:%M") user = get_current_user() files = request.files.getlist('file') for t in ticket: if request.form['ticket-state'] != t.state: data = { "user_id": ticket[0].user_id, "title": "Ticket Status Change", "content": "The admins have changed your tickets status to {0}.". format(request.form['ticket-state']) if user.type == "admin" else "A ticket has been changed to {0} by the user.".format( request.form['ticket-state']) } send_notification(data=data, type="alert") t.state = request.form['ticket-state'] db.session.commit() if message.replace(' ', '').replace('\n', '') != "" or files[0]: ticket_message = SupportTicketConversation(ticket_id=ticket_id, sender=user.name, time_sent=time, message=message) db.session.add(ticket_message) db.session.commit() if user.type == "admin": data = { "user_id": ticket[0].user_id, "title": "New Ticket Message", "content": "You have a new message from the admins in one of your tickets." } send_notification(data=data, type="alert") if files[0]: files = request.files.getlist('file') upload_file(ticket_id, ticket_message.id, user, files) return redirect(url_for("view_ticket", ticket_id=ticket_id)) ticket = SupportTickets.query.filter_by(id=ticket_id).first_or_404() ticket_message = SupportTicketConversation.query.filter_by( ticket_id=ticket_id) ticket_info = {} ticket_conversation = [] ticket_info.update({ "category": ticket.challenge_cat, "challenge": ticket.challenge_name, "description": ticket.description, "state": ticket.state }) for message_info in ticket_message: message_files = SupportTicketFiles.query.filter_by( message_id=message_info.id).all() file_list = [] for file in message_files: file_list.append({file.id: file.filename}) if message_info.message != '' or len(file_list) > 0: ticket_conversation.append({ "id": message_info.id, "sender": get_user_access(message_info.sender), "time": message_info.time_sent, "message": message_info.message, "files": file_list }) if is_admin(): return render_template('support_ticket_view_page.html', ticket_info=ticket_info, ticket_conversation=ticket_conversation, ticket=ticket_id, access="Admin") else: return render_template('support_ticket_view_page.html', ticket_info=ticket_info, ticket_conversation=ticket_conversation, ticket=ticket_id, access="User") @app.route('/support-ticket/download-file/<int:file_id>/<string:filename>') def download_file(file_id, filename): file = SupportTicketFiles.query.filter( and_(SupportTicketFiles.id == file_id)).first_or_404() return send_file(file.path, attachment_filename=file.filename) @app.route('/support-ticket/delete-file/<int:file_id>') def delete_file(file_id): file = SupportTicketFiles.query.filter_by(id=file_id) ticket_id = file[0].ticket_id if os.path.exists(file[0].path): os.remove(file[0].path) file.delete() db.session.commit() return redirect(url_for("ticket_management", ticket_id=ticket_id)) @app.route('/admin/plugins/support-ticket', methods=['GET']) @admins_only def admin_ticket_management(): return render_template('support_ticket_admin_view.html', ticket_list=get_ticket_for_admin()) @app.route('/admin/plugins/support-ticket/view/<int:ticket_id>') @admins_only def ticket_management(ticket_id): ticket = SupportTickets.query.filter_by(id=ticket_id).first_or_404() ticket_info = {} ticket_info.update({ "id": ticket_id, "creator": ticket.user, "category": ticket.challenge_cat, "challenge": ticket.challenge_name, "description": ticket.description, "state": ticket.state }) file_info = SupportTicketFiles.query.filter_by(ticket_id=ticket_id) file_list = [] for file in file_info: if int(file.size) >= 1000000: size = str(int(file.size) / 1000000) + 'MB' elif int(file.size) >= 1000: size = str(int(file.size) / 1000) + 'KB' else: size = str(file.size) + 'B' file_list.append({ "id": file.id, "filename": file.filename, "size": size }) print(file_list) return render_template('support_ticket_admin_edit.html', ticket_info=ticket_info, file_list=file_list) @app.route('/admin/plugins/support-ticket/delete/<int:ticket_id>', methods=['GET']) @admins_only def delete_ticket(ticket_id): files = SupportTicketFiles.query.filter_by(ticket_id=ticket_id).all() for file in files: delete_file(file.id) SupportTicketConversation.query.filter_by(ticket_id=ticket_id).delete() db.session.commit() SupportTickets.query.filter_by(id=ticket_id).delete() db.session.commit() return redirect(url_for("admin_ticket_management"))