示例#1
0
def project_author_set_listener(project: Project, author: User,
                                old_author: User, initiator: attributes.Event):
    author.projects.append(project)
    if old_author not in [NEVER_SET, NO_VALUE]:
        old_author.projects.remove(project)
    log.debug(
        f'{author.email}\'s own project "{project.name}" added also to her full list of projects'
    )
示例#2
0
 def private_key(self):
     """
     For lazy loading so we can set key's files beforehand
     """
     if not self._private_key:
         log.debug(
             f'Loading private key from {settings.config.jwt_secret_key_file}'
         )
         self._private_key = open(settings.config.jwt_secret_key_file,
                                  'rb').read()
     return self._private_key
示例#3
0
 def decode(self, encoded: str) -> dict:
     try:
         decoded = jwt.decode(
             encoded,
             self.public_key,
             algorithms='RS256',
         )
     except PyJWTError as e:
         decoded = None
         log.debug(f'Decode error for jwt "{encoded}": {e}')
     return decoded
示例#4
0
def users_list(auth_user: AuthUser,
               email: str = None,
               per_page: int = PER_PAGE_DEFAULT,
               page: int = PAGE_DEFAULT,
               order_by=DEFAULT_ORDER_BY):
    """
    Users list
    """
    order_by_options = {
        'createddatetime': {
            'field': 'createdDatetime',
            'model': db.models.User
        },
        'email': {
            'field': 'email',
            'model': db.models.User
        },
    }
    if not auth_user.is_admin:
        return 'Only admin can get list of users', HttpCode.unauthorized
    pager = Paging(dict(page=page, per_page=per_page))
    pager.validate()
    if order_by.strip() == '':
        order_by = DEFAULT_ORDER_BY
    if order_by[0] == '-':
        order_by = order_by[1:]
        sort_dir = 'desc'
    if order_by[0] == '+':
        order_by = order_by[1:]
    if order_by.lower() not in order_by_options:
        raise APIError(
            f'Wrong order by option "{order_by}". Possible options for order by: {", ".join([key for key in order_by_options.keys()])}'
        )
    sort_by = order_by_options[order_by.lower()]
    order_by = getattr(getattr(sort_by['model'], sort_by['field']), sort_dir)()
    if email:
        users = [db.models.User.by_email(email, check=False)]
        if users[0] is None:
            users = []
        total = len(users)
    else:
        users = db.models.User.query().order_by(order_by)
        total = users.count()
        users = users.limit(pager.per_page).offset(
            (pager.page - 1) * pager.per_page)
    # db.session..query(db.models.User).from_statement(
    #     text("SELECT * FROM users where name=:name")).\
    #     params(name='john').all()
    result = []
    for user in users:
        result.append(controllers.models.UserShort().from_orm(user).as_dict)
    log.debug(f'List of users: {[user["email"] for user in result]}')
    return {'data': result, 'total': total}
示例#5
0
 def wrapper(*args, **kwargs):
     if kwargs['Authorization'] is not None:
         token_tokens = kwargs['Authorization'].split(" ")
         token_value = token_tokens[1] if len(
             token_tokens) > 1 else token_tokens[0]
         kwargs.update({'auth_token': token.decode(token_value)})
     del kwargs['Authorization']
     result = handler(*args, **kwargs)
     if result[1] != 200:
         log.debug(f'Error response: {result}')
         return Response(result[0], result[1])
     return result[0]
示例#6
0
 def by_id(cls, id, check=True):
     """
     Find object by ID.
     If `check` then raise exception if not found.
     """
     result = cls.query().filter(cls.id == id).first()
     if not result:
         if check:
             raise APIError(f'There is no {cls.__name__} with id="{id}"')
         else:
             log.debug(f'{cls.__name__} with id="{id}" was not found')
     return result
示例#7
0
 def public_key(self):
     """
     For lazy loading so we can set key's files beforehand
     """
     if not self._public_key:
         log.debug(
             f'Loading public key from {settings.config.jwt_public_key_file}'
         )
         cert_str = open(settings.config.jwt_public_key_file, 'rb').read()
         cert_obj = load_pem_x509_certificate(cert_str, default_backend())
         self._public_key = cert_obj.public_key()
     return self._public_key
