예제 #1
0
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)
예제 #2
0
 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
예제 #3
0
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)
예제 #4
0
    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)
예제 #5
0
    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)
예제 #6
0
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)
예제 #7
0
    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)
예제 #8
0
    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)
예제 #9
0
 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
예제 #10
0
 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
예제 #11
0
    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)
예제 #12
0
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)
예제 #13
0
    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
예제 #14
0
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
예제 #15
0
    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)
예제 #16
0
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
예제 #17
0
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
예제 #18
0
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
예제 #19
0
    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)
예제 #20
0
    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!")
예제 #21
0
    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)
예제 #22
0
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()
예제 #23
0
    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)
예제 #24
0
    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)
예제 #25
0
 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
예제 #26
0
 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)
예제 #27
0
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
예제 #28
0
    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)
예제 #29
0
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()
예제 #30
0
 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