Example #1
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)
Example #2
0
def build_hash_dict(params, tokenize_gen):
    """Return a dict of hashes to record uid's with a parameterized tokenizing generator."""
    preexisting_record_hash = {}
    for preexisting_r_uid in params.record_cache:
        preexisting_rec = api.get_record(params, preexisting_r_uid)
        preexisting_record_hash[build_record_hash(preexisting_rec, tokenize_gen)] = preexisting_r_uid
    return preexisting_record_hash
def create_or_update_record(params, criteria):
    # Scan vault for shared folder

    sfs = api.search_shared_folders(params, criteria)
    if len(sfs) == 0:
        print(f'Shared folder {criteria} not found')
        return
    shared_folder = sfs[0]
    record_title = 'Test Record'
    record_uid = None
    if shared_folder.records:
        records = [api.get_record(params, x['record_uid']) for x in shared_folder.records]
        record_uid = next((x.record_uid for x in records if x.title.casefold() == record_title.casefold()), None)

    shared_folder_uid = shared_folder.shared_folder_uid
    if record_uid:
        command = RecordEditCommand()
        command.execute(params, record=record_uid, generate=True)
        print(f'Updated record {record_uid} in shared folder uid={shared_folder_uid}')
    else:
        command = RecordAddCommand()
        # Inputs - hard coded for demo purposes
        record_uid = command.execute(
            params,
            title='Test Record',
            login='******',
            folder=shared_folder_uid,
            generate=True,
            # force=True disables asking for missing fields
            force=True)
        print(f'Added record {record_uid} to shared folder uid={shared_folder_uid}')
Example #4
0
    def test_upload_attachment_command(self):
        params = get_synced_params()
        cmd = recordv2.RecordUploadAttachmentCommand()

        record_uid = next(
            iter([
                x['record_uid'] for x in params.record_cache.values()
                if len(x['extra_unencrypted']) > 10
            ]))
        rec = api.get_record(params, record_uid)

        with self.assertRaises(CommandError):
            cmd.execute(params, record=rec.title)

        def request_upload(rq):
            self.assertEqual(rq['command'], 'request_upload')
            return {
                'file_uploads': [{
                    'max_size': 1000000,
                    'url': 'https://keepersecurity.com/uploads/',
                    'success_status_code': 201,
                    'file_id': 'ABCDEF%.2d' % x,
                    'file_parameter': 'file',
                    'parameters': {
                        'a': 'b'
                    }
                } for x in range((rq.get('file_count') or 0) +
                                 (rq.get('thumbnail_count') or 0))]
            }

        def request_http_post(url, **kwargs):
            attachment = mock.Mock()
            attachment.status_code = 201
            return attachment

        with mock.patch('requests.post', side_effect=request_http_post), \
                mock.patch('builtins.open', mock.mock_open(read_data=b'data')) as m_open, \
                mock.patch('os.path.isfile', return_value=True), \
                mock.patch('os.path.getsize') as mock_getsize:

            m_open.return_value.tell = lambda: 4
            mock_getsize.return_value = 1000000000
            with self.assertRaises(CommandError):
                KeeperApiHelper.communicate_expect([request_upload])
                cmd.execute(params, file=['file.data'], record=record_uid)
                self.assertTrue(KeeperApiHelper.is_expect_empty())

            KeeperApiHelper.communicate_expect(
                [request_upload, 'record_update'])
            m_open.return_value.tell = lambda: 4
            mock_getsize.return_value = 1000
            cmd.execute(params, file=['file.data'], record=record_uid)
            self.assertTrue(KeeperApiHelper.is_expect_empty())
Example #5
0
    def test_delete_attachment_command(self):
        params = get_synced_params()
        cmd = recordv2.RecordDeleteAttachmentCommand()

        record_uid = next(
            iter([
                x['record_uid'] for x in params.record_cache.values()
                if len(x['extra_unencrypted']) > 10
            ]))
        rec = api.get_record(params, record_uid)

        KeeperApiHelper.communicate_expect(['record_update'])
        cmd.execute(params, name=[rec.attachments[0]['id']], record=rec.title)
        self.assertTrue(KeeperApiHelper.is_expect_empty())
