Exemple #1
0
 def __init__(self, app):
     for database in app.config['DATABASES']:
         # We need to have an active request to 'trick' set_database and work with the database we want
         with app.test_request_context('/{}/devices'.format(database)):
             print(('Starting update process for database {}'.format(
                 AccountDomain.get_requested_database())))
             app.auth._set_database(True)
             self.materialize_component_info()
             print(('Database {} successfully updated.'.format(
                 AccountDomain.get_requested_database())))
 def __init__(self, app):
     for database in app.config['DATABASES']:
         # We need to have an active request to 'trick' set_database and work with the database we want
         with app.test_request_context('/{}/devices'.format(database)):
             print('Starting update process for database {}'.format(AccountDomain.get_requested_database()))
             app.auth._set_database(True)
             self.set_prefix()
             self.re_materialize_events()
             self.re_materialize_owners()
             print('Database {} successfully updated.'.format(AccountDomain.get_requested_database()))
Exemple #3
0
def login():
    """
    Performs a login. We make this out of eve, being totally open.
    :return:
    """
    try:
        account = AccountDomain.get_one({'email': request.json['email']})
        if not AccountDomain.verify_password(request.json['password'], account['password']):
            raise WrongCredentials()
        account['token'] = AccountDomain.hash_token(account['token'])
        account['_id'] = str(account['_id'])
        return jsonify(account)
    except (KeyError, TypeError, UserNotFound):
        raise WrongCredentials()
Exemple #4
0
def login():
    """
    Performs a login. We make this out of eve, being totally open.
    :return:
    """
    try:
        account = AccountDomain.get_one({'email': request.json['email']})
        if not AccountDomain.verify_password(request.json['password'],
                                             account['password']):
            raise WrongCredentials()
        account['token'] = AccountDomain.hash_token(account['token'])
        account['_id'] = str(account['_id'])
        return jsonify(account)
    except (KeyError, TypeError, UserNotFound):
        raise WrongCredentials()
Exemple #5
0
def set_organization(deallocates: list):
    for deallocate in deallocates:
        with suppress(
                UserNotFound,
                KeyError):  # todo ensure organization is not always needed
            deallocate['fromOrganization'] = AccountDomain.get_one(
                deallocate['from'])['organization']
Exemple #6
0
 def clean_device(device: dict):
     """Removes values that are not supposed to be sent, like materialized or readonly ones."""
     schema = current_app.config['DOMAIN'][Naming.resource(device['@type'])]['schema']
     _id = device['_id']
     for field in copy.copy(device):
         if '_' in field or not {'materialized', 'readonly'}.isdisjoint(set(schema[field].keys())):
             del device[field]
     device['url'] = DeviceDomain.url_agent_for(AccountDomain.get_requested_database(), _id)
Exemple #7
0
def set_organization(receives: list):
    """
    This method needs to execute after add_or_get_inactive_account
    :param receives:
    :return:
    """
    for receive in receives:
        with suppress(UserNotFound):
            receive['receiverOrganization'] = AccountDomain.get_one(receive['receiver']).get('organization')
Exemple #8
0
def _add_or_get_inactive_account_id(event, field_name):
    """
    We need to execute after insert and insert_resource.
    """
    if field_name in event and type(event[field_name]) is dict:
        try:
            # We look for just accounts that share our database
            _id = AccountDomain.get_one(
                {
                    "email": event[field_name]["email"]
                    # 'databases': {'$in': AccountDomain.actual['databases']} todo review this
                }
            )["_id"]
        except UserNotFound:
            event[field_name]["databases"] = [AccountDomain.get_requested_database()]
            event[field_name]["active"] = False
            event[field_name]["@type"] = "Account"
            _id = execute_post_internal("accounts", event[field_name], True)["_id"]
        event[field_name] = _id
Exemple #9
0
def set_organization(receives: list):
    """
    This method needs to execute after add_or_get_inactive_account
    :param receives:
    :return:
    """
    for receive in receives:
        with suppress(UserNotFound):
            receive['receiverOrganization'] = AccountDomain.get_one(
                receive['receiver']).get('organization')
Exemple #10
0
 def clean_device(device: dict):
     """Removes values that are not supposed to be sent, like materialized or readonly ones."""
     schema = current_app.config['DOMAIN'][Naming.resource(
         device['@type'])]['schema']
     _id = device['_id']
     for field in copy.copy(device):
         if '_' in field or not {'materialized', 'readonly'}.isdisjoint(
                 set(schema[field].keys())):
             del device[field]
     device['url'] = DeviceDomain.url_agent_for(
         AccountDomain.get_requested_database(), _id)
