def remove_member(request: _Parsed, clan: str, creds: CredManager = CredManager): if not ALLOW_REMOVALS: raise AppException("Players can not be removed from the clan now!") user = creds.user json = request.json to_remove = json.get("user") clan_data = get_clan_by_id(clan) members = clan_data.members if user != clan_data.leader and not creds.is_admin: raise AppException(f"You cannot edit settings for Clan {clan}") if to_remove not in members: if to_remove not in clan_data.clan_requests: raise AppException(f"User is not a member of Clan {clan}") remove_player_request(clan_data, get_user_by_id(to_remove)) else: remove_player_from_clan(clan_data, get_user_by_id(to_remove)) if len(clan_data.members) == 0: delete_from_db(clan_data, True) save_to_db() data = clan_data.as_json if user == to_remove: data.pop("_secure_") return {"clan_data": data}
def request_to_join(request: _Parsed, clan: str, event_name: str, creds: CredManager = CredManager): get = request.json.get user = creds.user user_data = get_user_by_id(user) registration_data = get("registration_data") assert_user_has_discord( user_data, error_message="You have not connected discord yet!") assert_user_is_clanless(user_data, event_name, prefix="You are") maximum = MAX_MEMBER_COUNT.get(event_name) clan_data = get_clan_by_id(clan) if len(clan_data.members) == maximum: raise AppException( f"Clan {clan_data.team_name} already has {maximum} members") if user in clan_data.clan_invites: add_player_with_side_effects(clan_data, user_data) else: current_requests = clan_data.clan_requests if user in current_requests: raise AppException( f"You have already requested to join Clan {clan}") add_player_request(clan_data, user_data) add_registration_data(user_data, event_name, registration_data) save_to_db() return {"user_data": user_data.as_json}
def validate_file(event, data): # APPROVED_DOMAINS = ("drive.google.com", "pastebin.com", "discord.com") if event not in EVENTS_REQUIRING_SUBMISSION: raise AppException("Invalid event!") parsed = urlparse(data) if parsed.scheme.lower() not in ("http", "https") or not parsed.netloc: raise AppException("Invalid URL")
def add_member(request: _Parsed, clan: str, creds: CredManager = CredManager): user = creds.user json = request.json to_add = json.get("user") if to_add == user: raise AppException("You cannot add yourself to a team!") clan_data = get_clan_by_id(clan) members = clan_data.members if user not in members and not creds.is_admin: raise AppException(f"You cannot edit settings for Clan {clan}") clan_event = clan_data.team_event maximum = MAX_MEMBER_COUNT.get(clan_event) if maximum == len(members): raise AppException(f"Clan has reached the max limit of players") addee_data = get_user_by_id(to_add) assert_user_is_clanless(addee_data, clan_event) clan_requests = clan_data.clan_requests if to_add in clan_requests: add_player_with_side_effects(clan_data, addee_data) else: # the player hasn't requested to join, invite them invites = addee_data.clan_invites.get(clan_event) or [] if clan in invites: raise AppException("Already Invited!") add_player_invite(clan_data, addee_data) save_to_db() return {"clan_data": clan_data.as_json}
def login(request: _Parsed): json = request.json get = json.get user = get("user", "").strip().lower() password = get("password", "") invalids = [] if not user: invalids.append("username") if not password: invalids.append("password") if invalids: raise AppException(f"Invalid {' and '.join(invalids)}", code=401) user_data = get_user_by_id(user) password_hash = user_data.password_hash if not check_password_hash(password_hash, password): raise AppException("Incorrect Password", code=401) username = user_data.user access_token = create_token(issue_access_token(username)) refresh_token = create_token(issue_refresh_token(username, password_hash)) return json_response( {"data": { "success": True, "user_data": user_data.as_json }}, headers={ "x-access-token": access_token, "x-refresh-token": refresh_token }, )
def _validate_user(self, user: str): length = len(user) if length > 30: raise AppException("Username cannot be longer than 30 characters") if length < 4: raise AppException("Username cannot be shorter than 4 characters") if sanitize(user) != user: raise AppException("Username cannot have special characters or whitespace")
def _validate_team_name(self, val): val_len = len(val) if val_len > 80: raise AppException("Team name must be less than 30 characters") if val_len < 4: raise AppException("Team name must be atleast 4 characters") if sanitize(val) != val: raise AppException("Invalid characters in team name")
def edit(request: _Parsed, user: str, creds: CredManager = CredManager): editable_fields = ("email", "school", "name") current_user = creds.user if user != current_user: raise AppException("Cannot edit ( not allowed )") json = request.json edit_field = json.get("field") if edit_field not in editable_fields: raise AppException("Requested field cannot be edited") new_value = json.get("new_value") user_data = get_user_by_id(current_user) setattr(user_data, edit_field, new_value) save_to_db() return user_data.as_json
def setup_discord(request: _Parsed, creds=CredManager): user = get_user_by_id(creds.user) if all(x for x in ( user.discord_id, user.discord_access_token, user.discord_refresh_token, user.discord_token_expires_in, )): raise AppException("Discord already linked!!") code = request.json["code"] discord_response = exchange_code(code) access = discord_response["access"] refresh = discord_response["refresh"] expires = discord_response["expires"] discord_id = discord_response["discord_id"] user.discord_id = discord_id user.discord_access_token = access user.discord_refresh_token = refresh user.discord_token_expires_in = expires save_to_db() return {"user_data": user.as_json}
def decode_token(data: str) -> dict: try: return _decode_token(data, _SIGNING_KEY) except _EXPIRED: return None except: raise AppException("Invalid token")
def decode_token(data: str) -> dict: try: return _decode_token(data, _SIGNING_KEY, algorithms=["HS512"]) except _EXPIRED: return None except Exception as e: print(e) raise AppException("Invalid token", 400)
def score_team(request: ParsedRequest, team, creds=CredManager): json = request.json team_data = get_clan_by_id(team) score = int(json["score"]) if not 0 <= score <= 20: raise AppException("Invalid value of score") round_num = int(json["round"]) if team_data.current_round != round_num: raise AppException("User has already been rated for this round") # validate_score(score,team_data.team_event) # if only allow scores 5+ to progress if score > 5 and get_config( team_data.team_event).number_of_rounds < round_num: team_data.current_round += 1 team_data.score.append(score) save_to_db() return SUCCESS
def requalify(request: ParsedRequest, team, creds=CredManager): team_data = get_clan_by_id(team) if not team_data.is_disqualifed: raise AppException("Team not disqualified") team_data.is_disqualified = False save_to_db() return SUCCESS
def query_user(data: dict) -> dict: access = data["access"] req = requests.get(f"{API_ENDPOINT}/users/@me", auth=TokenAuth(access)) js = req.json() if not req.ok: print(js) raise AppException("Error while fetching user data from discord") data["discord_id"] = js["id"] return data
def get_user_details(request: _Parsed, user: str, creds: CredManager = CredManager): current_user = creds.user if current_user is not None and (user == "me" or current_user == user.lower()): return self_details(request, creds) raise AppException("Not authorized", 403)
def assert_user_has_discord(user: UserTable, error_message="No discord connection found!"): if any(not x for x in ( user.discord_id, user.discord_access_token, user.discord_refresh_token, user.discord_token_expires_in, )): raise AppException(error_message)
def __setattr__(self, key: str, val): if self._is_same_value(key, val): return if key == "team_event": if val not in EVENT_NAMES: raise AppException(f"Invalid Event name {val}") if key == "team_name": val = val.lower() self._validate_team_name(val) if key == "is_disqualified" and not val: # if we are requalifying someone, also clear the disqualification reason if self.__inited: super().__setattr__("disqualification_reason", None) if key == "members" and len(val) > 5: raise AppException("Team can only have 5 players at amx") super().__setattr__(key, val)
def verify_email(token: str): token = decode_token(token) assert_token_is_valid(token) user = token["u"] user_data = get_user_by_id(user) if user_data.email == token["e"]: user_data.has_verified_email = True save_to_db() return True raise AppException("Could not verify email")
def disqualify(request: ParsedRequest, team, creds=CredManager): reason = request.json["reason"].strip() team_data = get_clan_by_id(team) if team_data.is_disqualifed: raise AppException("Already disqualified") team_data.is_disqualified = True team_data.disqualification_reason = reason save_to_db() return SUCCESS
def submit(request: _Parsed, event: str, team_name: str, creds=CredManager): json: dict = request.json submit_data = json["data"] submission_round = json["round"] validate_file(event, submit_data) team_data = get_clan_by_id(team_name) if creds.user != team_data.leader: raise AppException("Only the clan leader can submit") if len(team_data.submissions) > submission_round: raise AppException("Already submitted!") if team_data.current_round != submission_round: raise AppException("Invalid level") team_data.submissions.append(submit_data) team_data.submitted_at = time() save_to_db() return {"team_data": team_data.as_json}
def get_user_details(request: _Parsed, user: str, creds: CredManager = CredManager): current_user = creds.user if user == "me" or current_user == user.lower(): if current_user is not None: return self_details(request, creds) raise AppException("Not Authenticated") user_details = get_user_by_id(user) json = user_details.as_json json.pop("_secure_") return {"user_data": json}
def verify_password(token: str, new_password: str): token = decode_token(token) assert_token_is_valid(token) user = token["u"] user_data = get_user_by_id(user) if not check_password_hash(token["ch"], user_data.user + user_data.password_hash): raise AppException("Password already changed!") user_data.password_hash = new_password save_to_db()
def create_team(request: _Parsed, team_event, creds: CredManager = CredManager): json = request.json get = json.get team_name = get("team_name") if team_event not in EVENT_NAMES: # bail out before hitting the db raise AppException("Event does not exist") registration_data = get("registration_data") user = get_user_by_id(creds.user) assert_user_has_discord( user, error_message="Cannot create clan without integrating with discord") assert_user_is_clanless(user, team_event, prefix="You are") members = [creds.user] try: team = TeamTable( team_name=team_name, team_event=team_event, members=members, leader=creds.user, ) user.team_data[team_event] = { "name": team_name, "registration_data": validate(registration_data, team_event), } add_to_db(team) except Exception as e: if isinstance(getattr(e, "orig", None), IntegrityError): raise AppException("clan name taken") raise e return {"clan_data": team.as_json}
def get_token(strict=True): headers = request.headers # should just use Authorization here... received_access_token = headers.get("x-access-token") if not received_access_token: if strict: raise AppException("No authentication provided") return None try: access = decode(received_access_token) except Exception: if strict: raise AppException("Invalid token") return None if access is None: if strict: raise AppException("refresh") return None return access
def music_shape( artist_name: str = None, daw_used: str = None, music_platform_link: str = None, category: str = None, ) -> dict: if category not in ("edm", "lofi"): raise AppException("Invalid Music category") return { "artist_name": artist_name, "daw_used": daw_used, "music_platform_link": music_platform_link, "category": category, }
def get_file_list(request: _Parsed, user: str, creds: CredManager = CredManager): if creds.user is None or (creds.user != user): raise AppException("Not authorized", 403) # pylint: disable=no-member files = (db.session.query( *[c for c in File.__table__.c if c.name != "binary"]).filter( File.owner_user == user, File.data_type == "encrypted_blob").all()) # pylint: enable=no-member ret = [f._asdict() for f in files] return {"files": ret}
def _post_to_discord(data): r = requests.post(f"{API_ENDPOINT}/oauth2/token", data=data) if not r.ok: print(r.text) # return raise AppException("Discord api gave invalid response") js = r.json() return { "access": js["access_token"], "refresh": js.get("refresh_token"), "expires": js["expires_in"], "token_type": "discord", }
def register_for_game(request: _Parsed, game: str, creds: CredManager = CredManager): get = request.json.get game = get("gaming_event__game") data = get("registration_data") user = creds.user user_data = get_user_by_id(user) event = "gaming" team_data = user_data.team_data.get(event) if team_data is None: raise AppException("Please register for the event first") game_data = team_data.get("game_data") or {} reg_data = game_data.get(game) if reg_data is not None: raise AppException("Already submitted details!") mutate(team_data, "game_data", "game", init_user_gaming_data_dict(data, game)) save_to_db() return {"user_data": user_data.as_json}
def register(request: _Parsed): json = request.json get = json.get user = get("user") name = get("name") password = get("password") try: user_data = UserTable(user, name, password) add_to_db(user_data) print("registered ", user) return {"user_data": user_data.as_json} except Exception as e: if isinstance(getattr(e, "orig", None), IntegrityError): raise AppException("User exists", 409) raise e
def reset_password(request: _Parsed, creds=CredManager): user = creds.user js = request.json current_password = js["current_password"] new_password = js["new_password"] u_data = get_user_by_id(user) hashed_pw = u_data.password_hash if not check_password_hash(hashed_pw, current_password): raise AppException("Incorrect Password", 401) u_data.password_hash = new_password save_to_db() return { "user_data": u_data.as_json, "message": "Please do not close the window while CollegeWarden re encrypts your files with the new password", }