示例#8
0
def options_handler():
    """
    Handles only unspecified below paths.
    Others handles by application logic and CORS headers added in after-request flask hook
    So I this this is unecessary part but I am too lazy to check..
    """
    log.debug(f'Options were requested for {request.full_path}')
    response = Response()
    response.headers['Content-Type'] = 'text/plain; charset=utf-8'
    response.status_code = 204
    if settings.config.web_enableCrossOriginRequests:
        response.headers['Access-Control-Max-Age'] = 1728000
    return response
示例#9
0
def test_delete_fail(user_id, admin_token):
    """
    Tries to delete user in empty DB.
    """
    data = api.users_list(admin_token)
    log.debug('empty db users ' + str(data))
    existed_users = set()
    for user in data:
        existed_users.add(user['id'])
    log.debug('existed id ' + str(existed_users))
    while str(user_id) in existed_users:
        user_id += 1
    api.delete_user(admin_token, user_id, expected_statuses=[400])
示例#10
0
 def by_email(email, check=True):
     """
     Find user by email.
     If `check` then raise exception if not found.
     """
     user = User.query().filter(
         func.lower(db.models.User.email) == email.lower()).first()
     if not user:
         if check:
             raise APIError(f'There is no user with email "{email}"')
         else:
             log.debug(f'User with email "{email}" was not found')
     return user
示例#11
0
 def token_to_auth_user_wrapper(*args, **kwargs):
     if 'auth_token' in kwargs:
         if kwargs['auth_token'] is not None:
             log.debug(f'Add auth_user to {handler.__name__}\n{kwargs["auth_token"]}')
             auth_user = AuthUser(kwargs['auth_token'])
             args = (auth_user, ) + args
             journaling.user = auth_user.email
         else:
             log.warning('No or wrong user token in request')
             return 'No or wrong user token in request', HttpCode.no_token
         del kwargs['auth_token']
     try:
         return handler(*args, **kwargs)
     finally:
         journaling.user = None
示例#12
0
def make_session():
    global session
    global engine
    log.debug(f'...Connecting to DB {settings.config.db_uri}...')
    engine = create_engine(settings.config.db_uri,
                           echo=settings.config.db_sqltrace)

    session = scoped_session(sessionmaker(bind=engine))  # ()
    Base.metadata.bind = engine
    if settings.config.db_autometa:
        refresh_metadata()
    create_admin_user()
    session.close()
    session.get_bind().dispose()
    log.debug('Connections dropped after creating meta-data')
    return session
示例#13
0
def delete_user(auth_user: AuthUser, user_id: str):
    """
    Deletes user.
    Returns deleted user id.
    """
    if not auth_user.is_admin:
        return 'Only admin can delete users', HttpCode.unauthorized
    user_to_delete = db.models.User.by_id(user_id, check=False)
    if user_to_delete:
        log.debug(f'Deletion of user with id={user_id}')
        db.conn.session.delete(user_to_delete)
        db.conn.session.commit()
        return {}
    else:
        log.debug(f'No user with id={user_id}')
        return f'No user with id={user_id}', HttpCode.logic_error
示例#14
0
def create_user(auth_user: AuthUser, new_user: NewUser):
    """
    Creates user.
    Returns new user id.
    """
    if not auth_user.is_admin:
        return 'Only admin can create users', HttpCode.unauthorized
    new_user = NewUser(new_user)
    new_user.validate()
    user = db.models.User.by_email(new_user.email, check=False)
    if user:
        return f'User with email="{new_user["email"]}" already exists', HttpCode.logic_error
    db_user = db.models.User(**new_user.to_orm)
    db.conn.session.add(db_user)
    db.conn.session.commit()
    log.debug(f'Created user: [{db_user}]')
    return {'id': db_user.id}
