def config_variables(self, client): config = {} config['scores_hide_others'] = config_get_bool("server", "scores_hide_others", False) config['scores_progress_overall'] = config_get_bool( "server", "scores_progress_overall", False) config['scores_read_only'] = config_get_bool("server", "scores_read_only", False) config['scores_writeups'] = config_get_bool("server", "scores_writeups", False) config['teams_setdetails'] = config_get_bool("server", "teams_setdetails", False) return config
def scores_scoreboard(self, client): """ Returns the scoreboard """ db_store = client['db_store'] hide_others = config_get_bool("server", "scores_hide_others", False) teams = {} for team in db_store.find(DBTeam): # Skip teams without a name (likely unconfigured) if not team.name: continue if team.id == 0 and client.get("team", None) != 0: continue teams[team.id] = {'teamid': team.id, 'team_name': (team.name if team.name else ""), 'team_country': (team.country if team.country else ""), 'team_website': (team.website if team.website else ""), 'score': 0, 'score_flags': 0, 'score_writeups': 0} # The public scoreboard only shows 0 when hide_others is set if hide_others and 'team' not in client: return sorted(teams.values(), key=lambda team: team['teamid']) for score in db_store.find(DBScore): # Skip score entries without a matching team if not score.teamid in teams: continue # Skip teams other than the requestor when hide_others is set if hide_others and score.teamid != client['team'] \ and client['team'] != 0: continue if score.value: teams[score.teamid]['score'] += score.value teams[score.teamid]['score_flags'] += score.value if (config_get_bool("server", "scores_writeups", False) and score.writeup_value): teams[score.teamid]['score'] += score.writeup_value teams[score.teamid]['score_writeups'] += score.writeup_value return sorted(teams.values(), key=lambda team: team['score'], reverse=True)
def scores_timeline(self, client): """ Returns the timeline """ db_store = client['db_store'] hide_others = config_get_bool("server", "scores_hide_others", False) result = [] # Guests don't get to see anything when hide_others is set if hide_others and "team" not in client: return result for score in db_store.find(DBScore).order_by(DBScore.submit_time): if not score.team.name: continue if score.team.id == 0 and client.get("team", None) != 0: continue # Skip teams other than the requestor when hide_others is set if hide_others and score.teamid != client['team'] \ and client['team'] != 0: continue result.append({'teamid': score.teamid, 'submit_time': score.submit_time, 'value': score.value}) return sorted(result, key=itemgetter('teamid', 'submit_time'))
def scores_list_submitted(self, client): """ Lists all the flags the team found and any related hints """ db_store = client['db_store'] results = [] for entry in db_store.find(DBScore, teamid=client['team']): result = {} result['flagid'] = entry.flagid result['description'] = (entry.flag.description if entry.flag.description else "") result['value'] = entry.value result['submit_time'] = entry.submit_time if config_get_bool("server", "scores_writeups", False): result['writeup_value'] = entry.writeup_value else: result['writeup_value'] = 0 result['writeup_submit_time'] = entry.writeup_time if entry.flag.writeup_value: result['writeup_string'] = "WID%s" % entry.id else: result['writeup_string'] = "" result['return_string'] = (entry.flag.return_string if entry.flag.return_string else "") results.append(result) return sorted(results, key=lambda result: result['flagid'])
def teams_setdetails(self, client, fields): """ Set the details for the caller's team """ if not config_get_bool("server", "teams_setdetails", False): raise AskgodException("Setting team details isn't allowed.") db_store = client['db_store'] convert_properties(fields) validate_properties(DBTeam, fields) results = db_store.find(DBTeam, id=client['team']) if results.count() != 1: raise AskgodException("Can't find a match for id=%s" % client['team']) dbentry = results[0] if set(fields.keys()) - set(['name', 'country', 'website']): raise AskgodException("Invalid field provided.") if "country" in fields: if len(fields['country']) != 2 or not fields['country'].isalpha(): raise AskgodException("Invalid country ISO code.") fields['country'] = fields['country'].upper() for key, value in fields.items(): if not value: continue if getattr(dbentry, key): raise AskgodException("Field is already set: %s" % key) setattr(dbentry, key, value) return db_commit(db_store)
def scores_submit_special(self, client, code, flag): """ Submits/validates a special flag (external validator) """ if config_get_bool("server", "scores_read_only", False): return -6 db_store = client['db_store'] if not code or (not isinstance(code, str) and not isinstance(code, unicode)): if not code: logging.debug("[team %02d] No code provided" % client['team']) raise AskgodException("No code provided.") else: logging.debug("[team %02d] Invalid code type: %s (%s)" % (client['team'], code, type(code))) raise AskgodException("Invalid type for code.") if isinstance(code, str): code = code.decode('utf-8') if not flag or (not isinstance(flag, str) and not isinstance(flag, unicode)): if not flag: logging.debug("[team %02d] No flag provided" % client['team']) raise AskgodException("No flag provided.") else: logging.debug("[team %02d] Invalid flag type: %s (%s)" % (client['team'], flag, type(flag))) raise AskgodException("Invalid type for flag.") if isinstance(code, str): flag = flag.decode('utf-8') logging.info("[team %02d] Submits special flag for code: %s => %s" % (client['team'], code, flag)) # NOTE: Intentional, "DBFlag.flag == None" != "DBFlag.flag is not None" results = db_store.find(DBFlag, And(DBFlag.code == code, DBFlag.flag == None, DBFlag.validator != None)) if results.count() == 0: logging.debug("[team %02d] Code '%s' doesn't exist." % (client['team'], code)) notify_flag(client['team'], "", 0, "") raise AskgodException("Invalid code.") for entry in results: # Deal with per-team flags if entry.teamid and entry.teamid != client['team']: continue # Deal with counter-limited flags if entry.counter: count = db_store.find(DBScore, flagid=entry.id).count() if count >= entry.counter: logging.debug("[team %02d] Flag '%s' has been exhausted." % (client['team'], code)) raise AskgodException("Too late, the flag has " "been exhausted.") # Check that it wasn't already submitted if db_store.find(DBScore, flagid=entry.id, teamid=client['team']).count() > 0: logging.debug("[team %02d] Flag '%s' was already submitted." % (client['team'], code)) raise AskgodException("The flag has already been submitted.") # Call validator if subprocess.call(["validator/%s" % entry.validator, str(client['team']), str(code), str(flag)]) != 0: continue # Add to score score = DBScore() score.teamid = client['team'] score.flagid = entry.id score.value = entry.value score.submit_time = datetime.datetime.now() db_store.add(score) db_commit(db_store) logging.info("[team %02d] Scores %s points with flagid=%s" % (client['team'], entry.value, entry.id)) notify_flag(client['team'], entry.code, entry.value, entry.tags) retval = [] # Generate response response = {} response['value'] = score.value if entry.return_string: response['return_string'] = entry.return_string if entry.writeup_value: response['writeupid'] = "WID%s" % score.id retval.append(response) # Process triggers retval += process_triggers(client) return retval logging.debug("[team %02d] Flag '%s' exists but won't validate." % (client['team'], flag)) raise AskgodException("Unknown error with your flag, " "please report this.")
def scores_submit(self, client, flag): """ Submits/validates a flag """ if config_get_bool("server", "scores_read_only", False): raise AskgodException("Server is read-only.") db_store = client['db_store'] if not flag or (not isinstance(flag, str) and not isinstance(flag, unicode)): if not flag: logging.debug("[team %02d] No flag provided" % client['team']) raise AskgodException("No flag provided.") else: logging.debug("[team %02d] Invalid flag type: %s (%s)" % (client['team'], flag, type(flag))) raise AskgodException("Invalid type for flag.") if isinstance(flag, str): flag = flag.decode('utf-8') logging.info("[team %02d] Submits flag: %s" % (client['team'], flag)) results = db_store.find(DBFlag, DBFlag.flag.lower() == flag.lower()) if results.count() == 0: logging.debug("[team %02d] Flag '%s' doesn't exist." % (client['team'], flag)) notify_flag(client['team'], "", 0, "") raise AskgodException("Flag isn't valid.") for entry in results: # Deal with per-team flags if (entry.teamid is not None and entry.teamid != client['team']): continue # Deal with counter-limited flags if entry.counter: count = db_store.find(DBScore, flagid=entry.id).count() if count >= entry.counter: logging.debug("[team %02d] Flag '%s' has been exhausted." % (client['team'], flag)) raise AskgodException("Too late, the flag has " "been exhausted.") # Check that it wasn't already submitted if db_store.find(DBScore, flagid=entry.id, teamid=client['team']).count() > 0: logging.debug("[team %02d] Flag '%s' was already submitted." % (client['team'], flag)) raise AskgodException("The flag has already been submitted.") # Add to score score = DBScore() score.teamid = client['team'] score.flagid = entry.id score.value = entry.value score.submit_time = datetime.datetime.now() db_store.add(score) db_commit(db_store) logging.info("[team %02d] Scores %s points with flagid=%s" % (client['team'], entry.value, entry.id)) notify_flag(client['team'], entry.code, entry.value, entry.tags) retval = [] # Generate response response = {} response['value'] = score.value if entry.return_string: response['return_string'] = entry.return_string if entry.writeup_value: response['writeup_string'] = "WID%s" % score.id retval.append(response) # Process triggers retval += process_triggers(client) return retval logging.debug("[team %02d] Flag '%s' exists but can't be used." % (client['team'], flag)) raise AskgodException("Unknown error with your flag, " "please report this.")
def scores_progress(self, client, tags=None): """ Returns the progress percentage """ db_store = client['db_store'] if not tags: # Overall progress if not config_get_bool("server", "scores_progress_overall", False): raise AskgodException("Overall progress is disabled.") total = 0.0 obtained = 0.0 for entry in db_store.find(DBFlag): if entry.teamid and entry.teamid != client['team']: continue total += entry.value for entry in db_store.find(DBScore, teamid=client['team']): obtained += entry.value return int(obtained / total * 100) ret = {} if not isinstance(tags, list): ret = 0.0 tags = [tags] for tag in tags: namespace = tag.split(":")[0] if namespace not in config_get_list("server", "scores_progress_tags", []): raise AskgodException("Disallowed tag namespaced.") total = 0.0 obtained = 0.0 for entry in db_store.find(DBFlag): if entry.teamid and entry.teamid != client['team']: continue entry_tags = entry.tags.split(",") if tag in entry_tags: total += entry.value for entry in db_store.find(DBScore, teamid=client['team']): entry_tags = entry.flag.tags.split(",") if tag in entry_tags: obtained += entry.value if isinstance(ret, dict): if not total: ret[tag] = 0 continue ret[tag] = int(obtained / total * 100) else: if not total: return 0 return int(obtained / total * 100) return ret