def register_shared_folder(shared_folder, records): # type: (shared_folder.SharedFolder, dict) -> bytes shared_folder_key = api.generate_aes_key() sf = { 'shared_folder_uid': shared_folder.shared_folder_uid, 'key_type': 1, 'shared_folder_key': api.encrypt_aes(shared_folder_key, _USER_DATA_KEY), 'name': api.encrypt_aes(shared_folder.name.encode('utf-8'), shared_folder_key), 'is_account_folder': False, 'manage_records': False, 'manage_users': False, 'default_manage_records': True, 'default_manage_users': True, 'default_can_edit': True, 'default_can_share': True, 'full_sync': True, 'records': [{ 'record_uid': x[0], 'record_key': api.encrypt_aes(x[1], shared_folder_key), 'can_share': False, 'can_edit': False } for x in records.items()], 'users': [{ 'username': _USER_NAME, 'manage_records': True, 'manage_users': True }], 'revision': 5 } _SHARED_FOLDERS.append(sf) return shared_folder_key
def register_record(record, key_type=None): # type: (record.Record, int or None) -> 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'] = utils.base64_url_encode( crypto.encrypt_aes_v1(record_key, _USER_DATA_KEY)) _RECORD_METADATA.append(meta_data) elif key_type == 2: meta_data['record_key'] = utils.base64_url_encode( crypto.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 construct_update_rec_req(params, preexisting_record_hash, rec_to_update): """ Build a rec_req for rec_to_import. Based on https://keeper.atlassian.net/wiki/spaces/KA/pages/13238307/record+update+-+deprecated and upload_attachment(params, attachments), which appears elsewhere in this file. We're not doing records_update yet, because it requires v3 and we don't do v3 yet. """ # FIXME: This assert probably can be sorted out during code review. assert len(rec_to_update.folders) == 1, "What should we do with records that aren't in exactly one folder?" data = { 'folder': rec_to_update.folders[0].get_folder_path(), 'title': rec_to_update.title, 'secret1': rec_to_update.login, 'secret2': rec_to_update.password, 'link': rec_to_update.login_url, # We add notes and custom a little later. } current_rec = params.record_cache[rec_to_update.uid] # This should always exist, because this is an import --update. preexisting_record = params.record_cache[rec_to_update.uid] preexisting_record_fields_str = preexisting_record['data_unencrypted'].decode('utf-8') preexisting_record_fields_dict = json.loads(preexisting_record_fields_str) # These fields need to be preserved - per our design. field_tuple = ('notes', 'custom') for field_name in field_tuple: # these need to be preserved if field_name in preexisting_record_fields_dict: data[field_name] = preexisting_record_fields_dict[field_name] unencrypted_key = preexisting_record['record_key_unencrypted'] encrypted_data = api.encrypt_aes(json.dumps(data).encode('utf-8'), unencrypted_key) record_key = api.encrypt_aes(unencrypted_key, params.data_key) one_rec_req = { 'record_uid': rec_to_update.uid, 'record_key': record_key, 'record_key_unencrypted': base64.urlsafe_b64encode(unencrypted_key).decode('utf-8'), 'data': encrypted_data, 'version': 2, 'client_modified_time': api.current_milli_time(), 'revision': current_rec['revision'] } return one_rec_req
def communicate_success(params, request): # type: (any, dict) -> dict if request['command'] == 'enterprise_allocate_ids': return enterprise_allocate_ids(params, request) rs = {'result': 'success', 'result_code': '', 'message': ''} if request['command'] == 'team_get_keys': rs['keys'] = [{ 'team_uid': x, 'key': api.encrypt_aes(ent_env.team_key, vault_env.data_key), 'type': 1 } for x in request['teams']] return rs if request['command'] == 'public_keys': rs['public_keys'] = [{ 'key_owner': x, 'public_key': vault_env.encoded_public_key } for x in request['key_owners']] return rs cmd = TestEnterprise.expected_commands.pop(0) if cmd == request['command']: return rs if request['command'] == 'execute': request = request['requests'][0] if cmd == request['command']: return rs raise Exception()
def test_role_create(self): param1 = TestCrossEnterpriseCommands.params1 # type: KeeperParams param2 = TestCrossEnterpriseCommands.params2 # type: KeeperParams ent1_parent_id = [x['node_id'] for x in param1.enterprise['nodes']][0] cmd = EnterpriseRoleCommand() ent2_role_id = cmd.get_enterprise_id(param2) dt = {"displayname": "Role"} encrypted_data = api.encrypt_aes( json.dumps(dt).encode('utf-8'), param2.enterprise['unencrypted_tree_key']) rq = { "command": "role_add", "role_id": ent2_role_id, "node_id": ent1_parent_id, "encrypted_data": encrypted_data, "visible_below": True, "new_user_inherit": False } failed = False try: api.communicate(param2, rq) except KeeperApiError as err: failed = True self.assertEqual(err.result_code, "bad_inputs_node_id") self.assertTrue(failed)
def test_download_attachment_command(self): params = get_synced_params() cmd = record.RecordDownloadAttachmentCommand() records = [ x for x in params.record_cache.values() if len(x['extra_unencrypted']) > 10 ] rec = records[0] record_uid = rec['record_uid'] extra = json.loads(rec['extra_unencrypted'].decode('utf-8')) attachments = {} for file in extra['files']: key = base64.urlsafe_b64decode(file['key'] + '==') body_encoded = api.encrypt_aes(os.urandom(file['size']), key) attachments['https://keepersecurity.com/files/' + file['id']] = body_encoded def request_download(rq): self.assertEqual(rq['command'], 'request_download') return { 'downloads': [{ 'url': 'https://keepersecurity.com/files/' + x } for x in rq['file_ids']] } def request_http_get(url, **kwargs): attachment = mock.Mock() attachment.raw = io.BytesIO( base64.urlsafe_b64decode(attachments[url] + '==')) return attachment with mock.patch('requests.get', side_effect=request_http_get) as mock_get, \ mock.patch('builtins.open', mock.mock_open()), mock.patch('os.path.abspath', return_value='/file_name') as mock_abspath: KeeperApiHelper.communicate_expect([request_download]) cmd.execute(params, record=record_uid) self.assertTrue(KeeperApiHelper.is_expect_empty()) mock_get.assert_called() mock_abspath.assert_called()
def generate_data(): r1 = record.Record() r1.record_uid = api.generate_record_uid() r1.folder = 'Old Folder' r1.title = 'Record 1' r1.login = '******' r1.password = '******' r1.login_url = 'https://keepersecurity.com/1' r1.set_field('field1', 'value1') r1.notes = 'note1' r1.attachments = [{ 'name': 'Attachment 1', 'key': base64.urlsafe_b64encode( api.generate_aes_key()).decode('utf-8').rstrip('='), 'id': 'ABCDEFGH', 'size': 1000 }] r1.revision = 1 r1_key = register_record(r1, 1) r2 = record.Record() r2.record_uid = api.generate_record_uid() r2.title = 'Record 2' r2.login = '******' r2.password = '******' r2.login_url = 'https://keepersecurity.com/2' r2.set_field('field2', 'value2') r2.notes = 'note2' r2.revision = 2 r2_key = register_record(r2, 2) register_records_to_folder(None, [r1.record_uid, r2.record_uid]) r3 = record.Record() r3.record_uid = api.generate_record_uid() r3.title = 'Record 3' r3.login = '******' r3.password = '******' r3.login_url = 'https://keepersecurity.com/3' r3.revision = 3 r3_key = register_record(r3) sf1 = shared_folder.SharedFolder() sf1.shared_folder_uid = api.generate_record_uid() sf1.default_manage_records = False sf1.default_manage_users = False sf1.default_can_edit = False sf1.default_can_share = False sf1.name = 'Shared Folder 1' sf1_key = register_shared_folder(sf1, {r3.record_uid: r3_key}) register_records_to_folder(sf1.shared_folder_uid, [r3.record_uid]) _USER_FOLDER_SHARED_FOLDER.append( {'shared_folder_uid': sf1.shared_folder_uid}) t1 = team.Team() t1.team_uid = api.generate_record_uid() t1.name = 'Team 1' t1.restrict_edit = True t1.restrict_share = True t1.restrict_view = False register_team(t1, 1, {sf1.shared_folder_uid: sf1_key}) folder_key = api.generate_aes_key() _USER_FOLDERS.append({ 'folder_uid': api.generate_record_uid(), 'key_type': 1, 'user_folder_key': api.encrypt_aes(folder_key, _USER_DATA_KEY), 'revision': 200, 'type': 'user_folder', 'data': api.encrypt_aes( json.dumps({ 'name': 'User Folder 1' }).encode('utf-8'), folder_key) })
38JuMwHChTK29H9EOlqbOOuzYA1ENzL88hELpe+kl4RmpNS94BJDssikFFbjoiAV fwIDAQAB -----END PUBLIC KEY----- ''' _SESSION_TOKEN = base64.urlsafe_b64encode( os.urandom(64)).decode('utf-8').strip('=') _DEVICE_ID = os.urandom(64) _2FA_ONE_TIME_TOKEN = '123456' _2FA_DEVICE_TOKEN = base64.urlsafe_b64encode( os.urandom(32)).decode('utf-8').strip('=') _IMPORTED_PRIVATE_KEY = RSA.importKey(_USER_PRIVATE_KEY, _PRIVATE_KEY_PASSWORD) _DER_PRIVATE_KEY = _IMPORTED_PRIVATE_KEY.export_key(format='DER') _ENCRYPTED_PRIVATE_KEY = api.encrypt_aes(_DER_PRIVATE_KEY, _USER_DATA_KEY) _IMPORTED_PUBLIC_KEY = RSA.importKey(_USER_PUBLIC_KEY) _ENCODED_PUBLIC_KEY = base64.urlsafe_b64encode( _IMPORTED_PUBLIC_KEY.export_key(format='DER')).decode('utf-8').strip('=') _V2_DERIVED_KEY = rest_api.derive_key_v2('data_key', _USER_PASSWORD, _USER_SALT, _USER_ITERATIONS) _dk = rest_api.encrypt_aes(_USER_DATA_KEY, _V2_DERIVED_KEY) _ENCRYPTED_DATA_KEY = base64.urlsafe_b64encode(_dk).decode('utf-8').strip() _V1_DERIVED_KEY = api.derive_key(_USER_PASSWORD, _USER_SALT, _USER_ITERATIONS) _enc_iter = int.to_bytes(_USER_ITERATIONS, length=3, byteorder='big', signed=False)
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 get_enterprise_data(params): # type: (KeeperParams) -> dict encrypted_tree_key = crypto.encrypt_aes_v1(_TREE_KEY, params.data_key) \ if _USE_DATA_KEY else crypto.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': utils.base64_url_encode(encrypted_tree_key), 'key_type_id': tree_key_type } rs['nodes'] = [ { 'node_id': _NODE1_ID, 'encrypted_data': api.encrypt_aes(json.dumps({}).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) } ] 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 } ] 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 } ] rs['managed_nodes'] = [ { 'role_id': _ROLE1_ID, 'managed_node_id': _NODE1_ID, 'cascade_node_management': True, } ] rs['role_users'] = [ { 'role_id': _ROLE1_ID, 'enterprise_user_id': _USER1_ID } ] 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, } ] 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 construct_import_rec_req(params, preexisting_record_hash, rec_to_import): """Build a rec_req for rec_to_import.""" r_hash = build_record_hash(record=rec_to_import, tokenize_gen=tokenize_full_import_record) if r_hash in preexisting_record_hash: # Nothing to do. We already have this identical record. return None else: rec_to_import.uid = api.generate_record_uid() preexisting_record_hash[r_hash] = rec_to_import.uid record_key = os.urandom(32) rec_req = folder_pb2.RecordRequest() rec_req.recordUid = base64.urlsafe_b64decode(rec_to_import.uid + '==') rec_req.recordType = 0 rec_req.encryptedRecordKey = base64.urlsafe_b64decode(api.encrypt_aes(record_key, params.data_key) + '==') rec_req.howLongAgo = 0 rec_req.folderType = 1 folder_uid = None if rec_to_import.folders: folder_uid = rec_to_import.folders[0].uid if folder_uid: if folder_uid in params.folder_cache: folder = params.folder_cache[folder_uid] if folder.type in {BaseFolderNode.SharedFolderType, BaseFolderNode.SharedFolderFolderType}: rec_req.folderUid = base64.urlsafe_b64decode(folder.uid + '==') rec_req.folderType = 2 if folder.type == BaseFolderNode.SharedFolderType else 3 sh_uid = folder.uid if folder.type == BaseFolderNode.SharedFolderType else folder.shared_folder_uid sf = params.shared_folder_cache[sh_uid] rec_req.encryptedRecordFolderKey = base64.urlsafe_b64decode( api.encrypt_aes(record_key, sf['shared_folder_key_unencrypted']) + '==' ) else: rec_req.folderType = 1 if folder.type != BaseFolderNode.RootFolderType: rec_req.folderUid = base64.urlsafe_b64decode(folder.uid + '==') custom_fields = [] totp = None if rec_to_import.custom_fields: for cf in rec_to_import.custom_fields: if cf == TWO_FACTOR_CODE: totp = rec_to_import.custom_fields[cf] else: custom_fields.append({ 'name': cf, 'value': rec_to_import.custom_fields[cf] }) data = { 'title': rec_to_import.title or '', 'secret1': rec_to_import.login or '', 'secret2': rec_to_import.password or '', 'link': rec_to_import.login_url or '', 'notes': rec_to_import.notes or '', 'custom': custom_fields } rec_req.recordData = base64.urlsafe_b64decode(api.encrypt_aes(json.dumps(data).encode('utf-8'), record_key) + '==') if totp: extra = { 'fields': [ { 'id': api.generate_record_uid(), 'field_type': 'totp', 'field_title': 'Two-Factor Code', 'type': 0, 'data': totp }] } rec_req.extra = base64.urlsafe_b64decode(api.encrypt_aes(json.dumps(extra).encode('utf-8'), record_key) + '==') return rec_req
def prepare_record_link(params, records): record_folders = {} # type: [str, [str]] record_links = [] for rec in records: if rec.uid: if rec.uid in params.record_cache: if rec.uid in record_folders: folder_ids = record_folders[rec.uid] else: folder_ids = list(find_folders(params, rec.uid)) record_folders[rec.uid] = folder_ids record = params.record_cache[rec.uid] for fol in rec.folders or [None]: folder_uid = fol.uid if fol else '' if folder_uid and folder_uid not in params.folder_cache: continue if folder_uid in folder_ids: continue if len(folder_ids) > 0: folder_ids.append(folder_uid) src_folder = params.folder_cache[folder_ids[0]] dst_folder = params.folder_cache[ folder_uid] if folder_uid in params.folder_cache else params.root_folder req = { 'command': 'move', 'to_type': dst_folder.type if dst_folder.type != BaseFolderNode.RootFolderType else BaseFolderNode.UserFolderType, 'link': True, 'move': [], 'transition_keys': [] } if dst_folder.type != BaseFolderNode.RootFolderType: req['to_uid'] = dst_folder.uid mo = { 'type': 'record', 'uid': rec.uid, 'from_type': src_folder.type if src_folder.type != BaseFolderNode.RootFolderType else BaseFolderNode.UserFolderType, 'cascade': True } if src_folder.type != BaseFolderNode.RootFolderType: mo['from_uid'] = src_folder.uid req['move'].append(mo) transition_key = None record_key = record['record_key_unencrypted'] if src_folder.type in { BaseFolderNode.SharedFolderType, BaseFolderNode.SharedFolderFolderType }: if dst_folder.type in { BaseFolderNode.SharedFolderType, BaseFolderNode.SharedFolderFolderType }: ssf_uid = src_folder.uid if src_folder.type == BaseFolderNode.SharedFolderType else \ src_folder.shared_folder_uid dsf_uid = dst_folder.uid if dst_folder.type == BaseFolderNode.SharedFolderType else \ dst_folder.shared_folder_uid if ssf_uid != dsf_uid: shf = params.shared_folder_cache[dsf_uid] transition_key = api.encrypt_aes( record_key, shf['shared_folder_key_unencrypted']) else: transition_key = api.encrypt_aes( record_key, params.data_key) else: if dst_folder.type in { BaseFolderNode.SharedFolderType, BaseFolderNode.SharedFolderFolderType }: dsf_uid = dst_folder.uid if dst_folder.type == BaseFolderNode.SharedFolderType else \ dst_folder.shared_folder_uid shf = params.shared_folder_cache[dsf_uid] transition_key = api.encrypt_aes( record_key, shf['shared_folder_key_unencrypted']) if transition_key is not None: req['transition_keys'].append({ 'uid': rec.uid, 'key': transition_key }) record_links.append(req) return record_links
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_folder_add(params, folders, records): 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 folder_add = [] # type: [folder_pb2.FolderRequest] if folders: for fol in folders: skip_folder = False parent_uid = '' 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() folder_type = 'shared_folder' if is_last else 'user_folder' fol_req = folder_pb2.FolderRequest() fol_req.folderUid = base64.urlsafe_b64decode(folder_uid + '==') fol_req.folderType = 2 if folder_type == 'shared_folder' else 1 if parent_uid: fol_req.parentFolderUid = base64.urlsafe_b64decode( parent_uid + '==') folder_key = os.urandom(32) fol_req.encryptedFolderKey = base64.urlsafe_b64decode( api.encrypt_aes(folder_key, params.data_key) + '==') data = {'name': comp} fol_req.folderData = base64.urlsafe_b64decode( api.encrypt_aes( json.dumps(data).encode('utf-8'), folder_key) + '==') if folder_type == 'shared_folder': fol_req.sharedFolderFields.encryptedFolderName = base64.urlsafe_b64decode( api.encrypt_aes(comp.encode('utf-8'), folder_key) + '==') fol_req.sharedFolderFields.manageUsers = fol.manage_users fol_req.sharedFolderFields.manageRecords = fol.manage_records fol_req.sharedFolderFields.canEdit = fol.can_edit fol_req.sharedFolderFields.canShare = fol.can_share folder_add.append(fol_req) folder_hash[ digest] = folder_uid, folder_type, folder_key if folder_type == 'shared_folder' else None else: folder_uid, folder_type, folder_key = folder_hash[digest] if is_last: skip_folder = folder_type != 'shared_folder' else: skip_folder = folder_type != 'user_folder' parent_uid = folder_uid if skip_folder: break if records: for rec in records: if rec.folders: for fol in rec.folders: parent_uid = '' parent_shared_folder_uid = None parent_shared_folder_key = None parent_type = '' for is_domain in [True, False]: path = fol.domain if is_domain else fol.path if not path: continue comps = list(path_components(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() if digest not in folder_hash: is_shared = False if i == len(comps) - 1: is_shared = is_domain folder_uid = api.generate_record_uid() if not parent_type or parent_type == 'user_folder': folder_type = 'shared_folder' if is_shared else 'user_folder' else: folder_type = 'shared_folder_folder' fol_req = folder_pb2.FolderRequest() fol_req.folderUid = base64.urlsafe_b64decode( folder_uid + '==') fol_req.folderType = 2 if folder_type == 'shared_folder' else 3 if folder_type == 'shared_folder_folder' else 1 if parent_uid: fol_req.parentFolderUid = base64.urlsafe_b64decode( parent_uid + '==') if folder_type == 'shared_folder_folder' and parent_uid == parent_shared_folder_uid: fol_req.parentFolderUid = b'' folder_key = os.urandom(32) if folder_type == 'shared_folder_folder': fol_req.encryptedFolderKey = base64.urlsafe_b64decode( api.encrypt_aes( folder_key, parent_shared_folder_key or params.data_key) + '==') else: fol_req.encryptedFolderKey = base64.urlsafe_b64decode( api.encrypt_aes( folder_key, params.data_key) + '==') data = {'name': comp} fol_req.folderData = base64.urlsafe_b64decode( api.encrypt_aes( json.dumps(data).encode('utf-8'), folder_key) + '==') if folder_type == 'shared_folder': fol_req.sharedFolderFields.encryptedFolderName = base64.urlsafe_b64decode( api.encrypt_aes( comp.encode('utf-8'), folder_key) + '==') parent_shared_folder_key = folder_key parent_shared_folder_uid = folder_uid elif folder_type == 'shared_folder_folder': if parent_shared_folder_uid: fol_req.sharedFolderFolderFields.sharedFolderUid = base64.urlsafe_b64decode( parent_shared_folder_uid + '==') folder_add.append(fol_req) folder_hash[ digest] = folder_uid, folder_type, parent_shared_folder_key else: folder_uid, folder_type, parent_shared_folder_key = folder_hash[ digest] if folder_type == 'shared_folder': parent_shared_folder_uid = folder_uid parent_uid = folder_uid parent_type = folder_type fol.uid = parent_uid return folder_add
def prepare_record_add(params, records): record_hash = {} for r_uid in params.record_cache: rec = api.get_record(params, r_uid) h = hashlib.sha256() for token in tokenize_record(rec): h.update(token.encode()) record_hash[h.hexdigest()] = r_uid record_adds = [] for rec in records: h = hashlib.sha256() for token in tokenize_import_record(rec): h.update(token.encode()) r_hash = h.hexdigest() if r_hash in record_hash: rec.uid = record_hash[r_hash] else: rec.uid = api.generate_record_uid() record_hash[r_hash] = rec.uid record_key = os.urandom(32) rec_req = folder_pb2.RecordRequest() rec_req.recordUid = base64.urlsafe_b64decode(rec.uid + '==') rec_req.recordType = 0 rec_req.encryptedRecordKey = base64.urlsafe_b64decode( api.encrypt_aes(record_key, params.data_key) + '==') rec_req.howLongAgo = 0 rec_req.folderType = 1 folder_uid = None if rec.folders: folder_uid = rec.folders[0].uid if folder_uid: if folder_uid in params.folder_cache: folder = params.folder_cache[folder_uid] if folder.type in { BaseFolderNode.SharedFolderType, BaseFolderNode.SharedFolderFolderType }: rec_req.folderUid = base64.urlsafe_b64decode( folder.uid + '==') rec_req.folderType = 2 if folder.type == BaseFolderNode.SharedFolderType else 3 sh_uid = folder.uid if folder.type == BaseFolderNode.SharedFolderType else folder.shared_folder_uid sf = params.shared_folder_cache[sh_uid] rec_req.encryptedRecordFolderKey = base64.urlsafe_b64decode( api.encrypt_aes( record_key, sf['shared_folder_key_unencrypted']) + '==') else: rec_req.folderType = 1 if folder.type != BaseFolderNode.RootFolderType: rec_req.folderUid = base64.urlsafe_b64decode( folder.uid + '==') custom_fields = [] totp = None if rec.custom_fields: for cf in rec.custom_fields: if cf == TWO_FACTOR_CODE: totp = rec.custom_fields[cf] else: custom_fields.append({ 'name': cf, 'value': rec.custom_fields[cf] }) data = { 'title': rec.title or '', 'secret1': rec.login or '', 'secret2': rec.password or '', 'link': rec.login_url or '', 'notes': rec.notes or '', 'custom': custom_fields } rec_req.recordData = base64.urlsafe_b64decode( api.encrypt_aes(json.dumps(data).encode('utf-8'), record_key) + '==') if totp: extra = { 'fields': [{ 'id': api.generate_record_uid(), 'field_type': 'totp', 'field_title': 'Two-Factor Code', 'type': 0, 'data': totp }] } rec_req.extra = base64.urlsafe_b64decode( api.encrypt_aes( json.dumps(extra).encode('utf-8'), record_key) + '==') record_adds.append(rec_req) return record_adds
def upload_attachment(params, attachments): ''' :param attachments: :type attachments: [(str, ImportAttachment)] ''' print('Uploading attachments:') while len(attachments) > 0: chunk = attachments[:90] attachments = attachments[90:] uploads = None file_no = 0 file_size = 0 for _, att in chunk: file_no += 1 file_size += att.size or 0 #TODO check storage subscription rq = {'command': 'request_upload', 'file_count': file_no} try: rs = api.communicate(params, rq) if rs['result'] == 'success': uploads = rs['file_uploads'] except Exception as e: logging.error(e) return uploaded = {} for record_id, atta in chunk: if not uploads: break try: upload = uploads.pop() buffer = io.BytesIO() cipher = None key = atta.key if not key: key = os.urandom(32) iv = os.urandom(16) cipher = AES.new(key, AES.MODE_CBC, iv) buffer.write(iv) with atta.open() as s: finished = False while not finished: chunk = s.read(10240) if len(chunk) > 0: if cipher is not None: if len(chunk) < 10240: finished = True chunk = api.pad_binary(chunk) chunk = cipher.encrypt(chunk) buffer.write(chunk) else: finished = True size = buffer.tell() - 16 if size > 0: buffer.seek(0, io.SEEK_SET) files = { upload['file_parameter']: (atta.name, buffer, 'application/octet-stream') } print('{0} ... '.format(atta.name), end='', flush=True) response = requests.post(upload['url'], files=files, data=upload['parameters']) if response.status_code == upload['success_status_code']: if record_id not in uploaded: uploaded[record_id] = [] uploaded[record_id].append({ 'key': base64.urlsafe_b64encode(key).decode().rstrip('='), 'name': atta.name, 'file_id': upload['file_id'], 'size': size }) print('Done') else: print('Failed') except Exception as e: logging.warning(e) if len(uploaded) > 0: rq = { 'command': 'record_update', 'pt': 'Commander', 'device_id': 'Commander', 'client_time': api.current_milli_time(), 'update_records': [] } for record_id in uploaded: if record_id in params.record_cache: rec = params.record_cache[record_id] extra = json.loads(rec['extra_unencrypted'].decode( 'utf-8')) if 'extra' in rec else {} files = extra.get('files') if files is None: files = [] extra['files'] = files udata = rec['udata'] if 'udata' in rec else {} file_ids = udata.get('file_ids') if file_ids is None: file_ids = [] udata['file_ids'] = file_ids for atta in uploaded[record_id]: file_ids.append(atta['file_id']) files.append({ 'id': atta['file_id'], 'name': atta['name'], 'size': atta['size'], 'key': atta['key'] }) ru = { 'record_uid': record_id, 'version': 2, 'client_modified_time': api.current_milli_time(), 'extra': api.encrypt_aes( json.dumps(extra).encode('utf-8'), rec['record_key_unencrypted']), 'udata': udata, 'revision': rec['revision'] } api.resolve_record_access_path(params, record_id, path=ru) rq['update_records'].append(ru) try: rs = api.communicate(params, rq) if rs['result'] == 'success': api.sync_down(params) except Exception as e: logging.debug(e)
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
def prepare_record_add(params, records): record_hash = {} for r_uid in params.record_cache: rec = api.get_record(params, r_uid) h = hashlib.md5() hs = '{0}|{1}|{2}'.format(rec.title or '', rec.login or '', rec.password or '') h.update(hs.encode()) record_hash[h.hexdigest()] = r_uid record_adds = [] for rec in records: h = hashlib.md5() hs = '{0}|{1}|{2}'.format(rec.title or '', rec.login or '', rec.password or '') h.update(hs.encode()) rec_hash = h.hexdigest() record_uid = record_hash.get(rec_hash) if record_uid is None: record_key = os.urandom(32) record_uid = api.generate_record_uid() req = { 'command': 'record_add', 'record_uid': record_uid, 'record_type': 'password', 'record_key': api.encrypt_aes(record_key, params.data_key), 'how_long_ago': 0, 'folder_type': 'user_folder' } folder_uid = None if rec.folders: if len(rec.folders) > 0: folder_uid = rec.folders[0].uid if folder_uid: if folder_uid in params.folder_cache: folder = params.folder_cache[folder_uid] if folder.type in { BaseFolderNode.SharedFolderType, BaseFolderNode.SharedFolderFolderType }: req['folder_uid'] = folder.uid req['folder_type'] = 'shared_folder' if folder.type == BaseFolderNode.SharedFolderType else 'shared_folder_folder' sh_uid = folder.uid if folder.type == BaseFolderNode.SharedFolderType else folder.shared_folder_uid sf = params.shared_folder_cache[sh_uid] req['folder_key'] = api.encrypt_aes( record_key, sf['shared_folder_key_unencrypted']) if 'key_type' not in sf: if 'teams' in sf: for team in sf['teams']: req['team_uid'] = team['team_uid'] if team['manage_records']: break else: req['folder_type'] = 'user_folder' if folder.type != BaseFolderNode.RootFolderType: req['folder_uid'] = folder.uid custom_fields = [] if rec.custom_fields: for cf in rec.custom_fields: custom_fields.append({ 'name': cf, 'value': rec.custom_fields[cf] }) data = { 'title': rec.title or '', 'secret1': rec.login or '', 'secret2': rec.password or '', 'link': rec.login_url or '', 'notes': rec.notes or '', 'custom': custom_fields } req['data'] = api.encrypt_aes( json.dumps(data).encode('utf-8'), record_key) record_adds.append(req) rec.uid = record_uid return record_adds
def prepare_folder_add(params, records): 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 folder_add = [] for rec in records: if rec.folders: for fol in rec.folders: parent_uid = '' parent_shared_folder_uid = None parent_shared_folder_key = None parent_type = BaseFolderNode.RootFolderType for is_domain in [True, False]: path = fol.domain if is_domain else fol.path if not path: continue comps = list(path_components(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() if digest not in folder_hash: is_shared = False if i == len(comps) - 1: is_shared = is_domain folder_uid = api.generate_record_uid() request = { 'command': 'folder_add', 'folder_uid': folder_uid } if parent_type in { BaseFolderNode.UserFolderType, BaseFolderNode.RootFolderType }: folder_type = 'shared_folder' if is_shared else 'user_folder' else: folder_type = 'shared_folder_folder' request['folder_type'] = folder_type encryption_key = params.data_key if request[ 'folder_type'] == 'shared_folder_folder' and parent_shared_folder_uid and parent_shared_folder_key: encryption_key = parent_shared_folder_key request[ 'shared_folder_uid'] = parent_shared_folder_uid folder_key = os.urandom(32) request['key'] = api.encrypt_aes( folder_key, encryption_key) if parent_type not in { BaseFolderNode.RootFolderType, BaseFolderNode.SharedFolderType }: request['parent_uid'] = parent_uid if request['folder_type'] == 'shared_folder': request['name'] = api.encrypt_aes( comp.encode('utf-8'), folder_key) parent_shared_folder_key = folder_key data = {'name': comp} request['data'] = api.encrypt_aes( json.dumps(data).encode('utf-8'), folder_key) folder_add.append(request) parent_uid = folder_uid parent_type = folder_type folder_hash[ digest] = parent_uid, parent_type, parent_shared_folder_key else: parent_uid, parent_type, parent_shared_folder_key = folder_hash[ digest] if parent_type == BaseFolderNode.SharedFolderType: parent_shared_folder_uid = parent_uid fol.uid = parent_uid return folder_add
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