Example #6
0
    def test_remove_command_from_root(self):
        params = get_synced_params()
        cmd = recordv2.RecordRemoveCommand()

        record_uid = next(iter(params.subfolder_record_cache['']))
        rec = api.get_record(params, record_uid)

        def pre_delete_command(rq):
            self.assertEqual(rq['command'], 'pre_delete')
            return {
                'pre_delete_response': {
                    'would_delete': {
                        'deletion_summary': ['delete all']
                    },
                    'pre_delete_token': 'token'
                }
            }

        with mock.patch('keepercommander.commands.recordv2.user_choice'
                        ) as choice_mock:
            choice_mock.return_value = KeyboardInterrupt()
            KeeperApiHelper.communicate_expect([pre_delete_command, 'delete'])
            cmd.execute(params, force=True, record=rec.record_uid)
            self.assertTrue(KeeperApiHelper.is_expect_empty())

            KeeperApiHelper.communicate_expect([pre_delete_command, 'delete'])
            cmd.execute(params, force=True, record=rec.title)
            self.assertTrue(KeeperApiHelper.is_expect_empty())

            with mock.patch('builtins.print'):
                choice_mock.return_value = 'y'
                KeeperApiHelper.communicate_expect(
                    [pre_delete_command, 'delete'])
                cmd.execute(params, record=rec.record_uid)
                self.assertTrue(KeeperApiHelper.is_expect_empty())

                KeeperApiHelper.communicate_expect(
                    [pre_delete_command, 'delete'])
                cmd.execute(params, record=rec.title)
                self.assertTrue(KeeperApiHelper.is_expect_empty())

                choice_mock.return_value = 'n'
                KeeperApiHelper.communicate_expect([pre_delete_command])
                cmd.execute(params, record=rec.record_uid)
                self.assertTrue(KeeperApiHelper.is_expect_empty())

                KeeperApiHelper.communicate_expect([pre_delete_command])
                cmd.execute(params, record=rec.title)
                self.assertTrue(KeeperApiHelper.is_expect_empty())
Example #7
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))
Example #8
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))
Example #9
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)))
Example #10
0
     password = sys.argv[2]
 except IndexError:
     try:
         password = os.environ['password']
     except KeyError:
         from getpass import getpass
         password = getpass('Password:'******'user': user, 'password': password}
 params = params.KeeperParams()  # config=config)
 params.user = user
 params.password = password
 session_token = api.login(params)
 # extractor = URLExtract()
 with open(f"{__file__}.output", mode='a') as o_f:
     for record_uid in params.record_cache:
         rec = api.get_record(params, record_uid)
         try:
             base_url = extract_base(rec.login_url)
         except (MatchError, IndexError):
             logger.debug(
                 f"Login URL ({rec.login_url}) error at record uid: {record_uid}"
             )  # base_url = ('', '')
         else:
             # title = rec.title
             home_url = '://'.join(base_url)
             # urls_in_title = extractor.find_urls(rec.title)
             for url_in_title in urls_in_title:  # if not title:  # if title is empty
                 # print("No title at record_uid:%s" % record_uid)
                 # res.encoding = res.apparent_encoding()
                 # req = request.Request(home_url)
                 # with request.urlopen(req) as res:
        except KeyError:
            user = input("User:"******"Exitting because of over repeat limit {repeat}")
            break
        rec = api.get_record(params, uid)
        if rec.login_url == sn_url:
            rec.login_url = ''  # set string empty
            api.update_record(params, rec)
            logger.info(f"sn_url is erased at {uid} : {rec.title}")

    exit(0)  # to suppress warning of 'Exit without exit code'
