def register(username: str, password: str): profile = Profile.get_or_none(Profile.username == username) if profile is not None: raise BadRequest('A user with this username already exists') hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode() profile = Profile.create( username=username, hashed_password=hashed, ) global_game = Game.get_or_none(Game.name == 'Global Indefinite') GameProfile.create(game=global_game, profile=profile, cash=global_game.starting_cash) global_game = Game.get_or_none(Game.name == 'Global Timed') GameProfile.create(game=global_game, profile=profile, cash=global_game.starting_cash) send_notification(profile, 'Welcome to Fortune!') send_notification( profile, 'Click the Play button in the menubar on top to create a new game.') send_notification( profile, 'To adjust account options, see achiements, and add friends, click on your username on the top and select Profile' ) return create_auth_token(profile)
def create_request(requester_name, requestee_name, status): requester_profile = Profile.get_or_none(Profile.username == requester_name) requestee_profile = Profile.get_or_none(Profile.username == requestee_name) if requester_profile is None: raise BadRequest('Could not find requester') if requestee_profile is None: send_notification(requester_profile, f'User {requestee_name} does not exist.') raise BadRequest('Could not find requestee') if requester_profile == requestee_profile: send_notification(requester_profile, f'Cannot friend yourself!') raise BadRequest('Cannot friend self') check_duplicates = Friends.get_or_none( (Friends.requester == requester_profile) & (Friends.requestee == requestee_profile)) if check_duplicates is not None: send_notification( requester_profile, f'Friend request to {requestee_profile.username} has already been created' ) raise BadRequest('Friend request has already been made') req = Friends.create(requester=requester_profile, requestee=requestee_profile, status=status) send_notification( requester_profile, f'Friend request to {requestee_profile.username} has been sent!') send_notification( requestee_profile, f'{requester_profile.username} has sent you a friend request!') return req
def change_username(profile_id: int, username: str): profile = Profile.get_or_none(Profile.username == username) if profile is not None: raise BadRequest('A user with this username already exists') try: update_username = Profile.update({ Profile.username: username }).where(Profile.id == profile_id) update_username.execute() except Exception as e: raise BadRequest('Failure to change username: {}'.format(str(e)))
def ban_user(profile_id: int): rows = Profile.update({ Profile.is_banned: True }).where(Profile.id == profile_id).execute() if rows == 0: raise BadRequest("Cannot ban user") profile = Profile.get_or_none(Profile.id == profile_id) if not profile: raise BadRequest("Profile not found") print("BANNED PROFILE IS BANNED:", profile.is_banned) broadcast(profile, "ban", "Your account has been banned for violating our policy.", True)
def set_skin(readable, model, profile: Profile): try: image: Image = Image.open(readable) except (FileNotFoundError, UnidentifiedImageError, ValueError): # May be inconsistent with official API return INVALID_IMAGE.dual try: profile.update_skin(image, model) except ValueError: # May be inconsistent with official API return INVALID_SKIN.dual return "", 204
def call(program, argv): parser = argparse.ArgumentParser(prog=program) parser.add_argument("dbid", help="new profile's account DBID", type=int) parser.add_argument("name", help="new profile's username") parser.add_argument("agent", help="new profile's agent") parser.add_argument("-u", "--uuid", help="new profile's UUID", type=UUID) args = parser.parse_args(argv) input_uuid = args.uuid if args.uuid is not None else uuid4() account: Account = Account.get(id=args.dbid) if account is None: print("No account matches that DBID!") exit(1) try: profile = Profile.create(uuid=input_uuid, agent=args.agent, account=account, name=args.name) except ExistsException: print("Name not available.") exit(1) try: commit() except Exception as e: print(str(e)) exit(1) print(profile)
def call(program, argv): parser = argparse.ArgumentParser(prog=program) parser.add_argument("name", help="profile name") parser.add_argument("-t", "--time", help="timestamp of past time", type=int) parser.add_argument("--unix", help="show timestamps as integer", action="store_true") args = parser.parse_args(argv) if args.time is None: args.time = datetime.utcnow() event = Profile.that_owned_name_at(args.name, args.time) print(f"History of {args.name}") if event is None: print(f"No profile owned that name at {args.time}!") else: print(f"Owner of {event.name} @ {args.time}: {event.profile}") events = ProfileNameEvent.select(lambda x: x.name == args.name or x.name_upper == args.name.upper() or x.name_lower == args.name.lower())\ .order_by(desc(ProfileNameEvent.active_from)) for old_event in events: print(old_event)
def test_get_coins_with_invalid_time_span(self): profile = Profile.get_or_none(Profile.username == 'theusername') GameProfile.create(game=1, profile=profile, cash=10000) res = self.client.get( '/game/1/coins?timeSpan=6&sortBy=0&numPerPage=10&pageNum=1', headers={'Authorization': 'Bearer ' + self.token}) self.assertEqual(int(HTTPStatus.BAD_REQUEST), res._status_code)
def setUp(self): super().setUp() with db.atomic() as txn: profile = Profile.create(username='******', hashed_password='******') self.token = AuthToken.create(profile=profile, token='thevalidtoken').token
def json_and_response_code(uuid): if len(uuid) != 32: return "", 204 try: uuid_object = UUID(uuid) except ValueError: return "", 204 profile = Profile.get(uuid=uuid_object) if profile is None: return "", 204 history = [] for event in profile.profile_name_events.order_by(desc(ProfileNameEvent.active_from)): event: ProfileNameEvent if event.is_initial_name: history.append({ "name": event.name }) else: history.append({ "name": event.name, "changedToAt": int(event.active_from.timestamp()) }) return jsonify(history), 200
def join_mcserver(request, textures_host): username, server_hash, ip = request.args.get("username"), request.args.get( "serverId"), request.args.get("ip") if username is None or server_hash is None: # May be inconsistent with official API return NULL_MESSAGE.dual profile = Profile.get_profile_with_name(username) if profile is None: # May be inconsistent with official API return MCSERVER_INVALID_PROFILE.dual session = MCServerSession.get( lambda x: x.profile == profile and x.server_hash == server_hash) if session is None: # May be inconsistent with official API return MCSERVER_INVALID_SESSION.dual if ip is not None and session.client_side_ip != ip: # May be inconsistent with official API return MCSERVER_DIFFERENT_IP.dual session.delete() return jsonify(get_public_profile_details(profile, False, textures_host)), 200
def call(program, argv): parser = argparse.ArgumentParser(prog=program) parser.add_argument("dbid", help="DBID of profile", type=int) parser.add_argument("--unix", help="show timestamps as integer", action="store_true") args = parser.parse_args(argv) profile: Profile = Profile.get(id=args.dbid) if profile is None: print("No profile matches that DBID!") exit(1) print(f"History of {profile}") print( f"Current name styles: {profile.name}, {profile.name_upper}, {profile.name_lower}" ) for event in profile.profile_name_events.order_by( desc(ProfileNameEvent.active_from)): if args.unix: print(event.repr_timestamp()) else: print(event)
def test_user_automatically_joins_new_global_time_game(self): # register user res = self.client.post('/auth/register', data=json.dumps({ 'username': '******', 'password': '******', 'password': '******', }), headers={'Content-Type': 'application/json'}) self.assertEqual(200, res._status_code) game_before_check = Game.get(Game.name == 'Global Timed') game_before_check.ends_at = datetime.utcnow() game_before_check.save() # assert deletes old GameProfile profile = Profile.get_by_id(1) qry = GameProfile.select().join(Game).where( (GameProfile.profile == profile) & (Game.name == 'Global Timed')) self.assertEqual(2, len(profile.game_profiles) ) # should have 2: global timed and indefinite self.assertEqual(1, qry.count()) # just to make sure gp_old = qry.get() check_global_timed_game() # assert creates new GameProfile qry = GameProfile.select().join(Game).where( (GameProfile.profile == profile) & (Game.name == 'Global Timed')) self.assertEqual(1, qry.count()) gp_new = qry.get() # but the ids should not be the same self.assertNotEqual(gp_old.id, gp_new.id)
def call(program, argv): parser = argparse.ArgumentParser(prog=program) parser.add_argument("dbid", help="DBID of profile", type=int) parser.add_argument("timestamp", help="timestamp", type=int) args = parser.parse_args(argv) profile: Profile = Profile.get(id=args.dbid) if profile is None: print("No profile matches that DBID!") exit(1) try: event = profile.owned_name_at(datetime.utcfromtimestamp( args.timestamp)) except OSError: print("Invalid timestamp.") exit(1) if event is None: print("This profile didn't have a name at that time.") exit(1) print(event)
def login(username: str, password: str): profile = Profile.get_or_none(Profile.username == username) if profile is None: raise BadRequest('A user with this username does not exist') if profile.is_banned: raise BadRequest("This user has been banned.") if not bcrypt.checkpw(password.encode(), profile.hashed_password.encode()): raise BadRequest('Incorrect password') return create_auth_token(profile)
def accept_request(requester_name, requestee_name): requester_profile = Profile.get_or_none(Profile.username == requester_name) requestee_profile = Profile.get_or_none(Profile.username == requestee_name) if requester_profile is None: raise BadRequest('Could not find requester') if requestee_profile is None: raise BadRequest('Could not find requestee') req = Friends.get_or_none((Friends.requester == requester_profile) & (Friends.requestee == requestee_profile)) if req is None: raise BadRequest('Could not find request') req.status = 1 other_way_friendship = Friends.create(requester=requestee_profile, requestee=requester_profile, status=1) send_notification( requester_profile, f'{requestee_profile.username} has accepted your friend request!') return req
def send(profile): validated_data: dict = FriendsSerializer.deserialize(request.json) requester_name = validated_data['requester'] requestee_name = validated_data['requestee'] status = validated_data['status'] friend_req = create_request(requester_name, requestee_name, status) if friend_req is None: raise BadRequest('Could not create request') pending = get_pending_by_profile(Profile.get_or_none(Profile.username == requestee_name)) return jsonify(PendingList.serialize({'pending': pending,}))
def json_and_response_code(request): if "clientToken" not in request.json or request.json["clientToken"] is None: return NULL_CLIENT_TOKEN.dual if "accessToken" not in request.json or request.json["accessToken"] is None: return NULL_ACCESS_TOKEN.dual access_token = AccessToken.from_token(request.json["accessToken"]) try: if access_token is None or access_token.client_token.uuid != UUID( request.json["clientToken"]): return INVALID_TOKEN.dual except ValueError: return INVALID_UUID.dual if "selectedProfile" in request.json: try: _selected_uuid = UUID(request.json["selectedProfile"]["id"]) except ValueError: return INVALID_UUID.dual new_profile = Profile.get( lambda x: x.uuid == _selected_uuid and x.name == request.json[ "selectedProfile"][ "name"] and x.account == access_token.client_token.account) if new_profile is None: return PROFILE_NOT_FOUND.dual else: new_profile = access_token.profile new_access_token = AccessToken( client_token=access_token.client_token, profile=new_profile, ) access_token.delete() response_data = { "accessToken": jwt_encode(new_access_token.format(), key="").decode(), "clientToken": request.json["clientToken"], } if new_access_token.profile: response_data["selectedProfile"] = { "id": new_access_token.profile.uuid.hex, "name": new_access_token.profile.name } if "requestUser" in request.json and request.json["requestUser"]: response_data["user"] = { "id": new_access_token.client_token.account.uuid.hex, "username": new_access_token.client_token.account.username } return jsonify(response_data), 200
def call(program, argv): parser = ArgumentParser(prog=program) parser.add_argument("dbid", help="DBID of profile", type=int) sources = parser.add_mutually_exclusive_group(required=True) sources.add_argument("-u", "--url", help="url of skin", dest="url") sources.add_argument("-f", help="file path of skin", dest="path") sources.add_argument("--delete", help="reset profile skin", action="store_true") parser.add_argument("--slim", help="slim model", action="store_true") args = parser.parse_args(argv) profile: Profile = Profile.get(id=args.dbid) if profile is None: print("No profile matches that DBID!") exit(1) if args.url is not None: fd = BytesIO(get(args.url).content) elif args.path is not None: fd = Path(args.path) elif not args.delete: print("You must specify a file!") exit(1) if args.delete: profile.reset_skin() else: try: image: Image = Image.open(fd) except (FileNotFoundError, UnidentifiedImageError, ValueError): print(INVALID_IMAGE.message) exit(1) try: profile.update_skin(image, "slim" if args.slim else "") except ValueError: print(INVALID_SKIN.message) exit(1) try: commit() except Exception as e: print(e) exit(1) if not args.delete: print(f"Texture name: {profile.profile_skin.name}")
def up(db): with db.atomic(): migrator = PostgresqlMigrator(db) db.bind(MODELS, bind_refs=False, bind_backrefs=False) db.create_tables(MODELS) if Coin.get_or_none(Coin.id == 1) is None: Coin.create(name='Bitcoin', symbol='BTC') Coin.create(name='Ethereum', symbol='ETH') Coin.create(name='Litecoin', symbol='LTC') Coin.create(name='Coin 3', symbol='CO3') Coin.create(name='Coin 4', symbol='CO4') Coin.create(name='Coin 5', symbol='CO5') global_indef = Game.create(name='Global Indefinite', starting_cash=10000.00, shareable_link='INDEF', shareable_code='INDEF', ends_at=None) # insert achievements into database Achievement.create( name="Win", description="Finish in first place in a private game") Achievement.create( name="Double net worth", description="Achieved by doubling your net worth in a game") Achievement.create(name="Identity Crisis", description="Change your username") # insert goals into database Goal.create(name="Entrepreneur", description="Create a private game") all_coins = Coin.select() for coin in all_coins: GameCoin.create(game=global_indef, coin=coin) global_timed = Game.create(name='Global Timed', starting_cash=10000.00, shareable_link='TIMED', shareable_code='TIMED', ends_at=datetime.utcnow() + timedelta(minutes=1)) # CHANGEME for devel purposes, making it 1 min for now GameCoin.create(game=global_timed, coin=Coin.get()) # from auth.services import register hashed = bcrypt.hashpw("admin".encode(), bcrypt.gensalt()).decode() admin = Profile.create(username="******", hashed_password=hashed, is_admin=True) # Required so that admin can still view graphs in the landing page GameProfile.create(profile=admin, game=global_indef, cash=0.0)
def json_and_response_code(request): if len(request.json) > 10: return OVER_PROFILE_LIMIT.dual uuids = [] for name in request.json: profile = Profile.get_profile_with_name(name) if profile is None: continue uuids.append({"id": profile.uuid.hex, "name": profile.name}) return jsonify(uuids), 200
def test_buy_coin_without_cash(self): profile = Profile.get_or_none(Profile.username == 'theusername') GameProfile.create(game=1, profile=profile, cash=0) GameCoin.create(game=1, coin=1) Ticker.create(coin=1, price=10, price_change_day_pct=1.1) res = self.client.post( '/game/1/coin', data=json.dumps({ 'coinId': '1', 'coinAmount': '1', }), content_type='application/json', headers={'Authorization': 'Bearer ' + self.token}) self.assertEqual(int(HTTPStatus.BAD_REQUEST), res._status_code)
def change_password(profile: Profile, old_password: str, new_password: str): if not bcrypt.checkpw(old_password.encode(), profile.hashed_password.encode()): raise BadRequest('Incorrect old password') hashed_new_password = bcrypt.hashpw(new_password.encode(), bcrypt.gensalt()).decode() try: update_password = Profile.update({ Profile.hashed_password: hashed_new_password }).where(Profile.id == profile.id) update_password.execute() except Exception as e: raise BadRequest('Failure to change password: {}'.format(str(e)))
def setUp(self): super().setUp() with db.atomic() as txn: #don't need to create a game, migrations/v1.py gets run before every test #Coin.create(id=1, name='Bitcoin', symbol='BTC') Game.create(name='Game', starting_cash=10000.00, shareable_link='aaaabbbbccccdddd', shareable_code='aaaa', ends_at=(datetime.utcnow().replace(tzinfo=pytz.utc) + timedelta(days=7)).isoformat()) profile = Profile.create(username='******', hashed_password='******') self.token = AuthToken.create(profile=profile, token='thevalidtoken').token
def send_notification_to_all(message: str): if socketio is None: raise Exception('Tried to emit but socketio is not initialized!') profiles = Profile.select().where(~Profile.is_admin).execute() notifications = [(profile.id, message) for profile in profiles] for batch in chunked(notifications, 100): Notification.insert_many( batch, fields=[Notification.profile, Notification.content]).execute() # LOOKATME: Seems slow for profile in profiles: if not profile.socket_id: continue socketio.emit('notification', message, room=profile.socket_id)
def json_and_response_code(request, uuid, textures_host): try: uuid_object = UUID(uuid) except ValueError: return "", 204 profile = Profile.get(uuid=uuid_object) if profile is None: return "", 204 unsigned = request.args.get("unsigned") if unsigned is not None and unsigned == "false": return jsonify( get_public_profile_details(profile, False, textures_host)), 200 return jsonify(get_public_profile_details(profile, True, textures_host)), 200
def test_liquefy_success(self): profile = Profile.get_or_none(Profile.username == 'theusername') game_profile = GameProfile.create(game=1, profile=profile, cash=0) GameCoin.create(game=1, coin=1) GameProfileCoin.create(game_profile=game_profile, coin=1, coin_amount=2) Ticker.create( coin=1, price=10, captured_at=(datetime.utcnow()).isoformat(), price_change_day_pct=1.1, ) res = self.client.delete( '/game/1/coins', headers={'Authorization': 'Bearer ' + self.token}) self.assertEqual(int(HTTPStatus.OK), res._status_code)
def json_and_response_code(request, username): if "at" not in request.args: at = datetime.utcnow() else: try: at = datetime.utcfromtimestamp(int(request.args["at"])) except (ValueError, OSError): return INVALID_TIMESTAMP.dual event = Profile.that_owned_name_at(username, at) if event is None: return "", 204 return jsonify({ "id": event.profile.uuid.hex, "name": event.profile.name }), 200
def test_allows_correct_token(self, auth_token_mock): stub_profile = Profile( username='******', hashed_password='******', ) stub_authtoken = AuthToken( profile=stub_profile, token='valid-token', ) auth_token_mock.return_value = stub_authtoken m = Mock() m.headers.get.return_value = 'Bearer valid-token' with patch('auth.decorators.request', m): profile = route() self.assertEqual(stub_profile.username, profile.username) self.assertEqual(stub_profile.hashed_password, profile.hashed_password) auth_token_mock.assert_called_with('valid-token')
def test_get_coins_success(self): profile = Profile.get_or_none(Profile.username == 'theusername') GameProfile.create(game=1, profile=profile, cash=10000) GameCoin.create( game=1, coin=1, ) for coin in Coin.select(): Ticker.create( coin=coin, price=30.0, captured_at=(datetime.utcnow()).isoformat(), price_change_day_pct=1.1, ) res = self.client.get( '/game/1/coins?timeSpan=1&sortBy=0&numPerPage=10&pageNum=1', headers={'Authorization': 'Bearer ' + self.token}) self.assertEqual(int(HTTPStatus.OK), res._status_code)