Exemple #11
0
def _add_or_get_inactive_account_id(event, field_name):
    """
    We need to execute after insert and insert_resource.
    """
    if field_name in event and type(event[field_name]) is dict:
        try:
            # We look for just accounts that share our database
            _id = AccountDomain.get_one({
                'email': event[field_name]['email']
                # 'databases': {'$in': AccountDomain.actual['databases']} todo review this
            })['_id']
        except UserNotFound:
            event[field_name]['databases'] = [
                AccountDomain.get_requested_database()
            ]
            event[field_name]['active'] = False
            event[field_name]['@type'] = 'Account'
            _id = execute_post_internal('accounts', event[field_name],
                                        True)['_id']
        event[field_name] = _id
Exemple #12
0
 def create_self_machine_account(self):
     email, password = self.app.config['AGENT_ACCOUNTS']['self']
     self.db.accounts.insert(
         {
             'role': 'superuser',
             'token': 'QYADFBPNZZDFJEWAFGGF',
             'databases': self.app.config['DATABASES'],
             '@type': 'Account',
             'email': email,
             'password': AccountDomain.encrypt_password(password)
         }
     )
Exemple #13
0
 def get_device(self, device_id: str) -> dict:
     """Gets the device ready to be sent to another database."""
     # It is just so easy to load stuff (through permissions, etc) through Python-Eve's API
     embedded = json.dumps({'components': 1})
     projection = json.dumps({'events': 0})
     token = AccountDomain.hash_token(AccountDomain.actual_token)
     url = '{}/devices/{}?embedded={}&projection={}'.format(self.database, device_id, embedded, projection)
     device = execute_get(url, token)
     self.clean_device(device)
     for component in device.get('components', []):
         self.clean_device(component)
     return device
Exemple #14
0
 def get_device(self, device_id: str) -> dict:
     """Gets the device ready to be sent to another database."""
     # It is just so easy to load stuff (through permissions, etc) through Python-Eve's API
     embedded = json.dumps({'components': 1})
     projection = json.dumps({'events': 0})
     token = AccountDomain.hash_token(AccountDomain.actual_token)
     url = '{}/devices/{}?embedded={}&projection={}'.format(
         self.database, device_id, embedded, projection)
     device = execute_get(url, token)
     self.clean_device(device)
     for component in device.get('components', []):
         self.clean_device(component)
     return device
Exemple #15
0
 def create_dummy_user(self):
     self.db.accounts.insert(
         {
             'email': "[email protected]",
             'password': AccountDomain.encrypt_password('1234'),
             'role': 'admin',
             'token': 'NOFATDNNUB',
             'databases': self.app.config['DATABASES'],
             'defaultDatabase': self.app.config['DATABASES'][0],
             '@type': 'Account'
         }
     )
     self.account = self.db.accounts.find_one({'email': '[email protected]'})
Exemple #16
0
def create_account(email: str, password: str, databases: list,
                   role: str = None, name: str = None, organization: str = None, blocked: bool = False,
                   default_database: str = None, mongo_host: str = None, mongo_port: int = None,
                   db_name: str = 'dh__accounts'):
    """
    Creates an account. You can call the file directly::

        create_account.py [email protected] 123 [\'db1\'] superuser

    :param email:
    :param password:
    :param databases: The databases the user has access to
    :param mongo_host: Leave empty to use default.
    :param mongo_port: Leave empty to use default.
    :param db_name: The name of the database to create the account to. Leave empty to use default.
    :param default_database: if none we use the first database of *databases*.
    :param role: the role of the user, if none, we use the default set in Account type.
    :param name:
    :param organization:
    :param blocked: False if it is not set
    :throws UserAlreadyExists:
    :return: The account with the *base256* token and *hashed* password.
    """
    connection = MongoClient(mongo_host, mongo_port)
    db = connection[db_name]
    if db.accounts.find_one({'email': email}):
        raise UserAlreadyExists()
    account = {
        'email': email,
        'password': password,
        'databases': databases,
        'defaultDatabase': default_database or databases[0],
        '@type': 'Account',
        'blocked': eval(blocked) if type(blocked) is str else blocked,
        'active': True
    }
    if role is not None:
        account['role'] = role
    if name is not None:
        account['name'] = name
    if organization is not None:
        account['organization'] = organization
    token = generate_token()
    while db.accounts.find_one({'token': token}) is not None:
        token = generate_token()
    account["token"] = token
    hash_password([account])
    db.accounts.insert(account)
    returned_account = db.accounts.find_one({'email': email})
    return returned_account, AccountDomain.hash_token(returned_account['token'])
