Exemplo n.º 1
0
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)
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
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
Exemplo n.º 5
0
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)
Exemplo n.º 6
0
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')
Exemplo n.º 7
0
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)
Exemplo n.º 8
0
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)
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
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)
Exemplo n.º 11
0
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)
Exemplo n.º 12
0
    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)
Exemplo n.º 13
0
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)
Exemplo n.º 14
0
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))
Exemplo n.º 15
0
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)))
Exemplo n.º 16
0
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)))
Exemplo n.º 17
0
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)))
Exemplo n.º 18
0
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))
Exemplo n.º 19
0
    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)
Exemplo n.º 20
0
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)
Exemplo n.º 21
0
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)
Exemplo n.º 22
0
    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
Exemplo n.º 24
0
                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')
Exemplo n.º 25
0
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
Exemplo n.º 26
0
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
Exemplo n.º 27
0
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)
Exemplo n.º 28
0
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
Exemplo n.º 29
0
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
Exemplo n.º 30
0
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)
Exemplo n.º 31
0
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)
Exemplo n.º 32
0
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')