示例#15
0
    def api_wrapper(*args, **kwargs):
        try:
            if bparams:
                body_obj = request.get_json()
                for param in bparams:
                    if isinstance(body_obj, dict) and param in body_obj:
                        val = body_obj[param]
                    else:
                        if len(bparams) == 1:
                            val = body_obj
                        else:
                            log.debug(
                                f'No parameter {param} in request:\n{request.data} ({body_obj})'
                            )
                            return f'No parameter {param} in request:\n{request.data}', HttpCode.wrong_request
                    kwargs.update({param: val})
            if request.args:
                for param in request.args:
                    kwargs.update({param: request.args[param]})

            # should be last so nothing could inject decoded token
            log.debug(
                f'API wraps handler with args: {inspect.getfullargspec(handler).args}'
            )
            # if 'auth_user' in inspect.getfullargspec(handler).args:
            """
            If the handler expects authenticated user (has 'auth_user' param), we pass token to it. 
            Controller's wrapper (@auth_user) will convert token into auth_user param for the handler.

            Here is transport layer so we just pass decoded token data to controller's logic.
            """
            kwargs.update({'auth_token': auth_token()})

            result = handler(*args, **kwargs)

        except APPNoTokenError as e:
            log.debug(f'Wrong token format: {e}', exc_info=True)
            result = {'status': str(e)}, HttpCode.no_token
        except Exception as e:
            log.debug(f'Transport exception: {e}', exc_info=True)
            result = {'status': str(e)}, HttpCode.wrong_request
        else:
            if raw:  # Only if success, if exception we return API error
                return result
        if isinstance(result, tuple):
            code = result[1]
            result = result[0]
        else:
            code = HttpCode.success
        if code not in HttpCode.successes and isinstance(result, str):
            result = {'status': result}
        return result, code
示例#16
0
def refresh_metadata():
    log.debug('Refreshing metadata...')
    insp = reflection.Inspector.from_engine(session().get_bind())
    table_names = insp.get_table_names()
    if 'users' not in table_names:
        log.info('Use alchemy to create meta DB')
        Base.metadata.create_all(session().get_bind())
    else:
        log.info('Use alembic to upgrade meta DB')

        # In fact settings.config is not None only for test
        alembic_root = 'src/' if isinstance(settings.config,
                                            settings.ConfigTest) else ''

        alembic_cfg = alembic.config.Config(f'{alembic_root}alembic.ini')
        alembic_cfg.set_main_option('script_location',
                                    f'{alembic_root}alembic')
        alembic_cfg.set_main_option('sqlalchemy.url', settings.config.db_uri)
        with session().get_bind().begin() as connection:
            alembic_cfg.attributes['connection'] = connection
            alembic.command.upgrade(alembic_cfg, 'head', sql=False)
示例#17
0
def create_admin_user():
    """
    Creates default admin if no users with admin right are in DB
    """
    # if session.info.get('has_flushed', False):
    users = db.models.User.query().filter(
        db.models.User.group == controllers.models.UserGroup.ADMIN)
    if not users.count():
        log.debug('!' * 25 + f"""
Creating default admin user <{settings.config.default_admin_email}> with
password '{settings.config.default_admin_password}' - please change her password
""" + '!' * 25)
        admin_user = db.models.User(
            email=settings.config.default_admin_email,
            password=settings.config.default_admin_password,
            group=controllers.models.UserGroup.ADMIN)
        session.add(admin_user)
        session.commit()
    else:
        log.debug(
            f'In db found users with admin roles: {", ".join([user.email for user in users])}'
        )
示例#18
0
def get_token(email: str, password: str, auth_token=None):  #todo: remove auth_token
    """
    Returns JWT for the email/password.
    """
    user = db.models.User.by_email(email)
    if not user:
        log.debug(f'No user with email={email}')
        raise APILogicError(f'No user with email={email}')
    if not password_hash.verify(password, user.password_hash):
        log.debug(f'Invalid email/password for user {email}')
        raise APIUnauthError(f'Invalid email/password for user {email}')
    log.debug(f'Issuing JWT for {email}')
    payload = {
        JWT_EXPIRATION: token.datetime2jwt(settings.config.now() + settings.config.token_expiration_delta),
        JWT_CREATED: token.datetime2jwt(settings.config.now()),
        JWT_EMAIL: user.email,
        JWT_GROUP: user.group.value
    }
    assert '.' not in payload['exp']
    return {'token': token.encode(payload)}