Exemple #17
0
def export(db, resource):
    try:
        file_type = FILE_TYPE_MIME_TABLE[request.accept_mimetypes.best]
    except KeyError:
        raise NotAcceptable()
    ids = request.args.getlist('ids')
    token = AccountDomain.hash_token(AccountDomain.actual_token)
    group_by = request.args.get('groupBy')
    default_group = request.args.get('defaultGroup', 'Others')
    embedded = {'byUser': 1, 'events': 1, 'components': 1, 'place': 1, 'owners': 1}
    translator = SpreadsheetTranslator(current_app.config, group_by=group_by, default_group=default_group)
    exporter = Exporter(translator, embedded, token)
    spreadsheets, _ = exporter.export(ids, db, resource)[0]
    return excel.make_response_from_book_dict(spreadsheets, file_type, file_name=resource)
    def generate_returned_same_as(self):
        """
        Populates self.returned_same_as with a dict where the URL of devices in the caller agent as keys and a copy of
        'sameAs' in this agent.

        This value will be returned to the caller agent (see
        :py:func:`ereuse_devicehub.resources.event.device.migrate.hooks.return_same_as`) which can use it to update
        its 'sameAs' values with new references.
        """
        for device, url in zip([self.device] + self.components, self.urls):
            device = DeviceDomain.get_one(device['_id'])
            same_as = set(device['sameAs'])
            same_as.remove(url)
            same_as.add(
                DeviceDomain.url_agent_for(
                    AccountDomain.get_requested_database(), device['_id']))
            self.returned_same_as[url] = list(same_as)
Exemple #19
0
def submit_migrate(migrates: dict):
    """
    Sends a Migrate event to the other DeviceHub.
    Note as the other DeviceHub requires the url of this event,
    this method needs to be executed after reaching the Database.
    """
    for migrate in migrates:
        if 'to' in migrate:
            auth = AgentAuth(migrate['to']['baseUrl'])
            submitter = MigrateSubmitter(current_app, MigrateTranslator(current_app.config), auth=auth)
            try:
                response, *_ = submitter.submit(migrate, AccountDomain.get_requested_database())
                migrate['to']['url'] = migrate['to']['baseUrl'] + response['_links']['self']['href']
                _update_same_as(response['returnedSameAs'])
            except InnerRequestError as e:
                execute_delete(Migrate.resource_name, migrate['_id'])
                raise e
            else:
                _remove_devices_from_places(migrate)
                update = {'$set': {'to.url': migrate['to']['url'], 'devices': [_id for _id in migrate['devices']]}}
                DeviceEventDomain.update_one_raw(migrate['_id'], update)
Exemple #20
0
def submit_migrate(migrates: dict):
    """
    Sends a Migrate event to the other DeviceHub.
    Note as the other DeviceHub requires the url of this event,
    this method needs to be executed after reaching the Database.
    """
    for migrate in migrates:
        if 'to' in migrate:
            auth = AgentAuth(migrate['to']['baseUrl'])
            submitter = MigrateSubmitter(current_app, MigrateTranslator(current_app.config), auth=auth)
            try:
                response, *_ = submitter.submit(migrate, AccountDomain.get_requested_database())
                migrate['to']['url'] = migrate['to']['baseUrl'] + response['_links']['self']['href']
                _update_same_as(response['returnedSameAs'])
            except InnerRequestError as e:
                execute_delete(Migrate.resource_name, migrate['_id'])
                raise e
            else:
                _remove_devices_from_places(migrate)
                update = {'$set': {'to.url': migrate['to']['url'], 'devices': [_id for _id in migrate['devices']]}}
                DeviceEventDomain.update_one_raw(migrate['_id'], update)
