def test_add_user_to_team(self): param1 = TestCrossEnterpriseCommands.params1 # type: KeeperParams param2 = TestCrossEnterpriseCommands.params2 # type: KeeperParams users = [ x for x in param2.enterprise['users'] if x['username'] != param2.user ] self.assertGreater(len(users), 0, 'cannot resolve user') user = users[0] ent2_user_id = user['enterprise_user_id'] cmd = EnterpriseUserCommand() pk = cmd.get_public_key(param2, user['username']) #real team uids = [] if 'teams' in param1.enterprise: uids = [x['team_uid'] for x in param1.enterprise['teams']] team_cmd = EnterpriseTeamCommand() if len(uids) == 0: team_cmd.execute(param1, add=True, team=['Team1']) uids = [x['team_uid'] for x in param1.enterprise['teams']] self.assertGreater(len(uids), 0, 'cannot resolve team') ent1_team_uid = uids[0] team_key = team_cmd.get_team_key(param1, ent1_team_uid) self.assertIsNotNone(team_key) rq = { "command": "team_enterprise_user_add", "team_uid": ent1_team_uid, "enterprise_user_id": ent2_user_id, "user_type": 0, "team_key": api.encrypt_rsa(team_key, pk) } failed = False try: api.communicate(param1, rq) except KeeperApiError as err: failed = True self.assertEqual(err.result_code, "bad_inputs_enterprise_user_id") self.assertTrue(failed) failed = False try: api.communicate(param2, rq) except KeeperApiError as err: failed = True self.assertEqual(err.result_code, "access_denied") self.assertTrue(failed) rq = {"command": "team_delete", "team_uid": ent1_team_uid} failed = False try: api.communicate(param2, rq) except KeeperApiError as err: failed = True self.assertEqual(err.result_code, "access_denied") self.assertTrue(failed)
def register_record(record, key_type=None): # type: (record.Record, Optional[int]) -> bytes data = { 'title': record.title or '', 'secret1': record.login or '', 'secret2': record.password or '', 'link': record.login_url or '', 'notes': record.notes or '', 'custom': record.custom_fields or '', 'folder': record.folder or '' } extra = None udata = None if record.attachments: extra = { 'files': record.attachments } udata = { 'file_id': [x['id'] for x in record.attachments] } record_key = api.generate_aes_key() if key_type != 0 else _USER_DATA_KEY rec_object = { 'record_uid': record.record_uid, 'revision': record.revision if (0 < record.revision <= _REVISION) else _REVISION, 'version': 2 if key_type != 0 else 1, 'shared': key_type not in [0, 1], 'data': api.encrypt_aes(json.dumps(data).encode('utf-8'), record_key), } if extra: rec_object['extra'] = api.encrypt_aes(json.dumps(extra).encode('utf-8'), record_key) if udata: rec_object['udata'] = udata _RECORDS.append(rec_object) meta_data = { 'record_uid': record.record_uid, 'owner': key_type in [0, 1], 'can_share': key_type == 1, 'can_edit': key_type == 1, 'record_key_type': key_type } if key_type == 0: _RECORD_METADATA.append(meta_data) if key_type == 1: meta_data['record_key'] = api.encrypt_aes(record_key, _USER_DATA_KEY) _RECORD_METADATA.append(meta_data) elif key_type == 2: meta_data['record_key'] = api.encrypt_rsa(record_key, _IMPORTED_PUBLIC_KEY) _RECORD_METADATA.append(meta_data) return record_key
def register_team(team, key_type, sfs=None): # type: (team.Team, int, dict) -> bytes team_key = api.generate_aes_key() t = { 'team_uid': team.team_uid, 'name': team.name, 'team_key_type': key_type, 'team_key': api.encrypt_aes(team_key, _USER_DATA_KEY) if key_type == 1 else api.encrypt_rsa(team_key, _IMPORTED_PUBLIC_KEY), 'team_private_key': api.encrypt_aes(_DER_PRIVATE_KEY, team_key), 'restrict_edit': team.restrict_edit, 'restrict_share': team.restrict_share, 'restrict_view': team.restrict_view, } _TEAMS.append(t) if sfs: t['shared_folder_keys'] = [{ 'shared_folder_uid': x[0], 'key_type': 1, 'shared_folder_key': api.encrypt_aes(x[1], team_key) } for x in sfs.items()] sf_uids = set() for uid in sfs: sf_uids.add(uid) for sf in _SHARED_FOLDERS: if sf['shared_folder_uid'] in sf_uids: if 'teams' not in sf: sf['teams'] = [] sf['teams'].append({ 'team_uid': team.team_uid, 'name': team.name, 'manage_records': key_type == 1, 'manage_users': key_type == 1 }) return team_key
def prepare_folder_permission(params, folders): # type: (KeeperParams, list) -> list shared_folder_lookup = {} for shared_folder_uid in params.shared_folder_cache: path = get_folder_path(params, shared_folder_uid) if path: shared_folder_lookup[path] = shared_folder_uid email_pattern = re.compile(EMAIL_PATTERN) emails = set() teams = set() for fol in folders: if fol.permissions: for perm in fol.permissions: if perm.uid: teams.add(perm.uid) if perm.name: teams.add(perm.name) elif perm.name: match = email_pattern.match(perm.name) if match: if perm.name != params.user: emails.add(perm.name.lower()) else: teams.add(perm.name) if len(emails) > 0: api.load_user_public_keys(params, list(emails)) if len(teams) > 0: api.load_available_teams(params) team_uids = set() for t in teams: team_uid = next( (x.get('team_uid') for x in params.available_team_cache if x.get('team_uid') == t or x.get('team_name').casefold() == t.casefold()), None) if team_uid: team_uids.add(team_uid) if len(team_uids) > 0: api.load_team_keys(params, list(team_uids)) folder_permissions = [] for fol in folders: shared_folder_uid = shared_folder_lookup.get(fol.path) if not shared_folder_uid: continue shared_folder = params.shared_folder_cache.get(shared_folder_uid) if not shared_folder: continue shared_folder_key = shared_folder.get('shared_folder_key_unencrypted') if not shared_folder_key: continue if fol.permissions: add_users = [] add_teams = [] for perm in fol.permissions: try: if perm.uid: if perm.uid in params.key_cache: team_key = params.key_cache[perm.uid] rq = { 'team_uid': perm.uid, 'manage_users': perm.manage_users, 'manage_records': perm.manage_records, } if type(team_key) == bytes: rq['shared_folder_key'] = api.encrypt_aes( shared_folder_key, team_key) else: rq['shared_folder_key'] = api.encrypt_rsa( shared_folder_key, team_key) add_teams.append(rq) continue if perm.name: name = perm.name.casefold() if name in params.key_cache: rsa_key = params.key_cache[name] rq = { 'username': name, 'manage_users': perm.manage_users, 'manage_records': perm.manage_records, 'shared_folder_key': api.encrypt_rsa(shared_folder_key, rsa_key) } add_users.append(rq) continue team_uid = next( (x.get('team_uid') for x in params.available_team_cache if x.get('team_name').casefold() == name), None) if team_uid in params.key_cache: team_key = params.key_cache[team_uid] rq = { 'team_uid': team_uid, 'manage_users': perm.manage_users, 'manage_records': perm.manage_records, } if type(team_key) == bytes: rq['shared_folder_key'] = api.encrypt_aes( shared_folder_key, team_key) else: rq['shared_folder_key'] = api.encrypt_rsa( shared_folder_key, team_key) add_teams.append(rq) continue except Exception as e: logging.debug(e) if add_teams or add_users: request = { 'command': 'shared_folder_update', 'operation': 'update', 'pt': 'Commander', 'shared_folder_uid': shared_folder_uid, 'force_update': True, 'add_teams': add_teams, 'add_users': add_users, } folder_permissions.append(request) return folder_permissions
def prepare_shared_folder_add(params, folders): folder_hash = {} for f_uid in params.folder_cache: fol = params.folder_cache[f_uid] h = hashlib.md5() hs = '{0}|{1}'.format((fol.name or '').lower(), fol.parent_uid or '') h.update(hs.encode()) shared_folder_key = None if fol.type in { BaseFolderNode.SharedFolderType, BaseFolderNode.SharedFolderFolderType }: sf_uid = fol.shared_folder_uid if fol.type == BaseFolderNode.SharedFolderFolderType else fol.uid if sf_uid in params.shared_folder_cache: shared_folder_key = params.shared_folder_cache[sf_uid][ 'shared_folder_key_unencrypted'] folder_hash[h.hexdigest()] = f_uid, fol.type, shared_folder_key # public keys emails = {} for fol in folders: if fol.permissions: for perm in fol.permissions: if perm.name not in emails: _, email = parseaddr(perm.name) if email: if email != params.user: emails[email.lower()] = None if emails: request = {'command': "public_keys", 'key_owners': list(emails.keys())} try: rs = api.communicate(params, request) if 'public_keys' in rs: for pk in rs['public_keys']: if 'public_key' in pk: emails[pk['key_owner']] = pk['public_key'] except Exception as e: logging.debug(e) shared_folder_add = [] for fol in folders: skip_folder = False parent_uid = '' parent_type = '' parent_key = None comps = list(path_components(fol.path)) for i in range(len(comps)): comp = comps[i] h = hashlib.md5() hs = '{0}|{1}'.format(comp.lower(), parent_uid) h.update(hs.encode()) digest = h.hexdigest() is_last = False if i == len(comps) - 1: is_last = True if digest not in folder_hash: folder_uid = api.generate_record_uid() request = {'command': 'folder_add', 'folder_uid': folder_uid} folder_type = 'shared_folder' if is_last else 'user_folder' request['folder_type'] = folder_type encryption_key = params.data_key folder_key = os.urandom(32) request['key'] = api.encrypt_aes(folder_key, encryption_key) if parent_uid: request['parent_uid'] = parent_uid if folder_type == 'shared_folder': request['name'] = api.encrypt_aes(comp.encode('utf-8'), folder_key) data = {'name': comp} request['data'] = api.encrypt_aes( json.dumps(data).encode('utf-8'), folder_key) shared_folder_add.append(request) parent_uid = folder_uid parent_type = folder_type parent_key = folder_key folder_hash[ digest] = folder_uid, folder_type, folder_key if folder_type == 'shared_folder' else None else: parent_uid, parent_type, parent_key = folder_hash[digest] if is_last: skip_folder = parent_type != 'shared_folder' else: skip_folder = parent_type != 'user_folder' if skip_folder: break if not skip_folder and parent_type == 'shared_folder': request = { 'command': 'shared_folder_update', 'operation': 'update', 'pt': 'Commander', 'shared_folder_uid': parent_uid, 'force_update': True, 'default_manage_users': fol.manage_users, 'default_manage_records': fol.manage_records, 'default_can_edit': fol.can_edit, 'default_can_share': fol.can_share } if fol.permissions: for perm in fol.permissions: is_team = False if perm.uid and params.team_cache: is_team = perm.uid in params.team_cache else: _, email = parseaddr(perm.name) if not email: is_team = True if is_team: perm.uid = None for team in params.team_cache: if team['name'].lower() == perm.name.lower(): perm.uid = team['team_uid'] break if is_team: if perm.uid and perm.uid in params.team_cache: if 'add_teams' not in request: request['add_teams'] = [] team = params.team_cache[perm.uid] request['add_teams'].append({ 'team_uid': perm.uid, 'manage_users': perm.manage_users, 'manage_records': perm.manage_records, 'shared_folder_key': api.encrypt_aes(parent_key, team['team_key']) }) else: if 'add_users' not in request: request['add_users'] = [] email = perm.name.lower() if email == params.user.lower(): request['add_users'].append({ 'username': email, 'manage_users': perm.manage_users, 'manage_records': perm.manage_records, 'shared_folder_key': api.encrypt_aes(parent_key, params.data_key) }) elif email in emails: public_key = emails[email] if public_key: try: rsa_key = RSA.importKey( base64.urlsafe_b64decode(public_key + '==')) request['add_users'].append({ 'username': email, 'manage_users': perm.manage_users, 'manage_records': perm.manage_records, 'shared_folder_key': api.encrypt_rsa(parent_key, rsa_key) }) except: pass shared_folder_add.append(request) return shared_folder_add
def get_enterprise_data(params, rq): # type: (KeeperParams, dict) -> dict encrypted_tree_key = api.encrypt_aes( _TREE_KEY, params.data_key) if _USE_DATA_KEY else api.encrypt_rsa( _TREE_KEY, _VAULT_ENV.public_key) tree_key_type = 1 if _USE_DATA_KEY else 2 rs = { 'result': 'success', 'result_code': '', 'message': '', 'enterprise_name': 'Enterprise 1', 'tree_key': encrypted_tree_key, 'key_type_id': tree_key_type } includes = set(rq.get('include') or []) ent_id = _ENTERPRISE_ID << 32 if 'nodes' in includes: rs['nodes'] = [{ 'node_id': _NODE1_ID, 'encrypted_data': api.encrypt_aes( json.dumps({ 'displayname': 'Root node' }).encode('utf-8'), _TREE_KEY) }, { 'node_id': _NODE2_ID, 'parent_id': _NODE1_ID, 'encrypted_data': api.encrypt_aes( json.dumps({ 'displayname': 'Sub node 1' }).encode('utf-8'), _TREE_KEY) }] if 'users' in includes: rs['users'] = [{ 'enterprise_user_id': _USER1_ID, 'node_id': _NODE1_ID, 'username': params.user, 'encrypted_data': api.encrypt_aes( json.dumps({ 'displayname': 'User 1' }).encode('utf-8'), _TREE_KEY), 'status': 'active', 'lock': 0 }, { 'enterprise_user_id': _USER2_ID, 'node_id': _NODE2_ID, 'username': _USER2_EMAIL, 'encrypted_data': api.encrypt_aes( json.dumps({ 'displayname': 'User 2' }).encode('utf-8'), _TREE_KEY), 'status': 'active', 'lock': 1 }] if 'roles' in includes: rs['roles'] = [{ 'role_id': _ROLE1_ID, 'node_id': _NODE1_ID, 'encrypted_data': api.encrypt_aes( json.dumps({ 'displayname': _ROLE1_NAME }).encode('utf-8'), _TREE_KEY), 'visible_below': True, 'new_user_inherit': True }] if 'role_users' in includes: rs['role_users'] = [{ 'role_id': ent_id + 301, 'enterprise_user_id': _USER1_ID }] if 'teams' in includes: rs['teams'] = [{ 'team_uid': _TEAM1_UID, 'name': _TEAM1_NAME, 'node_id': _NODE1_ID, 'restrict_sharing': False, 'restrict_edit': False, 'restrict_view': False, }, { 'team_uid': _TEAM2_UID, 'name': _TEAM2_NAME, 'node_id': _NODE1_ID, 'restrict_sharing': False, 'restrict_edit': False, 'restrict_view': False, }] if 'team_users' in includes: rs['team_users'] = [{ 'team_uid': _TEAM1_UID, 'enterprise_user_id': _USER1_ID, 'user_type': 1 }, { 'team_uid': _TEAM1_UID, 'enterprise_user_id': _USER2_ID, 'user_type': 1 }] return rs
def prepare_folder_permission(params, folders): shared_folder_lookup = {} for shared_folder_uid in params.shared_folder_cache: path = get_folder_path(params, shared_folder_uid) if path: shared_folder_lookup[path] = shared_folder_uid email_pattern = re.compile(EMAIL_PATTERN) # public keys emails = {} for fol in folders: if fol.permissions: for perm in fol.permissions: if not perm.uid: match = email_pattern.match(perm.name) if match: if perm.name not in emails: if perm.name != params.user: emails[perm.name.lower()] = None if emails: request = {'command': "public_keys", 'key_owners': list(emails.keys())} try: rs = api.communicate(params, request) if 'public_keys' in rs: for pk in rs['public_keys']: if 'public_key' in pk: emails[pk['key_owner']] = pk['public_key'] except Exception as e: logging.debug(e) folder_permissions = [] for fol in folders: shared_folder_uid = shared_folder_lookup.get(fol.path) if not shared_folder_uid: continue shared_folder = params.shared_folder_cache.get(shared_folder_uid) if not shared_folder: continue shared_folder_key = shared_folder.get('shared_folder_key_unencrypted') if not shared_folder_key: continue if fol.permissions: add_users = [] add_teams = [] for perm in fol.permissions: is_team = False if perm.uid and params.team_cache: is_team = perm.uid in params.team_cache else: match = email_pattern.match(perm.name) if not match: is_team = True if is_team: perm.uid = None for team_uid in params.team_cache: team = params.team_cache[team_uid] if team['name'].lower() == perm.name.lower(): perm.uid = team_uid break if is_team: team = params.team_cache.get(perm.uid) if team: found = False if 'teams' in shared_folder: for team in shared_folder['teams']: if team['team_uid'] == team['team_uid']: found = True break if not found: add_teams.append({ 'team_uid': team['team_uid'], 'manage_users': perm.manage_users, 'manage_records': perm.manage_records, 'shared_folder_key': api.encrypt_aes(shared_folder_key, team['team_key_unencrypted']), }) elif perm.name: email = perm.name.lower() found = False if 'users' in shared_folder: for user in shared_folder['users']: if user['username'] == email: found = True break if not found: if email == params.user.lower(): add_users.append({ 'username': email, 'manage_users': perm.manage_users, 'manage_records': perm.manage_records, 'shared_folder_key': api.encrypt_aes(shared_folder_key, params.data_key) }) elif email in emails: public_key = emails[email] if public_key: try: rsa_key = RSA.importKey( base64.urlsafe_b64decode(public_key + '==')) add_users.append({ 'username': email, 'manage_users': perm.manage_users, 'manage_records': perm.manage_records, 'shared_folder_key': api.encrypt_rsa( shared_folder_key, rsa_key) }) except Exception as e: logging.debug(e) if add_teams or add_users: request = { 'command': 'shared_folder_update', 'operation': 'update', 'pt': 'Commander', 'shared_folder_uid': shared_folder_uid, 'force_update': True, 'add_teams': add_teams, 'add_users': add_users, } folder_permissions.append(request) return folder_permissions