def execute_batch(params, requests): if not requests: return chunk_size = 100 queue = requests.copy() while len(queue) > 0: chunk = queue[:chunk_size] queue = queue[chunk_size:] rq = {'command': 'execute', 'requests': chunk} try: rs = api.communicate(params, rq) if rs['result'] == 'success': if 'results' in rs: results = rs['results'] if len(results) > 0: if params.debug: pos = len(results) - 1 req = chunk[pos] res = results[pos] if res['result'] != 'success': logging.debug( 'execute failed: command %s: %s)', req.get('command'), res.get('message')) if len(results) < len(chunk): queue = chunk[len(results):] + queue except Exception as e: logging.debug(e) api.sync_down(params)
def test_sync_remove_team_shared_folder(self): params = get_synced_params() teams_to_delete = [x['team_uid'] for x in params.team_cache.values()] sf_to_delete = [ x['shared_folder_uid'] for x in params.shared_folder_cache.values() ] def sync_down_removed_teams_and_shared_folders(rq): self.assertEqual(rq['command'], 'sync_down') return { 'revision': vault_env.revision + 1, 'removed_shared_folders': sf_to_delete, 'removed_teams': teams_to_delete } KeeperApiHelper.communicate_expect( [sync_down_removed_teams_and_shared_folders]) sync_down(params) self.assertTrue(KeeperApiHelper.is_expect_empty()) self.assertEqual(len(params.record_cache), 2) self.assertEqual(len(params.shared_folder_cache), 0) self.assertEqual(len(params.team_cache), 0) self.assert_key_unencrypted(params)
def get_synced_params(): p = get_connected_params() with mock.patch('keepercommander.api.communicate') as mock_comm: mock_comm.return_value = get_sync_down_response() api.sync_down(p) p.record_type_cache[1] = { "$id": "login", "categories": ["login"], "description": "Login template", "fields": [{ "$ref": "login" }, { "$ref": "password" }, { "$ref": "url" }, { "$ref": "fileRef" }, { "$ref": "oneTimeCode" }] } return p
def login_to_keeper_with_config(filename): # type: (str) -> KeeperParams # Load connection parameters from file my_params = get_params_from_config(filename) my_params.password = '' # Keeper account password. Can be omitted if account is setup for session resumption # Login to Keeper api.login(my_params) api.sync_down(my_params) return my_params
def get(params, uid): try: prompt_for_credentials(params) api.sync_down(params) if uid: api.get_record(params, uid).display() except Exception as e: raise click.ClickException(e)
def create_sf(params, filename): api.sync_down(params) def read_json(): with open(filename, mode="rt", encoding="utf8") as f: return json.load(f) print('Creating shared folder(s)...') num_success = 0 for json_sf in read_json(): print('Preparing shared folder') my_shared_folder = api.prepare_shared_folder(params, parse_sf_json(json_sf)) request = api.make_request(params, 'shared_folder_update') request.update(my_shared_folder) if params.debug: print('Sending request') response_json = api.communicate(params, request) user_success = [ info for info in response_json['add_users'] if info['status'] == 'success' ] if len(user_success) > 0: print("{0} users added successfully".format(len(user_success))) user_failures = [ info for info in response_json['add_users'] if info['status'] != 'success' ] if len(user_failures) > 0: print("{0} users failed to get added".format(len(user_failures))) add_records_success = [ info for info in response_json['add_records'] if info['status'] == 'success' ] if len(add_records_success) > 0: print("{0} records added successfully".format( len(add_records_success))) add_records_failures = [ info for info in response_json['add_records'] if info['status'] != 'success' ] if len(add_records_failures) > 0: print("{0} records failed to get added".format( len(add_records_failures))) if len(user_success) + len(add_records_success) > 0: num_success += 1 print('Created shared folder ' + request['shared_folder_uid'] + 'with success') if num_success > 0: print('Successfully created [' + str(num_success) + '] shared folders')
def get_rec(params, uid): if not (uid): raise click.ClickException("Need to specify uid option") try: api.sync_down(params) if uid: display.print_record(params, uid) except Exception as e: raise click.ClickException(e)
def list(params): try: api.sync_down(params) if (len(params.record_cache) == 0): print('No records') return results = api.search_records(params, '') display.formatted_records(results) except Exception as e: raise click.ClickException(e)
def search(params, regex): try: prompt_for_credentials(params) api.sync_down(params) if (len(params.record_cache) == 0): print('No records') return results = api.search_records(params, regex) display.formatted_records(results) except Exception as e: raise click.ClickException(e)
def list_teams(params): try: prompt_for_credentials(params) api.sync_down(params) if (len(params.team_cache) > 0): results = api.search_teams(params, '') display.formatted_teams(results) except Exception as e: raise click.ClickException(e)
def test_full_sync(self): params = get_connected_params() self.communicate_mock.side_effect = None self.communicate_mock.return_value = get_sync_down_response() sync_down(params) self.assertEqual(len(params.record_cache), 3) self.assertEqual(len(params.shared_folder_cache), 1) self.assertEqual(len(params.team_cache), 1) self.assert_key_unencrypted(params)
def rotate(params, uid, match): if not (uid or match): raise click.ClickException("Need to specify either uid or match option") try: api.sync_down(params) if uid: api.rotate_password(params, uid) else: if filter: results = api.search_records(params, match) for r in results: api.rotate_password(params, r.record_uid) except Exception as e: raise click.ClickException(e)
def export(params, format, filename): api.sync_down(params) records = [api.get_record(params, record_uid) for record_uid in params.record_cache] records.sort(key=lambda x: ((x.folder if x.folder else ' ') + x.title).lower(), reverse=False) if format == 'json': with open(filename, mode="w", encoding="utf8") as f: json.dump([record.to_dictionary() for record in records], f, indent=2, ensure_ascii=False) else: with open(filename, mode="wt", encoding="utf8") as f: for record in records: f.write(record.to_tab_delimited() + '\n') print('{0} records exported to {1}'.format(len(records), filename))
def delete_all(params): api.sync_down(params) if (len(params.record_cache) == 0): print('No records to delete') return request = api.make_request(params, 'record_update') print('removing {0} records from Keeper'.format(len(params.record_cache))) request['delete_records'] = [key for key in params.record_cache.keys()] response_json = api.communicate(params, request) success = [info for info in response_json['delete_records'] if info['status'] == 'success'] if len(success) > 0: print("{0} records deleted successfully".format(len(success))) failures = [info for info in response_json['delete_records'] if info['status'] != 'success'] if len(failures) > 0: print("{0} records failed to delete".format(len(failures)))
def export(params, format, filename): api.sync_down(params) records = [api.get_record(params, record_uid) for record_uid in params.record_cache if params.meta_data_cache[record_uid]['owner']] records.sort(key=lambda x: ((x.folder if x.folder else ' ') + x.title).lower(), reverse=False) if format == 'json': with open(filename, 'w') as f: json.dump([record.to_dictionary() for record in records], f, indent=2) else: with open(filename, 'wt') as f: for record in records: f.write(record.to_tab_delimited() + '\n') print(('{0} records exported to {1}'.format(len(records), filename)))
def export(params, format, filename): api.sync_down(params) records = [api.get_record(params, record_uid) for record_uid in params.record_cache if params.meta_data_cache[record_uid]['owner']] records.sort(key=lambda x: ((x.folder if x.folder else ' ') + x.title).lower(), reverse=False) if format == 'json': with open(filename, 'w') as f: json.dump([record.to_dictionary() for record in records], f, indent=2) else: with open(filename, 'wt') as f: for record in records: f.write(record.to_tab_delimited() + '\n') print('{0} records exported to {1}'.format(len(records), filename))
def wipe_out_data(cls): params = cls.params # type: KeeperParams params.revision = 0 api.sync_down(params) request = { 'command': 'record_update', 'delete_records': [key for key in params.record_cache.keys()] } rs = api.communicate(params, request) for shared_folder_uid in params.shared_folder_cache: request = { 'command': 'shared_folder_update', 'operation': 'delete', 'shared_folder_uid': shared_folder_uid } rs = api.communicate(params, request) folder_uids = [ x for x in params.root_folder.subfolders if params.subfolder_cache[x]['type'] == BaseFolderNode.UserFolderType ] if folder_uids: request = { 'command': 'pre_delete', 'objects': [{ 'from_type': 'user_folder', 'object_uid': x, 'object_type': 'user_folder', 'delete_resolution': 'unlink' } for x in folder_uids] } rs = api.communicate(params, request) request = { 'command': 'delete', 'pre_delete_token': rs['pre_delete_response']['pre_delete_token'] } rs = api.communicate(params, request) request = {'command': 'purge_deleted_records'} rs = api.communicate(params, request) params.revision = 0 api.sync_down(params)
def rotate(params, uid, match, print): try: prompt_for_credentials(params) api.sync_down(params) if uid: api.rotate_password(params, uid) if print: display.print_record(params, uid) else: if filter: results = api.search_records(params, match) for r in results: api.rotate_password(params, r.record_uid) if print: display.print_record(params, uid) except Exception as e: raise click.ClickException(e)
def rotate(params, uid, match, print): if not (uid or match): raise click.ClickException( "Need to specify either uid or match option") try: api.sync_down(params) if uid: api.rotate_password(params, uid) if print: display.print_record(params, uid) else: if filter: results = api.search_records(params, match) for r in results: api.rotate_password(params, r.record_uid) if print: display.print_record(params, uid) except Exception as e: raise click.ClickException(e)
def test_sync_remove_owned_records(self): params = get_synced_params() len_before = len(params.record_cache) records_to_delete = [x['record_uid'] for x in params.meta_data_cache.values() if x['owner']] def sync_down_removed_records(rq): self.assertEqual(rq['command'], 'sync_down') return { 'revision': vault_env.revision + 1, 'removed_records': records_to_delete } KeeperApiHelper.communicate_expect([sync_down_removed_records]) sync_down(params) self.assertTrue(KeeperApiHelper.is_expect_empty()) self.assertEqual(len(params.record_cache), len_before - len(records_to_delete)) self.assert_key_unencrypted(params)
def login(email, password=None, keeper_server='https://keepersecurity.com/api/v2/', config_file='myconfig.json'): if os.path.exists(config_file): params = get_params_from_config(config_file) else: params = KeeperParams() params.config_filename = config_file params.user = email params.password = password if password else '' params.server = keeper_server params.config['server'] = params.server api.login(params) api.sync_down(params) return params
params.password = params.config['password'] if 'device_id' in params.config: device_id = base64.urlsafe_b64decode( params.config['device_id'] + '==') params.rest_context.device_id = device_id my_params = KeeperParams() read_config_file(my_params) while not my_params.user: my_params.user = getpass.getpass(prompt='User(Email): ', stream=None) while not my_params.password: my_params.password = getpass.getpass(prompt='Master Password: '******'Record UID: ', stream=None) api.sync_down(my_params) # See record.py for available fields # or call display.formatted_records(record) to show all record details record = api.get_record(my_params, record_uid) if record: print('Record Password: '******'No record found with that UID')
def do_command(params): if (params.command == 'q'): return False elif (params.command == 'l'): if (len(params.record_cache) == 0): print('No records') else: results = api.search_records(params, '') display.formatted_records(results) elif (params.command == 'lsf'): if (len(params.shared_folder_cache) == 0): print('No shared folders') else: results = api.search_shared_folders(params, '') display.formatted_shared_folders(results) elif (params.command[:2] == 'g '): if (api.is_shared_folder(params, params.command[2:])): sf = api.get_shared_folder(params, params.command[2:]) if sf: sf.display() else: r = api.get_record(params, params.command[2:]) if r: r.display() elif (params.command[:2] == 'r '): api.rotate_password(params, params.command[2:]) elif (params.command[:2] == 'd '): api.delete_record(params, params.command[2:]) elif (params.command == 'c'): print(chr(27) + "[2J") elif (params.command[:2] == 's '): results = api.search_records(params, params.command[2:]) display.formatted_records(results) elif (params.command[:2] == 'b '): results = api.search_records(params, params.command[2:]) for r in results: api.rotate_password(params, r.record_uid) elif (params.command[:3] == 'an '): api.append_notes(params, params.command[3:]) elif (params.command == 'd'): api.sync_down(params) elif (params.command == 'a'): api.add_record(params) elif (params.command == 'h'): display.formatted_history(stack) elif (params.command == 'debug'): if params.debug: params.debug = False print('Debug OFF') else: params.debug = True print('Debug ON') elif params.command == '': pass else: print('\n\nCommands:\n') print(' d ... download & decrypt data') print(' l ... list folders and titles') print(' lsf ... list shared folders') print(' s <regex> ... search with regular expression') print(' g <uid> ... get record or shared folder details for uid') print(' r <uid> ... rotate password for uid') print( ' b <regex> ... rotate password for matches of regular expression' ) print(' a ... add a new record interactively') print(' an <uid> ... append some notes to the specified record') print(' c ... clear the screen') print(' h ... show command history') print(' q ... quit') print('') if params.command: if params.command != 'h': stack.append(params.command) stack.reverse() return True
def do_command(params): if (params.command == 'q'): return False elif (params.command == 'l'): if (len(params.record_cache) == 0): print('No records') else: results = api.search_records(params, '') display.formatted_records(results) elif (params.command == 'lsf'): if (len(params.shared_folder_cache) == 0): print('No shared folders') else: results = api.search_shared_folders(params, '') display.formatted_shared_folders(results) elif (params.command == 'lt'): if (len(params.team_cache) == 0): print('No teams') else: results = api.search_teams(params, '') display.formatted_teams(results) elif (params.command[:2] == 'g '): if (api.is_shared_folder(params, params.command[2:])): sf = api.get_shared_folder(params, params.command[2:]) if sf: sf.display() elif (api.is_team(params, params.command[2:])): team = api.get_team(params, params.command[2:]) if team: team.display() else: r = api.get_record(params, params.command[2:]) if r: r.display() elif (params.command[:2] == 'r '): api.rotate_password(params, params.command[2:]) elif (params.command[:2] == 'd '): api.delete_record(params, params.command[2:]) elif (params.command == 'c'): print(chr(27) + "[2J") elif (params.command[:2] == 's '): results = api.search_records(params, params.command[2:]) display.formatted_records(results) elif (params.command[:2] == 'b '): results = api.search_records(params, params.command[2:]) for r in results: api.rotate_password(params, r.record_uid) elif (params.command[:3] == 'an '): api.append_notes(params, params.command[3:]) elif (params.command == 'd'): api.sync_down(params) elif (params.command == 'a'): record = Record() while not record.title: record.title = input("... Title (req'd): ") record.folder = input("... Folder: ") record.login = input("... Login: "******"... Password: "******"... Login URL: ") record.notes = input("... Notes: ") while True: custom_dict = {} custom_dict['name'] = input("... Custom Field Name : ") if not custom_dict['name']: break custom_dict['value'] = input("... Custom Field Value : ") custom_dict['type'] = 'text' record.custom_fields.append(custom_dict) api.add_record(params, record) elif (params.command == 'h'): display.formatted_history(stack) elif (params.command == 'debug'): if params.debug: params.debug = False print('Debug OFF') else: params.debug = True print('Debug ON') elif params.command == '': pass else: print('\n\nShell Commands:\n') print(' d ... download & decrypt data') print(' l ... list folders and record titles') print(' lsf ... list shared folders') print(' lt ... list teams') print(' s <regex> ... search with regular expression') print(' g <uid> ... get record or shared folder details for uid') print(' r <uid> ... rotate password for uid') print( ' b <regex> ... rotate password for matches of regular expression' ) print(' a ... add a new record interactively') print(' an <uid> ... append some notes to the specified record') print(' c ... clear the screen') print(' h ... show command history') print(' q ... quit') print('') if params.command: if params.command != 'h': stack.append(params.command) stack.reverse() return True
def _import(params, file_format, filename, **kwargs): api.sync_down(params) shared = kwargs.get('shared') or False importer = importer_for_format(file_format)() """:type : BaseImporter""" records_before = len(params.record_cache) folders = [] # type: [ImportSharedFolder] records = [] # type: [ImportRecord] for x in importer.execute(filename): if type(x) is ImportRecord: if shared: if x.folders: for f in x.folders: d_comps = list(path_components( f.domain)) if f.domain else [] p_comps = list(path_components( f.path)) if f.path else [] if len(d_comps) > 0: f.domain = d_comps[0] p_comps[0:0] = d_comps[1:] elif len(p_comps) > 0: f.domain = p_comps[0] p_comps = p_comps[1:] f.path = PathDelimiter.join([ x.replace(PathDelimiter, 2 * PathDelimiter) for x in p_comps ]) records.append(x) elif type(x) is ImportSharedFolder: if shared: continue folders.append(x) if shared: manage_users = kwargs.get('manage_users') or False manage_records = kwargs.get('manage_records') or False can_edit = kwargs.get('can_edit') or False can_share = kwargs.get('can_share') or False sfol = set() for r in records: if r.folders: for f in r.folders: if f.domain: sfol.add(f.domain) for x in sfol: sf = ImportSharedFolder() sf.path = x sf.manage_users = manage_users sf.manage_records = manage_records sf.can_edit = can_edit sf.can_share = can_share folders.append(sf) if folders: shared_folder_add = prepare_shared_folder_add(params, folders) api.execute_batch(params, shared_folder_add) api.sync_down(params) if records: # create folders folder_add = prepare_folder_add(params, records) api.execute_batch(params, folder_add) api.sync_down(params) # create records record_adds = prepare_record_add(params, records) api.execute_batch(params, record_adds) api.sync_down(params) # ensure records are linked to folders record_links = prepare_record_link(params, records) api.execute_batch(params, record_links) api.sync_down(params) # adjust shared folder permissions shared_update = prepare_record_permission(params, records) api.execute_batch(params, shared_update) api.sync_down(params) # upload attachments atts = [] for r in records: if r.attachments: r_uid = r.uid for a in r.attachments: atts.append((r_uid, a)) if len(atts) > 0: upload_attachment(params, atts) records_after = len(params.record_cache) if records_after > records_before: logging.info("%d records imported successfully", records_after - records_before)
def get_synced_params(): p = get_connected_params() with mock.patch('keepercommander.api.communicate') as mock_comm: mock_comm.return_value = get_sync_down_response() api.sync_down(p) return p
def do_command(params): if (params.command == 'q'): return False elif (params.command == 'l'): if (len(params.record_cache) == 0): print('No records') else: results = api.search_records(params, '') display.formatted_records(results) elif (params.command[:2] == 'g '): r = api.get_record(params, params.command[2:]) if r: r.display() elif (params.command[:2] == 'r '): api.rotate_password(params, params.command[2:]) elif (params.command == 'c'): print(chr(27) + "[2J") elif (params.command[:2] == 's '): results = api.search_records(params, params.command[2:]) display.formatted_records(results) elif (params.command[:2] == 'b '): results = api.search_records(params, params.command[2:]) for r in results: api.rotate_password(params, r.record_uid) elif (params.command == 'd'): api.sync_down(params) elif (params.command == 'a'): api.add_record(params) elif (params.command == 'h'): display.formatted_history(stack) elif (params.command == 'debug'): if params.debug: params.debug = False print('Debug OFF') else: params.debug = True print('Debug ON') elif params.command == '': pass else: print('\n\nCommands:\n') print(' d ... download & decrypt data') print(' l ... list folders and titles') print(' s <regex> ... search with regular expression') print(' g <uid> ... get record details for uid') print(' r <uid> ... rotate password for uid') print(' b <regex> ... rotate password for matches of regular expression') print(' a ... add a new record interactively') print(' c ... clear the screen') print(' h ... show command history') print(' q ... quit') print('') if params.command: if params.command != 'h': stack.append(params.command) stack.reverse() return True
def export(params, file_format, filename, **export_args): api.sync_down(params) exporter = exporter_for_format(file_format)() # type: BaseExporter if export_args: if 'max_size' in export_args: exporter.max_size = int(export_args['max_size']) to_export = [] if exporter.has_shared_folders(): shfolders = [ api.get_shared_folder(params, sf_uid) for sf_uid in params.shared_folder_cache ] shfolders.sort(key=lambda x: x.name.lower(), reverse=False) for f in shfolders: fol = ImportSharedFolder() fol.uid = f.shared_folder_uid fol.path = get_folder_path(params, f.shared_folder_uid) fol.manage_users = f.default_manage_users fol.manage_records = f.default_manage_records fol.can_edit = f.default_can_edit fol.can_share = f.default_can_share fol.permissions = [] if f.teams: for team in f.teams: perm = ImportPermission() perm.uid = team['team_uid'] perm.name = team['name'] perm.manage_users = team['manage_users'] perm.manage_records = team['manage_records'] fol.permissions.append(perm) if f.users: for user in f.users: perm = ImportPermission() perm.name = user['username'] perm.manage_users = user['manage_users'] perm.manage_records = user['manage_records'] fol.permissions.append(perm) to_export.append(fol) sf_count = len(to_export) records = [ api.get_record(params, record_uid) for record_uid in params.record_cache ] records.sort(key=lambda x: x.title.lower(), reverse=False) for r in records: rec = ImportRecord() rec.uid = r.record_uid rec.title = r.title.strip('\x00') if r.title else '' rec.login = r.login.strip('\x00') if r.login else '' rec.password = r.password.strip('\x00') if r.password else '' rec.login_url = r.login_url.strip('\x00') if r.login_url else '' rec.notes = r.notes.strip('\x00') if r.notes else '' for cf in r.custom_fields: name = cf.get('name') value = cf.get('value') if name and value: rec.custom_fields[name] = value if r.totp: rec.custom_fields[TWO_FACTOR_CODE] = r.totp for folder_uid in find_folders(params, r.record_uid): if folder_uid in params.folder_cache: folder = get_import_folder(params, folder_uid, r.record_uid) if rec.folders is None: rec.folders = [] rec.folders.append(folder) if exporter.has_attachments() and r.attachments: rec.attachments = [] names = set() for a in r.attachments: orig_name = a.get('title') or a.get('name') or 'attachment' name = orig_name counter = 0 while name in names: counter += 1 name = "{0}-{1}".format(orig_name, counter) names.add(name) atta = KeeperAttachment(params, rec.uid) atta.file_id = a['id'] atta.name = name atta.size = a['size'] atta.key = base64.urlsafe_b64decode(a['key'] + '==') atta.mime = a.get('type') or '' rec.attachments.append(atta) to_export.append(rec) rec_count = len(to_export) - sf_count if len(to_export) > 0: exporter.execute(filename, to_export) params.queue_audit_event('exported_records', file_format=file_format) logging.info('%d records exported', rec_count)
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 _import(params, file_format, filename, **kwargs): api.sync_down(params) shared = kwargs.get('shared') or False import_into = kwargs.get('import_into') or '' if import_into: import_into = import_into.replace(PathDelimiter, 2 * PathDelimiter) importer = importer_for_format(file_format)() # type: BaseImporter records_before = len(params.record_cache) folders = [] # type: [ImportSharedFolder] records = [] # type: [ImportRecord] for x in importer.execute(filename): if type(x) is ImportRecord: if shared or import_into: if not x.folders: x.folders = [ImportFolder()] for f in x.folders: if shared: d_comps = list(path_components( f.domain)) if f.domain else [] p_comps = list(path_components( f.path)) if f.path else [] if len(d_comps) > 0: f.domain = d_comps[0] p_comps[0:0] = d_comps[1:] elif len(p_comps) > 0: f.domain = p_comps[0] p_comps = p_comps[1:] f.path = PathDelimiter.join([ x.replace(PathDelimiter, 2 * PathDelimiter) for x in p_comps ]) if import_into: if f.domain: f.domain = PathDelimiter.join( [import_into, f.domain]) elif f.path: f.path = PathDelimiter.join([import_into, f.path]) else: f.path = import_into x.validate() records.append(x) elif type(x) is ImportSharedFolder: if shared: continue x.validate() if import_into: if x.path: x.path = PathDelimiter.join([import_into, x.path]) folders.append(x) if shared: manage_users = kwargs.get('manage_users') or False manage_records = kwargs.get('manage_records') or False can_edit = kwargs.get('can_edit') or False can_share = kwargs.get('can_share') or False sfol = set() for r in records: if r.folders: for f in r.folders: if f.domain: sfol.add(f.domain) for x in sfol: sf = ImportSharedFolder() sf.path = x sf.manage_users = manage_users sf.manage_records = manage_records sf.can_edit = can_edit sf.can_share = can_share folders.append(sf) folder_add = prepare_folder_add(params, folders, records) if folder_add: fol_rs, _ = execute_import_folder_record(params, folder_add, None) api.sync_down(params) if folders: permissions = prepare_folder_permission(params, folders) if permissions: api.execute_batch(params, permissions) api.sync_down(params) if records: # create records record_add = prepare_record_add(params, records) if record_add: _, rec_rs = execute_import_folder_record(params, None, record_add) api.sync_down(params) # ensure records are linked to folders record_links = prepare_record_link(params, records) if record_links: api.execute_batch(params, record_links) api.sync_down(params) # adjust shared folder permissions shared_update = prepare_record_permission(params, records) if shared_update: api.execute_batch(params, shared_update) api.sync_down(params) # upload attachments atts = [] for r in records: if r.attachments: r_uid = r.uid for a in r.attachments: atts.append((r_uid, a)) if len(atts) > 0: upload_attachment(params, atts) records_after = len(params.record_cache) if records_after > records_before: params.queue_audit_event('imported_records', file_format=file_format.upper()) logging.info("%d records imported successfully", records_after - records_before)
# Copyright 2018 Keeper Security Inc. # Contact: [email protected] # # Example showing how to add a new or existing record # to an existing shared folder. # from keepercommander.params import KeeperParams from keepercommander import api from keepercommander.commands.record import RecordAddCommand params = KeeperParams() # Inputs - hard coded for demo purposes params.user = '******' params.password = '******' shared_folder_uid = 'your_shared_folder_uid' # Login and sync api.sync_down(params) command = RecordAddCommand() record_uid = command.execute(params, title='Test Record', login='******', url='https://google.com', folder=shared_folder_uid, generate=True, force=True) print('Added record to shared folder')