Exemple #21
0
 def _set_database(self, force: bool = False):
     """
     Sets the actual database according of the value in the URL.
     :param force: Sets the database even if the user has no access to it
     :raises NotADatabase: When the URL is malformed or doesn't contain an existing database
     :raises UnauthorizedToUseDatabase: If force is true this won't raise
     """
     try:
         requested_database = AccountDomain.get_requested_database()
     except NotADatabase as e:
         try:
             if e.body['requested_path'] not in current_app.config['RESOURCES_NOT_USING_DATABASES'] \
                     and not current_app.config['DOMAIN'][e.body['requested_path']]['use_default_database']:
                 raise e
         except KeyError:
             raise e
     else:
         if force or (requested_database in AccountDomain.actual['databases']
                      or AccountDomain.actual['role'] == Role.SUPERUSER):
             self.set_mongo_prefix(requested_database.replace("-", "").upper())
         else:
             raise UnauthorizedToUseDatabase()
Exemple #22
0
def export(db, resource):
    try:
        file_type = FILE_TYPE_MIME_TABLE[request.accept_mimetypes.best]
    except KeyError:
        raise NotAcceptable()
    ids = request.args.getlist('ids')
    token = AccountDomain.hash_token(AccountDomain.actual_token)
    group_by = request.args.get('groupBy')
    default_group = request.args.get('defaultGroup', 'Others')
    embedded = {
        'byUser': 1,
        'events': 1,
        'components': 1,
        'place': 1,
        'owners': 1
    }
    translator = SpreadsheetTranslator(current_app.config,
                                       group_by=group_by,
                                       default_group=default_group)
    exporter = Exporter(translator, embedded, token)
    spreadsheets, _ = exporter.export(ids, db, resource)[0]
    return excel.make_response_from_book_dict(spreadsheets,
                                              file_type,
                                              file_name=resource)
Exemple #23
0
def set_organization(deallocates: list):
    for deallocate in deallocates:
        with suppress(UserNotFound, KeyError):  # todo ensure organization is not always needed
            deallocate['fromOrganization'] = AccountDomain.get_one(deallocate['from'])['organization']
Exemple #24
0
 def set_superuser(self):
     with self.app.app_context():
         AccountDomain.update_raw(self.account['_id'], {'$set': {'role': 'superuser'}})
Exemple #25
0
def set_organization(allocates: list):
    for allocate in allocates:
        with suppress(UserNotFound, KeyError):
            allocate['toOrganization'] = AccountDomain.get_one(
                allocate['to'])['organization']
Exemple #26
0
def create_account(
    email: str,
    password: str,
    databases: list,
    role: str = None,
    name: str = None,
    organization: str = None,
    blocked: bool = False,
    default_database: str = None,
    mongo_host: str = None,
    mongo_port: int = None,
    db_name: str = "dh__accounts",
):
    """
    Creates an account. You can call the file directly::

        create_account.py [email protected] 123 [\'db1\'] superuser

    :param email:
    :param password:
    :param databases: The databases the user has access to
    :param mongo_host: Leave empty to use default.
    :param mongo_port: Leave empty to use default.
    :param db_name: The name of the database to create the account to. Leave empty to use default.
    :param default_database: if none we use the first database of *databases*.
    :param role: the role of the user, if none, we use the default set in Account type.
    :param name:
    :param organization:
    :param blocked: False if it is not set
    :throws UserAlreadyExists:
    :return: The account with the *base256* token and *hashed* password.
    """
    connection = MongoClient(mongo_host, mongo_port)
    db = connection[db_name]
    if db.accounts.find_one({"email": email}):
        raise UserAlreadyExists()
    databases = eval(databases)
    if type(databases) is not list:
        raise TypeError("databases has to be a list")
    account = {
        "email": email,
        "password": password,
        "databases": databases,
        "defaultDatabase": default_database or databases[0],
        "@type": "Account",
        "blocked": eval(blocked) if type(blocked) is str else blocked,
        "active": True,
    }
    if role is not None:
        account["role"] = role
    if name is not None:
        account["name"] = name
    if organization is not None:
        account["organization"] = organization
    token = generate_token()
    while db.accounts.find_one({"token": token}) is not None:
        token = generate_token()
    account["token"] = token
    hash_password([account])
    db.accounts.insert(account)
    returned_account = db.accounts.find_one({"email": email})
    return returned_account, AccountDomain.hash_token(returned_account["token"])
Exemple #27
0
def set_organization(allocates: list):
    for allocate in allocates:
        with suppress(UserNotFound, KeyError):
            allocate['toOrganization'] = AccountDomain.get_one(allocate['to'])['organization']