def test_register_plugin_asset(): """Test that plugin asset registration works""" app = create_ctfd(setup=False) register_plugin_asset(app, asset_path='/plugins/__init__.py') app = setup_ctfd(app) with app.app_context(): with app.test_client() as client: r = client.get('/plugins/__init__.py') assert len(r.get_data(as_text=True)) > 0 assert r.status_code == 200 destroy_ctfd(app)
def load(app): app.db.create_all() classification = Blueprint('classification', __name__, template_folder='./') dir_path = os.path.dirname(os.path.realpath(__file__)) template_path = os.path.join(dir_path, 'scoreboard.html') override_template('scoreboard.html', open(template_path).read()) register_plugin_asset(app, asset_path='/plugins/classification/config.js') # Server side Configuration menu @classification.route('/admin/plugins/classification/', methods=['GET', 'POST']) @utils.admins_only def classified(): if request.method == 'POST': teamid = request.form['id'] previous = Classification.query.filter_by(id=teamid) for x in previous: db.session.delete(x) errors = [] classification = request.form['classification'] if classification == 'other': classification = request.form['new_classification'] classify = Classification(int(teamid), classification) db.session.add(classify) db.session.commit() db.session.close() if request.method == 'GET' or request.method == 'POST': classifications = Classification.query.all() teams = [] scoring_teams = [] standings = get_standings() # Competitors with a score for i, x in enumerate(standings): pushed = 0 for classification in classifications: if classification.teamid == x.teamid: teams.append({ 'id': x.teamid, 'name': x.name, 'class': classification.classification, 'score': x.score }) pushed = 1 break scoring_teams.append(x.teamid) if (pushed == 0): teams.append({ 'id': x.teamid, 'name': x.name, 'class': '', 'score': x.score }) # Competitors with/without a score (limited to only without a score) for team in db.session.query(Teams.name, Teams.id, Teams.admin).all(): if (team.admin == False): pushed = 0 for classification in classifications: if classification.teamid == team.id: if (team.id not in scoring_teams): teams.append({ 'id': team.id, 'name': team.name, 'class': classification.classification, 'score': '' }) pushed = 1 if (pushed == 0 and (team.id not in scoring_teams)): teams.append({ 'id': team.id, 'name': team.name, 'class': '', 'score': '' }) classf = [] for clas in classifications: classf.append(clas.classification) classf = list(sorted(set(classf))) # -=- For TAMUctf, but can be left in without any problems -=- try: tamu_test() tamu = ["tamu"] except: tamu = [] # -=- db.session.close() return render_template('config.html', teams=teams, classifications=classf, tamu=tamu) def get_standings(admin=False, count=None, classification=None): scores = db.session.query( Solves.teamid.label('teamid'), db.func.sum(Challenges.value).label('score'), db.func.max(Solves.date).label('date')).join(Challenges).group_by( Solves.teamid) awards = db.session.query( Awards.teamid.label('teamid'), db.func.sum(Awards.value).label('score'), db.func.max(Awards.date).label('date')).group_by(Awards.teamid) freeze = utils.get_config('freeze') if not admin and freeze: scores = scores.filter( Solves.date < utils.unix_time_to_utc(freeze)) awards = awards.filter( Awards.date < utils.unix_time_to_utc(freeze)) results = union_all(scores, awards).alias('results') sumscores = db.session.query( results.columns.teamid, db.func.sum(results.columns.score).label('score'), db.func.max(results.columns.date).label('date')).group_by( results.columns.teamid).subquery() if admin: standings_query = db.session.query( Teams.id.label('teamid'), Teams.name.label('name'), Teams.banned, sumscores.columns.score, Classification.classification )\ .join(sumscores, Teams.id == sumscores.columns.teamid) \ .join(Classification, Teams.id == Classification.id) \ .order_by(sumscores.columns.score.desc(), sumscores.columns.date) else: standings_query = db.session.query( Teams.id.label('teamid'), Teams.name.label('name'), sumscores.columns.score, Classification.classification )\ .join(sumscores, Teams.id == sumscores.columns.teamid) \ .join(Classification, Teams.id == Classification.id) \ .filter(Teams.banned == False) \ .order_by(sumscores.columns.score.desc(), sumscores.columns.date) if classification and count: # -=- For TAMUctf, but can be left in without any problems -=- try: tamu_test() c = Classification if (classification == "tamu"): standings = standings_query.filter( or_(c.classification == "U0", c.classification == "U1", c.classification == "U2", c.classification == "U3", c.classification == "U4", c.classification == "U5", c.classification == "G5", c.classification == "G6", c.classification == "G7", c.classification == "G8", c.classification == "G9")).limit(count).all() elif (classification == "tamug"): standings = standings_query.filter( or_(c.classification == "G5", c.classification == "G6", c.classification == "G7", c.classification == "G8", c.classification == "G9")).limit(count).all() elif (classification == "tamuu"): standings = standings_query.filter( or_(c.classification == "U0", c.classification == "U1", c.classification == "U2", c.classification == "U3", c.classification == "U4", c.classification == "U5")).limit(count).all() elif (classification == "U4"): standings = standings_query.filter( or_(c.classification == "U4", c.classification == "U5")).limit(count).all() elif (classification == "tamum"): standings = standings_query.filter( or_(c.other == 3, c.other == 5, c.other == 7, c.other == 8, c.other == 12, c.other == 10, c.other == 15)).limit(count).all() elif (classification == "tamumc"): standings = standings_query.filter( or_(c.other == 3, c.other == 8, c.other == 10, c.other == 15)).limit(count).all() elif (classification == "tamumr"): standings = standings_query.filter( or_(c.other == 5, c.other == 8, c.other == 12, c.other == 15)).limit(count).all() elif (classification == "tamumd"): standings = standings_query.filter( or_(c.other == 7, c.other == 12, c.other == 10, c.other == 15)).limit(count).all() else: standings = standings_query.filter( Classification.classification == classification).limit( count).all() except: standings = standings_query.filter( Classification.classification == classification).limit( count).all() #-=- elif classification: # -=- For TAMUctf, but can be left in without any problems -=- try: tamu_test() c = Classification if (classification == "tamu"): standings = standings_query.filter( or_(c.classification == "U0", c.classification == "U1", c.classification == "U2", c.classification == "U3", c.classification == "U4", c.classification == "U5", c.classification == "G5", c.classification == "G6", c.classification == "G7", c.classification == "G8", c.classification == "G9")).all() elif (classification == "tamug"): standings = standings_query.filter( or_(c.classification == "G5", c.classification == "G6", c.classification == "G7", c.classification == "G8", c.classification == "G9")).all() elif (classification == "tamuu"): standings = standings_query.filter( or_(c.classification == "U01", c.classification == "U1", c.classification == "U2", c.classification == "U3", c.classification == "U4", c.classification == "U5")).all() elif (classification == "tamuu"): standings = standings_query.filter( or_(c.classification == "U4", c.classification == "U5")).all() elif (classification == "tamum"): standings = standings_query.filter( or_(c.other == 3, c.other == 5, c.other == 7, c.other == 8, c.other == 12, c.other == 10, c.other == 15)).all() elif (classification == "tamumc"): standings = standings_query.filter( or_(c.other == 3, c.other == 8, c.other == 10, c.other == 15)).all() elif (classification == "tamumr"): standings = standings_query.filter( or_(c.other == 5, c.other == 8, c.other == 12, c.other == 15)).all() elif (classification == "tamumd"): standings = standings_query.filter( or_(c.other == 7, c.other == 12, c.other == 10, c.other == 15)).all() else: standings = standings_query.filter( Classification.classification == classification).all() except: standings = standings_query.filter( Classification.classification == classification).all() #-=- elif count: standings = standings_query.limit(count).all() else: standings = standings_query.all() return standings def scoreboard_view(): classifications = [] for classification in db.session.query( Classification.classification).distinct(): classifications.append(classification[0]) db.session.close() classifications = sorted(classifications, reverse=True) # -=- For TAMUctf, but can be left in without any problems -=- try: tamu_test() tamu = ["tamu"] except: tamu = [] #-=- try: current_user_class = Classification.query.filter_by( id=session.get('id')).first().classification except: current_user_class = "ALL" try: current_user_other = Classification.query.filter_by( id=session.get('id')).first().other except: current_user_other = 0 if utils.get_config( 'view_scoreboard_if_authed') and not utils.authed(): return redirect(url_for('auth.login', next=request.path)) if utils.hide_scores(): return render_template('scoreboard.html', errors=['Scores are currently hidden']) standings = get_standings() return render_template('scoreboard.html', teams=standings, score_frozen=utils.is_scoreboard_frozen(), classifications=classifications, tamu=tamu, current_user_class=current_user_class, current_user_other=current_user_other) def scores(): json = {'standings': []} if utils.get_config( 'view_scoreboard_if_authed') and not utils.authed(): return redirect(url_for('auth.login', next=request.path)) if utils.hide_scores(): return jsonify(json) standings = get_standings() for i, x in enumerate(standings): json['standings'].append({ 'pos': i + 1, 'id': x.teamid, 'team': x.name, 'score': int(x.score) }) return jsonify(json) @app.route('/scores/<classification>') def classified_scores(classification): json = {'standings': []} if utils.get_config( 'view_scoreboard_if_authed') and not utils.authed(): return redirect(url_for('auth.login', next=request.path)) if utils.hide_scores(): return jsonify(json) standings = get_standings(classification=classification) for i, x in enumerate(standings): json['standings'].append({ 'pos': i + 1, 'id': x.teamid, 'team': x.name, 'score': int(x.score) }) return jsonify(json) @app.route('/top/<int:count>/<classification>') def classified_topteams(count, classification): json = {'places': {}} if utils.get_config( 'view_scoreboard_if_authed') and not utils.authed(): return redirect(url_for('auth.login', next=request.path)) if utils.hide_scores(): return jsonify(json) if count > 20 or count < 0: count = 10 standings = get_standings(count=count, classification=classification) team_ids = [team.teamid for team in standings] solves = Solves.query.filter(Solves.teamid.in_(team_ids)) awards = Awards.query.filter(Awards.teamid.in_(team_ids)) freeze = utils.get_config('freeze') if freeze: solves = solves.filter( Solves.date < utils.unix_time_to_utc(freeze)) awards = awards.filter( Awards.date < utils.unix_time_to_utc(freeze)) solves = solves.all() awards = awards.all() for i, team in enumerate(team_ids): json['places'][i + 1] = { 'id': standings[i].teamid, 'name': standings[i].name, 'solves': [] } for solve in solves: if solve.teamid == team: json['places'][i + 1]['solves'].append({ 'chal': solve.chalid, 'team': solve.teamid, 'value': solve.chal.value, 'time': utils.unix_time(solve.date) }) for award in awards: if award.teamid == team: json['places'][i + 1]['solves'].append({ 'chal': None, 'team': award.teamid, 'value': award.value, 'time': utils.unix_time(award.date) }) json['places'][i + 1]['solves'] = sorted( json['places'][i + 1]['solves'], key=lambda k: k['time']) return jsonify(json) app.view_functions['scoreboard.scoreboard_view'] = scoreboard_view app.view_functions['scoreboard.scores'] = scores app.register_blueprint(classification)
def load(app): app.db.create_all() discoveryList = Blueprint('discoveryList', __name__) register_plugin_asset(app, asset_path='/plugins/discovery/config.js') @discoveryList.route('/admin/discoveryList/<int:chalid>', methods=['GET', 'POST']) @admins_only def admin_discoveryList(chalid): if request.method == 'GET': if chalid == 0: service = DiscoveryList.query.filter_by(chal=chalid) json_data = {'service': [], 'auto': []} for x in service: if x.discovery == "OFF" or x.discovery == "ON": json_data['service'].append(x.discovery) else: json_data['auto'].append(x.discovery) return jsonify(json_data) discoveryList = DiscoveryList.query.filter_by(chal=chalid).all() json_data = {'discoveryList': []} for x in discoveryList: json_data['discoveryList'].append({'id': x.id, 'chal': x.chal, 'discovery': x.discovery}) return jsonify(json_data) elif request.method == 'POST': if chalid == 0: services = DiscoveryList.query.filter_by(chal=0) previous = DiscoveryList.query.filter_by(chal=chalid) json_data = {'service': [], 'auto': []} for x in previous: if x.discovery == "OFF" or x.discovery == "ON": json_data['service'].append(x.discovery) else: json_data['auto'].append(x.discovery) for x in services: db.session.delete(x) db.session.commit() service = request.form.getlist('service[]') autoDiscovery = request.form.getlist('auto[]') for x in service: discovery = DiscoveryList(chalid, x) db.session.add(discovery) for y in json_data['auto']: discovery = DiscoveryList(chalid, y) db.session.add(discovery) for x in autoDiscovery: discovery = DiscoveryList(chalid, x) db.session.add(discovery) for x in json_data['service']: discovery = DiscoveryList(chalid, x) db.session.add(discovery) db.session.commit() db.session.close() return '1' newdiscoveryList = request.form.getlist('discoveryList[]') discoveryList = DiscoveryList.query.filter_by(chal=chalid).all() for x in newdiscoveryList: skip=0 for y in discoveryList: if x == y.discovery: skip = 1; if skip == 0: discovery = DiscoveryList(chalid, x) db.session.add(discovery) db.session.commit() db.session.close() return '1' @discoveryList.route('/admin/discoveryList/<string:auto>', methods=['GET', 'POST']) @admins_only def admin_AutoDiscovery(auto): if request.method == 'GET': json_data = {'Challenge': [], 'Dependent Challenges': [[]]} if auto == "basic": #Simple Auto Discovery #Challenges appear after the previous challenge in category was solved chals = Challenges.query.filter(or_(Challenges.hidden != True, Challenges.hidden == None)).order_by(Challenges.value).all() for x in chals: json_data['Challenge'].append(x.id) chals_cat = [chal for chal in chals if (chal != x and chal.value <= x.value and chal.category == x.category)] if len(chals_cat) > 0: chals_cat = chals_cat[-1].id json_data['Dependent Challenges'].append(chals_cat) elif auto == "auto": #Broader Auto Discovery (Challenges become visible more easily) chals = Challenges.query.filter(or_(Challenges.hidden != True, Challenges.hidden == None)).order_by(Challenges.value).all() for x in chals: starter = [chal for chal in chals if (chal != x and chal.value < x.value and chal.category == x.category)] current_challenges = [[]] if len(starter) > 0: # First Challenge in Category - Visible by default second_last_elem=[] json_data['Challenge'].append(x.id) chals_cat = [chal for chal in chals if (chal != x and chal.value <= x.value and chal.category == x.category)] if len(chals_cat) > 0: current_challenges.append(chals_cat[-1].id) if len(chals_cat) > 1: print(chals_cat[-2]) print(chals_cat[-2].id) second_last_elem = chals_cat[-2].id chals_not_cat = [chal for chal in chals if (chal != x and chal.value > x.value and chal.category != x.category)] categories = [] for y in chals_not_cat: if y.category not in categories: categories.append(y.category) current_cat = [chal for chal in chals_not_cat if (chal.value >= y.value and chal.category == y.category)] for z in current_cat: print("Challenge:" + x.name + "2nd" + str(second_last_elem) + " : " + str(z.id)) current_challenges.append((second_last_elem,z.id)) json_data['Dependent Challenges'].append(current_challenges) elif auto == "preview": hidden = DiscoveryList.query.filter_by(chal="preview") json_data = {'hidden': [], 'solved':[]} for x in hidden: json_data['hidden'].append(x.discovery) solved = DiscoveryList.query.filter_by(chal="solved") for x in solved: json_data['solved'].append(x.discovery) return jsonify(json_data) else: return "This method is not allowed" return jsonify(json_data) if request.method == 'POST': if auto == "delete": discovery = DiscoveryList.query.filter(id != 0).all() print discovery for x in discovery: db.session.delete(x) db.session.commit() db.session.close() return '1' if auto == "preview": previous = DiscoveryList.query.filter_by(chal="preview") for x in previous: db.session.delete(x) previous = DiscoveryList.query.filter_by(chal="solved") for x in previous: db.session.delete(x) db.session.commit() solved = request.form.getlist('solved[]') for y in solved: discovery = DiscoveryList('solved', y) db.session.add(discovery) db.session.commit() visible = [] hidden = [] if len(solved) > 0: solved = solved[0].split("&") allDiscovery = DiscoveryList.query.filter(id != 0).all() for x in allDiscovery: if x.chal != 0: #print('x.chal: ' + str(x.chal) + 'solved: ' + str(solved)) if str(x.chal) in solved: visible.append(x.chal) else: discovery = filter(None, (' '.join(y.split("&")).split() for y in x.discovery)) discovery = [item for sublist in discovery for item in sublist] #print discovery current_visible=1 #print("Challenge: " + str(x.chal) +" Set:") for y in discovery: if y[0] not in solved: current_visible=0 break; if(current_visible==1): visible.append(x.chal) else: hidden.append(x.chal) else: allDiscovery = DiscoveryList.query.filter(id != 0).all() for x in allDiscovery: if x.chal != 0: discovery = filter(None, (' '.join(y.split("&")).split() for y in x.discovery)) discovery = [item for sublist in discovery for item in sublist] if(len(discovery)>0): hidden.append(x.chal) else: visible.append(x.chal) hidden = [x for x in hidden if x not in visible] #print('visible: '+str(visible)) #print('hidden: '+str(hidden)) json_data = {'visible': visible, 'hidden': hidden} for y in hidden: discovery = DiscoveryList('preview', y) db.session.add(discovery) db.session.commit() db.session.close() return '1' @discoveryList.route('/admin/discoveryList/<int:discoveryid>/delete', methods=['POST', 'DELETE']) @admins_only def admin_delete_discoveryList(discoveryid): if request.method == 'POST' or request.method == 'DELETE': discovery = DiscoveryList.query.filter_by(id=discoveryid) for x in discovery: db.session.delete(x) db.session.commit() db.session.close() return '1' #@admin.route('/admin/chal/delete', methods=['POST']) #@admins_only #def admin_delete_chal(): # challenge = Challenges.query.filter_by(id=request.form['id']).first_or_404() # WrongKeys.query.filter_by(chalid=challenge.id).delete() # Solves.query.filter_by(chalid=challenge.id).delete() #Keys.query.filter_by(chal=challenge.id).delete() #files = Files.query.filter_by(chal=challenge.id).all() #for f in files: # utils.delete_file(f.id) #Files.query.filter_by(chal=challenge.id).delete() #Tags.query.filter_by(chal=challenge.id).delete() #DiscoveryList.query.filter_by(chal=challenge.id).delete() #Challenges.query.filter_by(id=challenge.id).delete() #db.session.commit() #db.session.close() #return '1' @challenges.route('/chals', methods=['GET']) def chals(): if not utils.is_admin(): if not utils.ctftime(): if utils.view_after_ctf(): pass else: abort(403) if utils.user_can_view_challenges() and (utils.ctf_started() or utils.is_admin()): chals = Challenges.query.filter(or_(Challenges.hidden != True, Challenges.hidden == None)).order_by(Challenges.value).all() # Only one line in chals() needed to add for Challenge Discovery # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- chals = discovery(chals) if len(chals)!=0 else chals # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- json = {'game': []} for x in chals: tags = [tag.tag for tag in Tags.query.add_columns('tag').filter_by(chal=x.id).all()] files = [str(f.location) for f in Files.query.filter_by(chal=x.id).all()] unlocked_hints = [] if utils.authed(): unlocked_hints = set([u.itemid for u in Unlocks.query.filter_by(model='hints', teamid=session['id'])]) hints = [] for hint in Hints.query.filter_by(chal=x.id).all(): if hint.id in unlocked_hints or utils.ctf_ended(): hints.append({'id': hint.id, 'cost': hint.cost, 'hint': hint.hint}) else: hints.append({'id': hint.id, 'cost': hint.cost}) chal_type = get_chal_class(x.type) json['game'].append({ 'id': x.id, 'type': chal_type.name, 'name': x.name, 'value': x.value, 'description': x.description, 'category': x.category, 'files': files, 'tags': tags, 'hints': hints, 'template': chal_type.templates['modal'], 'script': chal_type.scripts['modal'], }) db.session.close() return jsonify(json) else: db.session.close() abort(403) def discovery(chals): #print("Testing") #print(chals) #if is_admin(): # print("In Admin") # return chals for x in DiscoveryList.query.filter_by(chal=0): if (x.discovery == "OFF"): return chals discovered = [] for x in chals: show, and_list = 0, [] #print("Challenge #" + str(x.id) + " - Needed problems solved to be seen:") for y in DiscoveryList.query.add_columns('id', 'discovery', 'chal').all(): # For each OR set if (str(y.chal) == str(x.id) and show != 1): and_list = map(int, (y.discovery).split('&')) #print("NEEDED: " + str(and_list)) for need_solved in and_list: # For each AND elem show = 2 if utils.authed(): for z in Solves.query.add_columns('chalid').filter_by(teamid=session['id']).all(): if need_solved == z.chalid: show = 1 # Chal is solved and is needed #print("Challenge ID: " + str(need_solved) + " has been solved & is needed") break if (show == 2): #Challenge is not solved and is needed and_list=[] # Mark wrong break if ((len(and_list)==0 and show == 0) or show==1): #print("Shown, because of:" + str(and_list) + " show:" + str(show) +'\n') discovered.append(x) #else: # print("HIDDEN, solved:" + str(and_list) + " show:" + str(show) +'\n') print(chals) return discovered app.view_functions['challenges.chals'] = chals #app.view_functions['admin.admin_delete_chal'] = admin_delete_chal app.view_functions['admin.admin_delete_discoveryList'] = admin_delete_discoveryList app.view_functions['challenges.discovery'] = discovery app.register_blueprint(discoveryList)