def dev_harness(): # Use one TOTP QR and code for all of dev. if ENV_TYPE == 'Production': print("Nope.") return threesixthree = DBSession.query(OneTimeTOTP).filter(OneTimeTOTP.user_id==363).one() for user in DBSession.query(User).filter(User.role.in_((4,8))).all(): if not user.active: continue if user.id==363: continue local_db_session = get_scoped_session() totp_record = local_db_session.query(OneTimeTOTP).filter( OneTimeTOTP.user_id==user.id).first() if not totp_record: totp_record = OneTimeTOTP( user_id=user.id, ) local_db_session.add(totp_record) totp_record.url=threesixthree.url totp_record.code=threesixthree.code local_db_session.commit() local_db_session.close() img = qrcode.make(threesixthree.url) fname = '/tmp/UPSTAGE_{}.png'.format('gauth') img.save(fname)
def resolve_active_recording(self, info): recording = DBSession.query(PerformanceModel)\ .filter(PerformanceModel.stage_id == self.db_id)\ .filter(PerformanceModel.recording == True)\ .filter(PerformanceModel.saved_on == None)\ .first() return recording
def refresh(): current_user_id = get_jwt_identity() refresh_token = request.headers[app.config['JWT_HEADER_NAME']] user = DBSession.query(User).filter(User.id == current_user_id).filter( User.active == True).first() if not user: TNL.add(refresh_token) return make_response( jsonify({'error': "Your session expired. Please log in again."}), 401) access_token = create_access_token(identity=current_user_id) user_session = UserSession( user_id=current_user_id, access_token=access_token, refresh_token=refresh_token, app_version=request.headers.get('X-Upstage-App-Version'), app_os_type=request.headers.get("X-Upstage-Os-Type"), app_os_version=request.headers.get("X-Upstage-Os-Version"), app_device=request.headers.get("X-Upstage-Device-Model")) with ScopedSession() as local_db_session: local_db_session.add(user_session) local_db_session.flush() user_session_id = user_session.id return make_response(jsonify({'access_token': access_token}), 200)
def mutate(self, info, refresh_token): current_user_id = get_jwt_identity() refresh_token = request.headers[app.config['JWT_HEADER_NAME']] user = DBSession.query(User).filter(User.id == current_user_id).filter( User.active == True).first() if not user: TNL.add(refresh_token) raise Exception("Your session expired. Please log in again.") access_token = create_access_token(identity=current_user_id) user_session = UserSession( user_id=current_user_id, access_token=access_token, refresh_token=refresh_token, app_version=request.headers.get('X-Upstage-App-Version'), app_os_type=request.headers.get("X-Upstage-Os-Type"), app_os_version=request.headers.get("X-Upstage-Os-Version"), app_device=request.headers.get("X-Upstage-Device-Model")) with ScopedSession() as local_db_session: local_db_session.add(user_session) local_db_session.flush() user_session_id = user_session.id return RefreshMutation(new_token=access_token)
def mutate(self, info, inbound): data = graphql_utils.input_to_dictionary(inbound) code,error,user,timezone = current_user() if not user.role in (ADMIN,SUPER_ADMIN) : if not user.id == int(data['id']): raise Exception("Permission denied!") if not data['email'] and data['role'] != GUEST: raise Exception("Email is required!") with ScopedSession() as local_db_session: user = local_db_session.query(UserModel)\ .filter(UserModel.id==data['id']).first() if (data['password']): data['password'] = encrypt(data['password']) else: del data['password'] for key, value in data.items(): if key == 'active': if value and not user.active and not user.deactivated_on: send(user.email, f"Registration approved for user {user.username}", user_approved(user)) if not value and user.active: user.deactivated_on = datetime.now() if hasattr(user, key): setattr(user, key, value) user = DBSession.query(UserModel).filter(UserModel.id==data['id']).first() return UpdateUser(user=user)
def generate_user_totp(user_id): user = DBSession.query(User).filter(User.id==user_id).one() local_db_session = get_scoped_session() local_db_session.query(OneTimeTOTP).filter( OneTimeTOTP.user_id==user_id).delete(synchronize_session=False) code=pyotp.random_base32() totp_record = OneTimeTOTP( user_id=user_id, url=f'otpauth://totp/UPSTAGE_{ENV_TYPE}:{user.email}?secret={code}&issuer=Upstage', code=code, ) local_db_session.add(totp_record) local_db_session.flush() totp_record_url = totp_record.url local_db_session.commit() local_db_session.close() img = qrcode.make(totp_record_url) fname = '/tmp/{}_{}_{}.png'.format(user_id,user.email,'gauth') img.save(fname)
def wrapper(*args, **kwargs): try: verify_jwt_in_request() current_user_id = get_jwt_identity() user = DBSession.query(User).options(FromCache("default")).filter( User.id == current_user_id).filter( User.active == True).first() #print(request.referrer) if ENV_TYPE == 'Production' and '/vue_admin/' not in request.referrer: abort(403, 'Invalid path.') except ExpiredSignatureError: app.logger.warning("Signature Expired") return make_response( jsonify({'error': "You have been logged out on this session."}), 401) except RevokedTokenError: app.logger.warning("Token Revoked") return make_response( jsonify( {'error': "You have been logged out on this session ."}), 401) except NoAuthorizationError: app.logger.warning("Token Revoked from another login") return make_response( jsonify( {'error': "You have been logged out on this session ."}), 401) return fn(*args, **kwargs)
def mutate(self, info, input): data = graphql_utils.input_to_dictionary(input) with ScopedSession() as local_db_session: stage = local_db_session.query(StageModel).filter( StageModel.id == data['id']).first() for key, value in data.items(): if hasattr(stage, key): setattr(stage, key, value) elif value: attribute = stage.attributes.filter( StageAttributeModel.name == key).first() if attribute: attribute.description = value else: attribute = StageAttributeModel(stage_id=data['id'], name=key, description=value) local_db_session.add(attribute) local_db_session.commit() stage = DBSession.query(StageModel).filter( StageModel.id == data['id']).first() return UpdateStage(stage=stage)
def resolve_events(self, info, performance_id=None, cursor=0): events = DBSession.query(EventModel)\ .filter(EventModel.performance_id == performance_id)\ .filter(EventModel.id > cursor)\ .filter(EventModel.topic.like("%/{}/%".format(self.file_location)))\ .order_by(EventModel.mqtt_timestamp.asc())\ .all() return events
def resolve_scenes(self, info, performance_id=None): query = DBSession.query(SceneModel)\ .filter(SceneModel.stage_id == self.db_id)\ .order_by(SceneModel.scene_order.asc()) if not performance_id: # Only fetch disabled scene in performance replay query = query.filter(SceneModel.active == True) scenes = query.all() return scenes
def mutate(self, info, users, stageIds=[]): code,error,user,timezone = current_user() if not user.role in (ADMIN,SUPER_ADMIN) : raise Exception("Permission denied!") ids = [] with ScopedSession() as local_db_session: duplicated = [] for i in range(len(users) - 1): for j in range(i + 1, len(users)): if users[i].username == users[j].username: duplicated.append(users[i].username) if duplicated: raise Exception('Duplicated username: '******', '.join(duplicated)) existed = [user.username for user in DBSession.query(UserModel).filter(UserModel.username.in_([x.username for x in users])).all()] if existed: raise Exception('Username already existed: ' + ', '.join(existed)) for item in users: user = UserModel( username=item.username, active=True, role=GUEST ) # Add validation for non-empty passwords, etc. user.password = encrypt(item.password) local_db_session.add(user) local_db_session.flush() ids.append(user.id) # Now assigns users into stages stages = DBSession.query(StageModel).filter(StageModel.id.in_(stageIds)).all() for stage in stages: player_access = stage.attributes.filter(StageAttributeModel.name == 'playerAccess').first() if player_access: accesses = json.loads(player_access.description) for user_id in ids: if user_id not in accesses[0]: accesses[0].append(user_id) # append user id to player ids player_access.description = json.dumps(accesses) local_db_session.flush() local_db_session.commit() users = DBSession.query(UserModel).filter(UserModel.id.in_(ids)).all() return BatchUserCreation(users=users)
def one_time_prod_gen(): if ENV_TYPE != 'Production': print("Nope.") return # This will delete and replace codes!!! for user in DBSession.query(User).filter( User.active==True).filter( User.role.in_((4,8))).all(): generate_user_totp(user.id)
def check(self, header, token): # Check if token has already been no-listed. origtoken = token if 'jti' not in token and 'token' not in token: token = jwt_utils.decode_token(token) if DBSession.query(JWTNoList).filter( JWTNoList.token == token['jti']).count() > 0: return True return False
def current_user(user_id=None, admin_initial=False, internal_use=False): current_user_id = get_jwt_identity() if not user_id else user_id user = DBSession.query(User).filter(User.id == current_user_id).filter( User.active == True).first() if not user: return 401, "Invalid user (1)", None, None, None, None if not user_id: user_session = DBSession.query(UserSession).filter( UserSession.user_id == user.id).order_by( UserSession.recorded_time.desc()).first() if not user_session and not internal_use: return 403, 'Bad user session (2)', None, None, None, None # TODO: Get user timezone from front end. timezone = 'UTC' return 200, None, user, timezone
def resolve_search(self, info, inbound): """ Get user from JWT token. """ code,error,this_user,timezone = current_user() if code != 200: raise Exception(error) """ Compare it with params. If current user is an admin, allow lookup of other users. """ if inbound: data = graphql_utils.input_to_dictionary(inbound) lookup_user = DBSession.query(UserModel).filter_by(data).first() access_token = request.headers.get(app.config['JWT_HEADER_NAME'],None) #app.logger.info("access token:{0}".format(access_token)) # If latest user session access token doesn't match, kick them out. user_session = DBSession.query(UserSession).filter( UserSession.user_id==user.id).order_by( UserSession.recorded_time.desc()).first() if not user_session: raise Exception('Bad user session') if (user_session.access_token != access_token): TNL.add(access_token) # No. user session may be valid, from a newer login on a different device. #TNL.add(user_session.refresh_token) #TNL.add(user_session.access_token) raise Exception('Access token is invalid') self.result = { 'user_id':user.id,'role':user.role, 'phone':user.phone, 'first_name':user.first_name, 'last_name': user.last_name, 'email':user.email, 'timezone':timezone, 'groups':[], 'username':user.username, } #return result return graphql_utils.json2obj(self.result)
def get_security_code(user_id, reason): if reason not in SECURITY_CODE_REASONS: raise BadSecCodeReason( "Invalid reason id for new security code, failing") code = DBSession.query(OneTimeCode).filter( OneTimeCode.user_id == user_id).filter( OneTimeCode.reason == reason).first() if code: return code.code
def verify_user_totp(user,num_value): totp_record = DBSession.query(OneTimeTOTP).filter( OneTimeTOTP.user_id==user.id).first() if not totp_record: app.logger.warning("User's totp record does not exist:{}".format(user.id)) return False totp = pyotp.TOTP(totp_record.code) result = totp.verify(num_value) #print("TOTP user: {} code:{} num:{} result:{}".format(user.id,totp_record.code,num_value,result)) return result
def resolve_notifications(self, info): code, error, user, timezone = current_user() notifications = [] if user: mediaUsages = [ Notification(type=NotificationType.MEDIA_USAGE, mediaUsage=x) for x in DBSession.query(AssetUsageModel).filter( AssetUsageModel.approved == False).filter( AssetUsageModel.asset.has(owner_id=user.id)).all() ] notifications += mediaUsages return notifications
def mutate(self, info, inbound): data = graphql_utils.input_to_dictionary(inbound) if not data['email'] and data['role'] != GUEST: raise Exception("Email is required!") user = UserModel(**data) user_id = None # Add validation for non-empty passwords, etc. user.password = encrypt(user.password) if not user.role: user.role = PLAYER with ScopedSession() as local_db_session: local_db_session.add(user) local_db_session.flush() user_id = user.id user = DBSession.query(UserModel).filter(UserModel.id==user_id).first() send(user.email, f"Welcome to UpStage!", user_registration(user)) admin_emails = [admin.email for admin in DBSession.query(UserModel).filter(UserModel.role.in_([SUPER_ADMIN,ADMIN])).all()] approval_url = f"{request.url_root}backstage/admin/player-management" send(','.join(admin_emails), f"Approval required for {user.username}'s registration", admin_registration_notification(user, approval_url)) return CreateUser(user=user)
def mutate(self, info, id, name): with ScopedSession() as local_db_session: code, error, user, timezone = current_user() id = from_global_id(id)[1] stage = local_db_session.query(StageModel).filter( StageModel.id == id).first() if stage: local_db_session.expunge(stage) make_transient(stage) original_stage_id = id stage.id = None stage.name = name stage.owner_id = user.id shortname = re.sub('\s+', '-', re.sub('[^A-Za-z0-9 ]+', '', name)).lower() suffix = "" while True: existedStages = DBSession.query(StageModel).filter( StageModel.file_location == f"{shortname}{suffix}").first() if existedStages: suffix = int(suffix or 0) + 1 else: break stage.file_location = f"{shortname}{suffix}" local_db_session.add(stage) local_db_session.flush() new_stage_id = stage.id # Clone media and attributes, player accesses,... for ps in local_db_session.query(ParentStage).filter( ParentStage.stage_id == original_stage_id).all(): local_db_session.add( ParentStage(stage_id=new_stage_id, child_asset_id=ps.child_asset_id)) for attribute in local_db_session.query( StageAttributeModel).filter( StageAttributeModel.stage_id == original_stage_id).all(): local_db_session.add( StageAttributeModel(stage_id=new_stage_id, name=attribute.name, description=attribute.description)) local_db_session.flush() local_db_session.commit() return DuplicateStage(success=True, new_stage_id=to_global_id( 'Stage', new_stage_id)) else: raise Exception("Stage not found!")
def mutate(self, info, input): data = graphql_utils.input_to_dictionary(input) with ScopedSession() as local_db_session: stage = local_db_session.query(StageModel).filter( StageModel.id == data['id']).first() stage.assets.delete() for id in data['media_ids']: stage.assets.append(ParentStage(child_asset_id=id)) local_db_session.commit() stage = DBSession.query(StageModel).filter( StageModel.id == data['id']).first() return AssignMedia(stage=stage)
def verify_security_code(code, activate=False): # Verify that it exists, save history, pass back corresp. user id. code = code.lower().strip() local_db_session = get_scoped_session() result = local_db_session.query(OneTimeCode).filter( OneTimeCode.code == code).first() if not result: local_db_session.commit() local_db_session.close() return user_id = result.user_id hist = OneTimeCodeHistory( user_id=result.user_id, code=result.code, pending_google_login_id=result.pending_google_login_id, pending_facebook_login_id=result.pending_facebook_login_id, pending_apple_login_id=result.pending_apple_login_id, reason=result.reason, ) local_db_session.add(hist) if result.pending_google_login_id: local_db_session.query(GoogleProfile).filter( GoogleProfile.id == result.pending_google_login_id).update( {GoogleProfile.user_id: user_id}, synchronize_session=False) if result.pending_facebook_login_id: local_db_session.query(FacebookProfile).filter( FacebookProfile.id == result.pending_facebook_login_id).update( {FacebookProfile.user_id: user_id}, synchronize_session=False) if result.pending_apple_login_id: local_db_session.query(AppleProfile).filter( AppleProfile.id == result.pending_apple_login_id).update( {AppleProfile.user_id: user_id}, synchronize_session=False) local_db_session.query(OneTimeCode).filter( OneTimeCode.id == result.id).delete(synchronize_session=False) if activate: local_db_session.query(User).filter(User.id == user_id).update( {'active': True}, synchronize_session=False) local_db_session.commit() local_db_session.close() return DBSession.query(User).filter(User.id == user_id).one()
def mutate(self, info, input): if not input.name or not input.file_location: raise Exception('Please fill in all required fields') data = graphql_utils.input_to_dictionary(input) stage = StageModel(**data) stage.owner_id = get_jwt_identity() # Add validation for non-empty passwords, etc. with ScopedSession() as local_db_session: local_db_session.add(stage) local_db_session.flush() stage_id = stage.id local_db_session.commit() stage = DBSession.query(StageModel).filter( StageModel.id == stage_id).first() return CreateStage(stage=stage)
def add(self, token): if 'token' in token: orig_token = copy.deepcopy(token['token']) token_type = token['token']['type'] decoded_token = token['token'] token = token['token']['jti'] elif 'type' in token: orig_token = copy.deepcopy(token) token_type = token['type'] decoded_token = token token = token['jti'] else: orig_token = copy.deepcopy(token) decoded_token = jwt_utils.decode_token(token) token_type = decoded_token['type'] token = decoded_token['jti'] if self.check('x', decoded_token): return # Already restricted. if DBSession.query(JWTNoList).filter(JWTNoList.token == token).first(): return if token_type == 'access': remove_after = datetime.utcnow( ) + app.config['JWT_ACCESS_TOKEN_EXPIRES'] else: remove_after = datetime.utcnow( ) + app.config['JWT_REFRESH_TOKEN_EXPIRES'] with ScopedSession() as local_db_session: TokenNo = JWTNoList( token=token, token_type=token_type, remove_after=remove_after, ) local_db_session.add(TokenNo)
def resolve_privilege(self, info): result = verify_jwt_in_request(True) user_id = get_jwt_identity() if not user_id: return Previlege.NONE if self.owner_id == user_id: return Previlege.OWNER if not self.copyright_level: # no copyright return Previlege.APPROVED if self.copyright_level == 3: # not shared, will not visisble to anyone either, this condidtion is just in case return Previlege.NONE usage = DBSession.query(AssetUsageModel).filter( AssetUsageModel.asset_id == self.id).filter( AssetUsageModel.user_id == user_id).first() if usage: if not usage.approved and self.copyright_level == 2: return Previlege.PENDING_APPROVAL else: return Previlege.APPROVED else: return Previlege.REQUIRE_APPROVAL
def mutate(self, info, id, approved): id = from_global_id(id)[1] with ScopedSession() as local_db_session: asset_usage = local_db_session.query(AssetUsageModel).get(id) asset_id = asset_usage.asset_id if asset_usage: code, error, user, timezone = current_user() if not user.role in (ADMIN, SUPER_ADMIN): if not user.id == asset_usage.asset.owner_id: return ConfirmPermission( success=False, message= "Only media owner or admin can delete this media!") if approved: asset_usage.approved = True asset_usage.seen = True else: local_db_session.delete(asset_usage) local_db_session.flush() permissions = DBSession.query(AssetUsageModel).filter( AssetUsageModel.asset_id == asset_id).all() return ConfirmPermission(success=True, permissions=permissions)
def resolve_voices(self, info): voices = [] for media in DBSession.query(AssetModel).filter( AssetModel.asset_type.has(AssetTypeModel.name == 'avatar')).all(): if media.description: attributes = json.loads(media.description) if 'voice' in attributes: voice = attributes['voice'] if voice and voice['voice']: av = AvatarVoice() av.voice = voice['voice'] av.variant = voice['variant'] for key in ['pitch', 'speed', 'amplitude']: if key in voice: setattr(av, key, int(voice[key])) else: if key == 'speed': setattr(av, key, 175) else: setattr(av, key, 50) voices.append(Voice(avatar=media, voice=av)) return voices
def mutate(self, info, input): data = graphql_utils.input_to_dictionary(input) with ScopedSession() as local_db_session: stage = local_db_session.query(StageModel)\ .filter(StageModel.id == data['id'])\ .first() events = DBSession.query(EventModel)\ .filter(EventModel.performance_id == None)\ .filter(EventModel.topic.like("%/{}/%".format(stage.file_location))) if events.count() > 0: performance = PerformanceModel(stage=stage) local_db_session.add(performance) local_db_session.flush() events.update({EventModel.performance_id: performance.id}, synchronize_session="fetch") else: raise Exception("The stage is already sweeped!") local_db_session.commit() return SweepStage(success=True, performance_id=performance.id)
from user import user, schema from asset import asset from asset.views import assets from licenses.views import licenses from stage import schema from config import schema from studio import schema # Below, duplicate names are actually app names. # See __init__.py in each directory to verify app name. #from apidir import apiname, etc add_signals(app) app.register_blueprint(auth) app.register_blueprint(user) app.register_blueprint(asset) if __name__ == "__main__": # This is used for running two instances locally: one for testing, one to # do async authn while testing locally. This requires two host files, # and explicitly setting HARDCODED_HOSTNAME. try: if RUNFROM_PORT: WSGIServer((FLASK_HOST, RUNFROM_PORT), app).serve_forever() else: WSGIServer((FLASK_HOST, FLASK_PORT), app).serve_forever() finally: DBSession.close()
def resolve_chats(self, info): events = DBSession.query(EventModel)\ .filter(EventModel.topic.like("%/{}/chat".format(self.file_location)))\ .order_by(EventModel.mqtt_timestamp.asc())\ .all() return events