Example #12
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')
Example #13
0
    def test_vault_commands(self):
        params = TestConnectedCommands.params  # type: KeeperParams
        with mock.patch(
                'builtins.input',
                side_effect=KeyboardInterrupt()), mock.patch('builtins.print'):
            cli.do_command(
                params,
                'add  --login="******" --pass=password --url="https://keepersecurity.com/" --custom="{\\"cmdr:plugin\\":\\"noop\\"}" "Record 1"'
            )
            cli.do_command(params, 'sync-down')

            record_uid = next(iter(params.record_cache.keys()))
            rec = api.get_record(params, record_uid)

            self.assertEqual(rec.get('cmdr:plugin'), 'noop')
            old_password = rec.password
            cli.do_command(params, 'r -- {0}'.format(rec.record_uid))
            cli.do_command(params, 'sync-down')
            rec = api.get_record(params, record_uid)
            self.assertNotEqual(old_password, rec.password)

            cli.do_command(params, 'ls -l')
            cli.do_command(params, 'mkdir --user-folder "User Folder 1"')
            cli.do_command(params,
                           'mkdir --shared-folder --all "Shared Folder 1"')
            cli.do_command(params, 'sync-down')
            cli.do_command(params, 'cd "User Folder 1"')
            cli.do_command(params, 'mkdir --user-folder "User Folder 2"')
            cli.do_command(params, 'cd /')
            cli.do_command(params, 'ln "Record 1" "Shared Folder 1"')
            cli.do_command(params, 'mv "Record 1" "User Folder 1"')
            params.revision = 0
            cli.do_command(params, 'sync-down')
            self.assertEqual(len(params.record_cache), 1)
            self.assertEqual(len(params.shared_folder_cache), 1)

            cli.do_command(params, 'cd "Shared Folder 1"')
            cli.do_command(
                params, 'append-notes --notes="Additional info" "Record 1"')
            cli.do_command(params, 'sync-down')
            cli.do_command(params, 'cd "../User Folder 1"')
            cli.do_command(params, 'rmdir --force "User Folder 2"')
            cli.do_command(params, 'sync-down')

            cli.do_command(params, 'cd /')
            cli.do_command(params, 'search record')
            cli.do_command(params, 'search folder')

            with tempfile.NamedTemporaryFile() as f:
                f.write(b'data')
                f.flush()
                cli.do_command(params, 'cd "User Folder 1"')
                cli.do_command(
                    params,
                    'upload-attachment --file="{0}" "Record 1"'.format(f.name))
            cli.do_command(params, 'sync-down')

            with mock.patch('builtins.open',
                            mock.mock_open()) as m_open, mock.patch(
                                'os.path.abspath', return_value='file/path'):
                cli.do_command(params,
                               'download-attachment -- {0}'.format(record_uid))
                m_open.assert_called()
                m_open.return_value.write.assert_called()

            rec = api.get_record(params, record_uid)
            self.assertEqual(len(rec.attachments), 1)
            cli.do_command(
                params, 'delete-attachment --name={0} -- {1}'.format(
                    rec.attachments[0]['id'], record_uid))
            cli.do_command(params, 'sync-down')
            rec = api.get_record(params, record_uid)
            self.assertEqual(len(rec.attachments), 0)

            json_text = ''
            with mock.patch('builtins.open',
                            mock.mock_open()) as m_open, mock.patch(
                                'os.path.abspath', return_value='file/path'):

                def file_write(text):
                    nonlocal json_text
                    json_text += text

                m_open.return_value.write = file_write
                cli.do_command(params, 'export --format=json file')
            self.assertTrue(len(json_text) > 0)
            exported = json.loads(json_text)
            self.assertEqual(len(params.record_cache),
                             len(exported['records']))
            self.assertEqual(len(params.shared_folder_cache),
                             len(exported['shared_folders']))

            TestConnectedCommands.wipe_out_data()
            with mock.patch('builtins.open',
                            mock.mock_open()) as m_open, mock.patch(
                                'os.path.isfile', return_value=True):

                def file_read():
                    nonlocal json_text
                    return json_text

                m_open.return_value.read = file_read
                cli.do_command(params, 'import --format=json file')

            self.assertEqual(len(params.record_cache),
                             len(exported['records']))
            self.assertEqual(len(params.shared_folder_cache),
                             len(exported['shared_folders']))
Example #14
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)
Example #15
0
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
Example #16
0
    def test_commands(self):
        params = TestConnectedCommands.params  # type: KeeperParams
        with mock.patch(
                'builtins.input',
                side_effect=KeyboardInterrupt()), mock.patch('builtins.print'):
            record_uid = cli.do_command(
                params,
                'add  --legacy --login="******" --pass=password --url="https://keepersecurity.com/" --custom="{\\"cmdr:plugin\\":\\"noop\\"}" --title="Record 1"'
            )
            cli.do_command(params, 'sync-down')

            rec = api.get_record(params, record_uid)

            self.assertEqual(rec.get('cmdr:plugin'), 'noop')
            old_password = rec.password
            cli.do_command(params, 'rotate -- {0}'.format(rec.record_uid))
            cli.do_command(params, 'sync-down')
            rec = api.get_record(params, record_uid)
            self.assertNotEqual(old_password, rec.password)

            cli.do_command(params, 'ls -l')
            cli.do_command(params, 'mkdir --user-folder "User Folder 1"')
            cli.do_command(params,
                           'mkdir --shared-folder --all "Shared Folder 1"')
            cli.do_command(params, 'sync-down')
            cli.do_command(params, 'cd "User Folder 1"')
            cli.do_command(params, 'mkdir --user-folder "User Folder 2"')
            cli.do_command(params, 'cd /')
            cli.do_command(params, 'ln "Record 1" "Shared Folder 1"')
            cli.do_command(params, 'mv "Record 1" "User Folder 1"')
            params.revision = 0
            cli.do_command(params, 'sync-down')
            self.assertEqual(len(params.record_cache), 1)
            self.assertEqual(len(params.shared_folder_cache), 1)

            cli.do_command(params, 'cd "Shared Folder 1"')
            cli.do_command(
                params, 'append-notes --notes="Additional info" "Record 1"')
            cli.do_command(params, 'sync-down')
            cli.do_command(params, 'cd "../User Folder 1"')
            cli.do_command(params, 'rmdir --force "User Folder 2"')
            cli.do_command(params, 'sync-down')

            cli.do_command(params, 'cd /')
            cli.do_command(params, 'search record')
            cli.do_command(params, 'search folder')

            with tempfile.NamedTemporaryFile(delete=False) as f:
                try:
                    f.write(b'data')
                    f.flush()
                    cli.do_command(params, 'cd "User Folder 1"')
                    cli.do_command(
                        params,
                        'upload-attachment --file="{0}" "Record 1"'.format(
                            f.name))
                    f.close()
                finally:
                    os.remove(f.name)
            cli.do_command(params, 'sync-down')

            rec = api.get_record(params, record_uid)
            self.assertEqual(len(rec.attachments), 1)
            cli.do_command(
                params, 'delete-attachment --name={0} -- {1}'.format(
                    rec.attachments[0]['id'], record_uid))
            cli.do_command(params, 'sync-down')
            rec = api.get_record(params, record_uid)
            self.assertEqual(len(rec.attachments), 0)

            script_path = os.path.dirname(__file__)
            cwd = os.getcwd()
            if script_path.startswith(cwd):
                script_path = script_path[len(cwd):]
                if script_path.startswith(os.sep):
                    script_path = script_path[1:]
            file = 'keepass.kdbx'
            if script_path:
                file = os.path.join(script_path, file)
            if os.path.isfile(file):
                os.remove(file)

            with mock.patch('getpass.getpass',
                            return_value='password'), mock.patch(
                                'keepercommander.commands.base.user_choice',
                                return_value='y'):
                cli.do_command(params,
                               'export --format=keepass "{0}"'.format(file))

            TestConnectedCommands.wipe_out_data()
            cli.do_command(params, 'sync-down')

            with mock.patch('getpass.getpass',
                            return_value='password'), mock.patch(
                                'builtins.input', return_value=''):
                cli.do_command(params,
                               'import --format=keepass "{0}"'.format(file))
            cli.do_command(params, 'sync-down')

            json_text = ''
            with mock.patch('builtins.open',
                            mock.mock_open()) as m_open, mock.patch(
                                'os.path.abspath', return_value='file/path'):

                def file_write(text):
                    nonlocal json_text
                    json_text += text

                m_open.return_value.write = file_write
                cli.do_command(params, 'export --format=json file')
            self.assertTrue(len(json_text) > 0)
            exported = json.loads(json_text)
            self.assertEqual(len(params.record_cache),
                             len(exported['records']))
            self.assertEqual(len(params.shared_folder_cache),
                             len(exported['shared_folders']))

            TestConnectedCommands.wipe_out_data()
            with mock.patch('builtins.open',
                            mock.mock_open()) as m_open, mock.patch(
                                'os.path.isfile', return_value=True):

                def file_read():
                    nonlocal json_text
                    return json_text

                m_open.return_value.read = file_read
                cli.do_command(params, 'import --format=json file')

            self.assertEqual(len(params.record_cache),
                             len(exported['records']))
            self.assertEqual(len(params.shared_folder_cache),
                             len(exported['shared_folders']))
Example #17
0
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
Example #18
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
Example #19
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
Example #20
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