From 8e345324b3e8ccbeefde89c8c59c0bf1cc4b511c Mon Sep 17 00:00:00 2001 From: adeshmukh-ks Date: Wed, 15 Jul 2026 22:22:45 +0530 Subject: [PATCH] NSF folder and record support in PAM Commands --- keepercommander/commands/base.py | 5 + .../commands/credential_provision.py | 107 +-- keepercommander/commands/discoveryrotation.py | 437 ++++++---- .../commands/discoveryrotation_v1.py | 7 +- keepercommander/commands/folder.py | 10 +- keepercommander/commands/ksm.py | 489 +++++++++--- .../nested_share_folder/folder_commands.py | 38 +- .../commands/nested_share_folder/helpers.py | 29 +- .../commands/nested_share_folder/parsers.py | 16 + .../nested_share_folder/record_commands.py | 7 +- .../nested_share_folder/sharing_commands.py | 38 +- keepercommander/commands/pam/config_helper.py | 118 ++- keepercommander/commands/pam/vault_target.py | 680 ++++++++++++++++ .../pam_cloud/pam_privileged_access.py | 20 +- keepercommander/commands/pam_import/README.md | 3 +- keepercommander/commands/pam_import/base.py | 14 +- keepercommander/commands/pam_import/edit.py | 154 +++- keepercommander/commands/pam_import/export.py | 12 +- keepercommander/commands/pam_import/extend.py | 197 +++-- .../commands/pam_import/nsf_helpers.py | 311 ++++++++ .../commands/pam_import/record_loader.py | 67 ++ .../commands/tunnel_and_connections.py | 18 +- .../nested_share_folder/__init__.py | 7 +- .../nested_share_folder/folder_api.py | 135 +++- .../nested_share_folder/folder_record_api.py | 3 +- .../nested_share_folder/record_api.py | 155 +++- keepercommander/nested_share_folder/sync.py | 9 + keepercommander/proto/AccountSummary_pb2.py | 4 +- keepercommander/proto/AccountSummary_pb2.pyi | 22 +- keepercommander/proto/GraphSync_pb2.pyi | 2 +- keepercommander/proto/SyncDown_pb2.pyi | 32 +- keepercommander/proto/dag_pb2.pyi | 2 +- keepercommander/proto/enterprise_pb2.py | 753 +++++++++--------- keepercommander/proto/enterprise_pb2.pyi | 161 ++-- keepercommander/proto/folder_access_pb2.pyi | 2 +- keepercommander/proto/folder_pb2.py | 104 +-- keepercommander/proto/folder_pb2.pyi | 24 +- keepercommander/proto/pagination_pb2.pyi | 2 +- keepercommander/proto/record_endpoints_pb2.py | 4 +- .../proto/record_endpoints_pb2.pyi | 6 +- keepercommander/proto/record_pb2.py | 312 ++++---- keepercommander/proto/record_pb2.pyi | 32 +- keepercommander/proto/record_sharing_pb2.pyi | 4 +- keepercommander/proto/remove_pb2.py | 42 +- keepercommander/proto/remove_pb2.pyi | 74 ++ keepercommander/proto/tla_pb2.pyi | 2 +- keepercommander/sync_down.py | 16 +- keepercommander/vault_extensions.py | 63 +- tests/test_pam_privileged_cloud.py | 3 +- unit-tests/pam/test_pam_nsf_config.py | 509 ++++++++++++ unit-tests/pam/test_pam_project_export.py | 100 ++- unit-tests/pam/test_pam_project_extend_nsf.py | 112 +++ .../test_pam_project_extend_nsf_helpers.py | 114 +++ unit-tests/pam/test_pam_project_import_nsf.py | 330 ++++++++ unit-tests/pam/test_pam_provision_nsf.py | 137 ++++ unit-tests/pam/test_pam_rotation.py | 242 +++++- unit-tests/pam/test_pam_split_nsf.py | 117 +++ unit-tests/test_command_ksm.py | 165 ++++ unit-tests/test_nested_share_folder.py | 182 ++++- 59 files changed, 5442 insertions(+), 1318 deletions(-) create mode 100644 keepercommander/commands/pam/vault_target.py create mode 100644 keepercommander/commands/pam_import/nsf_helpers.py create mode 100644 keepercommander/commands/pam_import/record_loader.py create mode 100644 unit-tests/pam/test_pam_nsf_config.py create mode 100644 unit-tests/pam/test_pam_project_extend_nsf.py create mode 100644 unit-tests/pam/test_pam_project_extend_nsf_helpers.py create mode 100644 unit-tests/pam/test_pam_project_import_nsf.py create mode 100644 unit-tests/pam/test_pam_provision_nsf.py create mode 100644 unit-tests/pam/test_pam_split_nsf.py diff --git a/keepercommander/commands/base.py b/keepercommander/commands/base.py index cba03f2dc..572e0f8c0 100644 --- a/keepercommander/commands/base.py +++ b/keepercommander/commands/base.py @@ -915,6 +915,11 @@ def resolve_single_record(params, record_name): # type: (KeeperParams, str) -> if record_name in params.record_cache: return vault.KeeperRecord.load(params, record_name) + from .pam_import.record_loader import load_pam_record + rec = load_pam_record(params, record_name) + if rec: + return rec + rs = try_resolve_path(params, record_name) if rs is None: return None diff --git a/keepercommander/commands/credential_provision.py b/keepercommander/commands/credential_provision.py index b1a9008bd..5029b2b6d 100644 --- a/keepercommander/commands/credential_provision.py +++ b/keepercommander/commands/credential_provision.py @@ -47,11 +47,12 @@ from .. import api, vault, vault_extensions, crypto, utils, generator from ..error import CommandError from ..params import KeeperParams -from ..subfolder import try_resolve_path, get_folder_path -from ..record_management import add_record_to_folder +from ..subfolder import try_resolve_path from ..record_facades import LoginRecordFacade from ..proto import APIRequest_pb2 from ..commands.folder import FolderMakeCommand +from ..commands.pam.vault_target import ( + create_record_in_folder, records_in_folder, resolve_provision_target_folder) # RecordLink and discoveryrotation require pydantic (Python 3.8+) try: @@ -1313,35 +1314,24 @@ def _check_duplicate_by_username_in_folder(self, config: Dict[str, Any], params: username = config['account']['username'] pam_config_uid = config['account']['pam_config_uid'] - # Get the same folder path that will be used for PAM User creation try: - gateway_folder_uid, gateway_folder_path = self._get_gateway_application_folder(pam_config_uid, params) + folder_uid = self._resolve_pam_user_folder_uid(config, params) except Exception as e: + logging.warning( + f'Could not resolve target folder for duplicate username check ' + f'(username={username}, PAM config={pam_config_uid}): {e}' + ) return False - # Determine target folder (same logic as _create_pam_user) - user_specified_folder = config.get('vault', {}).get('folder') - - if user_specified_folder: - target_folder_path = f"{gateway_folder_path}/{user_specified_folder.strip('/')}" - else: - department = config['user'].get('department', 'Default') - target_folder_path = f"{gateway_folder_path}/PAM Users/{department}" - - # Get folder UID - folder_uid = self._get_folder_uid(target_folder_path, params) - if not folder_uid: return False - # Get all records in this folder - records_in_folder = params.subfolder_record_cache.get(folder_uid, set()) - - if not records_in_folder: + records_in_folder_set = records_in_folder(params, folder_uid) + if not records_in_folder_set: return False # Search for PAM Users in folder with matching username - for record_uid in records_in_folder: + for record_uid in records_in_folder_set: try: record = vault.KeeperRecord.load(params, record_uid) @@ -1358,7 +1348,7 @@ def _check_duplicate_by_username_in_folder(self, config: Dict[str, Any], params: if facade.login == username: logging.error(f'❌ Duplicate PAM User found (by username in folder):') logging.error(f' Username: {username}') - logging.error(f' Folder: {target_folder_path}') + logging.error(f' Folder UID: {folder_uid}') logging.error(f' Existing UID: {record_uid}') logging.error(f' Title: {record.title}') return True @@ -1481,28 +1471,7 @@ def _create_pam_user( username = config['account']['username'] pam_config_uid = config['account']['pam_config_uid'] - # Get gateway application folder from PAM Config - gateway_folder_uid, gateway_folder_path = self._get_gateway_application_folder(pam_config_uid, params) - - # Determine target folder - user_specified_folder = config.get('vault', {}).get('folder') - - if user_specified_folder: - # Check if the value is a folder UID (exists in folder cache) - if user_specified_folder in params.folder_cache: - folder_uid = user_specified_folder - elif user_specified_folder in params.shared_folder_cache: - folder_uid = user_specified_folder - else: - # Treat as a relative folder path - self._validate_folder_path(user_specified_folder) - target_folder_path = f"{gateway_folder_path}/{user_specified_folder.strip('/')}" - folder_uid = self._ensure_folder_exists(target_folder_path, params) - else: - # Auto-generate subfolder based on department - department = config['user'].get('department', 'Default') - target_folder_path = f"{gateway_folder_path}/PAM Users/{department}" - folder_uid = self._ensure_folder_exists(target_folder_path, params) + folder_uid = self._resolve_pam_user_folder_uid(config, params) # Create PAM User typed record pam_user = vault.TypedRecord() @@ -1576,7 +1545,7 @@ def _create_pam_user( try: # Create record in vault and add to folder - add_record_to_folder(params, pam_user, folder_uid) + create_record_in_folder(params, pam_user, folder_uid, command='credential-provision') # Sync to get the record UID api.sync_down(params) @@ -1619,6 +1588,20 @@ def _validate_folder_path(self, folder_path: str) -> None: f"Example: 'PAM Users/Engineering' (not '/Shared Folders/...')" ) + def _resolve_pam_user_folder_uid(self, config: Dict[str, Any], params: KeeperParams) -> str: + pam_config_uid = config['account']['pam_config_uid'] + user_specified_folder = config.get('vault', {}).get('folder') + if user_specified_folder: + self._validate_folder_path(user_specified_folder) + department = config.get('user', {}).get('department', 'Default') + return resolve_provision_target_folder( + params, + pam_config_uid, + folder_spec=user_specified_folder, + department=department, + command='credential-provision', + ) + def _get_gateway_application_folder(self, pam_config_uid: str, params: KeeperParams) -> Tuple[str, str]: """ Get gateway application folder from PAM Configuration. @@ -1636,35 +1619,11 @@ def _get_gateway_application_folder(self, pam_config_uid: str, params: KeeperPar Raises: ValueError: If PAM Config not found or folder not accessible """ - - # Load PAM Config record - pam_config_record = vault.KeeperRecord.load(params, pam_config_uid) - if not pam_config_record: - raise ValueError(f"PAM Configuration not found: {pam_config_uid}") - - # Use facade to access folder_uid - facade = PamConfigurationRecordFacade() - facade.record = pam_config_record - facade.load_typed_fields() - - folder_uid = facade.folder_uid - - if not folder_uid: - raise ValueError( - f"PAM Configuration '{pam_config_record.title}' has no application folder configured.\n" - f"Please configure the application folder in the PAM Configuration record." - ) - - # Get folder path from folder_uid using existing utility - if folder_uid not in params.folder_cache: - raise ValueError( - f"Application folder (UID: {folder_uid}) not found in vault.\n" - f"Ensure the folder is shared with you." - ) - - folder_path = get_folder_path(params, folder_uid) - - return folder_uid, folder_path + from ..commands.pam.vault_target import resolve_pam_application_folder + try: + return resolve_pam_application_folder(params, pam_config_uid, command='credential-provision') + except CommandError as exc: + raise ValueError(str(exc)) from exc def _ensure_folder_exists(self, folder_path: str, params: KeeperParams) -> Optional[str]: """ diff --git a/keepercommander/commands/discoveryrotation.py b/keepercommander/commands/discoveryrotation.py index 221c96da5..a6fbb9cc9 100644 --- a/keepercommander/commands/discoveryrotation.py +++ b/keepercommander/commands/discoveryrotation.py @@ -24,15 +24,20 @@ from keeper_secrets_manager_core.utils import url_safe_str_to_bytes from .base import (Command, GroupCommand, user_choice, dump_report_data, report_output_parser, - json_output_parser, field_to_title, - FolderMixin, RecordMixin, toggle_pam_legacy_commands) -from .folder import FolderMoveCommand + json_output_parser, field_to_title, toggle_pam_legacy_commands) from .ksm import KSMCommand from .pam import gateway_helper, router_helper from .pam.config_facades import PamConfigurationRecordFacade +from .pam.vault_target import ( + format_pam_folder_display, resolve_pam_folder_uid, + resolve_pam_record, record_exists_in_vault, collect_pam_folder_uids, + get_vault_record_title_type, find_pam_records_by_search, + resolve_pam_config_folder_info, pam_folder_json_payload, place_record_in_folder, + create_pam_configuration_in_folder, update_pam_record, records_in_folder, +) from .pam.config_helper import configuration_controller_get, \ pam_configurations_get_all, pam_configuration_remove, \ - pam_configuration_create_record_v6, record_rotation_get, \ + record_rotation_get, \ pam_decrypt_configuration_data from .pam.pam_dto import ( @@ -53,11 +58,12 @@ from .tunnel.port_forward.TunnelGraph import TunnelDAG, get_vertex_content from .tunnel.port_forward.tunnel_helpers import get_config_uid, get_keeper_tokens from .. import api, utils, vault_extensions, crypto, vault, record_management, attachment, record_facades +from ..recordv3 import RecordV3 from ..display import bcolors from ..error import CommandError, KeeperApiError from ..params import KeeperParams, LAST_RECORD_UID from ..proto import pam_pb2, router_pb2, record_pb2, APIRequest_pb2 -from ..subfolder import find_parent_top_folder, try_resolve_path, BaseFolderNode +from ..subfolder import try_resolve_path, BaseFolderNode from ..vault import TypedField from ..discovery_common.record_link import RecordLink from .discover.job_start import PAMGatewayActionDiscoverJobStartCommand @@ -260,6 +266,22 @@ def uses_default_rotation_schedule(params, record_uid, configuration_uid): if not isinstance(record_schedule, list) or len(record_schedule) == 0: return False return record_schedule == default_schedule + +def _valid_record_uids(uids): + return [uid for uid in (uids or []) if RecordV3.is_valid_ref_uid(uid)] + + +def _get_pam_config_resource_uids(pam_config_record): + if not pam_config_record: + return [] + resource_field = pam_config_record.get_typed_field('pamResources') + if resource_field and isinstance(resource_field.value, list) and len(resource_field.value) > 0: + resources = resource_field.value[0] + if isinstance(resources, dict): + refs = resources.get('resourceRef') + if isinstance(refs, list): + return _valid_record_uids(refs) + return [] def register_commands(commands): @@ -488,8 +510,8 @@ class PAMCreateRecordRotationCommand(Command): record_group.add_argument('--record', '-r', dest='record_name', action='store', help='Record UID, name, or pattern to be rotated manually or via schedule') record_group.add_argument('--folder', '-fd', dest='folder_name', action='store', - help='Used for bulk rotation setup. The folder UID or name that holds records to be ' - 'configured') + help='Used for bulk rotation setup. The folder UID or name (including Nested Share ' + 'Folders) that holds records to be configured') parser.add_argument('--force', '-f', dest='force', action='store_true', help='Do not ask for confirmation') parser.add_argument('--config', '-c', required=False, dest='config', action='store', help='UID or path of the configuration record.') @@ -543,7 +565,7 @@ def config_resource(_dag, target_record, target_config_uid, silent=None): # Add DAG for resource if target_config_uid: _dag = TunnelDAG(params, encrypted_session_token, encrypted_transmission_key, target_config_uid, - transmission_key=transmission_key) + is_config=True, transmission_key=transmission_key) _dag.edit_tunneling_config(rotation=True) else: raise CommandError('', f'{bcolors.FAIL}Resource "{target_record.record_uid}" is not associated ' @@ -558,7 +580,7 @@ def config_resource(_dag, target_record, target_config_uid, silent=None): _dag.link_resource_to_config(target_record.record_uid) admin = kwargs.get('admin') - adm_rec = RecordMixin.resolve_single_record(params, kwargs.get('admin', None)) + adm_rec = resolve_pam_record(params, kwargs.get('admin', None), rec_type='pamUser') if adm_rec and isinstance(adm_rec, vault.TypedRecord): admin = adm_rec.record_uid @@ -1197,22 +1219,31 @@ def config_user(_dag, target_record, target_resource_uid, target_config_uid=None f"--admin-user ADMIN{bcolors.ENDC}") current_record_rotation = params.record_rotation_cache.get(target_record.record_uid) - if not _dag or not _dag.linking_dag.has_graph: - _dag = TunnelDAG(params, encrypted_session_token, encrypted_transmission_key, target_resource_uid, - transmission_key=transmission_key) + if target_config_uid and (not _dag or not _dag.linking_dag.has_graph + or _dag.record.record_uid != target_config_uid): + _dag = TunnelDAG(params, encrypted_session_token, encrypted_transmission_key, target_config_uid, + is_config=True, transmission_key=transmission_key) if not _dag.linking_dag.has_graph: - raise CommandError('', f'{bcolors.FAIL}Resource "{target_resource_uid}" is not associated ' + _dag.edit_tunneling_config(rotation=True) + elif not _dag or not _dag.linking_dag.has_graph: + if RecordV3.is_valid_ref_uid(target_resource_uid): + _dag = TunnelDAG(params, encrypted_session_token, encrypted_transmission_key, target_resource_uid, + transmission_key=transmission_key) + if not _dag or not _dag.linking_dag.has_graph: + raise CommandError('', f'{bcolors.FAIL}Record "{target_record.record_uid}" is not associated ' f'with any configuration. ' - f'{bcolors.OKBLUE}pam rotation edit -rs {target_resource_uid} ' - f'--config CONFIG{bcolors.ENDC}') + f'{bcolors.OKBLUE}pam rotation edit -r {target_record.record_uid} ' + f'--config CONFIG [--resource RESOURCE]{bcolors.ENDC}') # Noop and resource cannot be both assigned if noop_rotation: target_resource_uid = target_record.record_uid record_resource_uid = None else: - if not target_resource_uid: + if not RecordV3.is_valid_ref_uid(target_resource_uid): # Get the resource configuration from DAG - resource_uids = _dag.get_all_owners(target_record.record_uid) + resource_uids = _valid_record_uids(_dag.get_all_owners(target_record.record_uid)) + if len(resource_uids) == 0 and pam_config: + resource_uids = _get_pam_config_resource_uids(pam_config) if len(resource_uids) > 1: # When processing folders, skip records with multiple resources if folder_name: @@ -1235,17 +1266,23 @@ def config_user(_dag, target_record, target_resource_uid, target_config_uid=None f'it.{bcolors.ENDC}') target_resource_uid = resource_uids[0] - if not _dag.resource_belongs_to_config(target_resource_uid): + if (RecordV3.is_valid_ref_uid(target_resource_uid) + and not _dag.resource_belongs_to_config(target_resource_uid)): # some rotations (iam_user/noop) link straight to pamConfiguration if target_resource_uid != _dag.record.record_uid: - raise CommandError('', - f'{bcolors.FAIL}Resource "{target_resource_uid}" is not associated with the ' - f'configuration of the user "{target_record.record_uid}". To associated the resources ' - f'to this config run {bcolors.OKBLUE}"pam rotation resource {target_resource_uid} ' - f'--config {_dag.record.record_uid}"{bcolors.ENDC}') - if not _dag.user_belongs_to_resource(target_record.record_uid, target_resource_uid): + if target_config_uid: + _dag.link_resource_to_config(target_resource_uid) + else: + raise CommandError('', + f'{bcolors.FAIL}Resource "{target_resource_uid}" is not associated with the ' + f'configuration of the user "{target_record.record_uid}". To associated the resources ' + f'to this config run {bcolors.OKBLUE}"pam rotation resource {target_resource_uid} ' + f'--config {_dag.record.record_uid}"{bcolors.ENDC}') + if (RecordV3.is_valid_ref_uid(target_resource_uid) + and not _dag.user_belongs_to_resource(target_record.record_uid, target_resource_uid)): old_resource_uid = _dag.get_resource_uid(target_record.record_uid) - if old_resource_uid is not None and old_resource_uid != target_resource_uid: + if (RecordV3.is_valid_ref_uid(old_resource_uid) + and old_resource_uid != target_resource_uid): print( f'{bcolors.WARNING}User "{target_record.record_uid}" is associated with another resource: ' f'{old_resource_uid}. ' @@ -1380,7 +1417,11 @@ def config_user(_dag, target_record, target_resource_uid, target_config_uid=None encrypted_session_token, encrypted_transmission_key, transmission_key = get_keeper_tokens(params) if record_name: - if record_name in params.record_cache: + rec = resolve_pam_record( + params, record_name, rec_type=PamConfigurationEditMixin.ROTATION_TARGET_RECORD_TYPES) + if rec: + record_uids.add(rec.record_uid) + elif record_name in params.record_cache: record_uids.add(record_name) else: rs = try_resolve_path(params, record_name, find_all_matches=True) @@ -1399,24 +1440,11 @@ def config_user(_dag, target_record, target_resource_uid, target_config_uid=None folder_name = kwargs.get('folder_name') if folder_name: - if folder_name in params.folder_cache: - folder_uids.add(folder_name) + collected = collect_pam_folder_uids(params, folder_name) + if collected: + folder_uids.update(collected) else: - rs = try_resolve_path(params, folder_name, find_all_matches=True) - if rs is not None: - folder, record_title = rs - if not record_title: - - def add_folders(sub_folder): # type: (BaseFolderNode) -> None - folder_uids.add(sub_folder.uid or '') - - if isinstance(folder, BaseFolderNode): - folder = [folder] - if isinstance(folder, list): - for f in folder: - FolderMixin.traverse_folder_tree(params, f.uid, add_folders) - else: - logging.warning('Folder \"%s\" not found. Skipping.', folder_name) + logging.warning('Folder \"%s\" not found. Skipping.', folder_name) if record_name and folder_name: raise CommandError('', 'Cannot use both --record and --folder at the same time.') @@ -1424,7 +1452,7 @@ def add_folders(sub_folder): # type: (BaseFolderNode) -> None if folder_uids: regex = re.compile(fnmatch.translate(record_pattern), re.IGNORECASE).match if record_pattern else None for folder_uid in folder_uids: - folder_records = params.subfolder_record_cache.get(folder_uid) + folder_records = records_in_folder(params, folder_uid) if not folder_records: continue if record_pattern and record_pattern in folder_records: @@ -1460,16 +1488,24 @@ def add_folders(sub_folder): # type: (BaseFolderNode) -> None isinstance(x, vault.TypedRecord)} config_uid = kwargs.get('config') - cfg_rec = RecordMixin.resolve_single_record(params, kwargs.get('config', None)) - if cfg_rec and cfg_rec.version == 6 and cfg_rec.record_uid in pam_configurations: + cfg_rec = resolve_pam_record( + params, kwargs.get('config', None), rec_type=PamConfigurationEditMixin.PAM_CONFIG_RECORD_TYPES) + if cfg_rec and cfg_rec.version == 6 and cfg_rec.record_type in PamConfigurationEditMixin.PAM_CONFIG_RECORD_TYPES: config_uid = cfg_rec.record_uid pam_config = None # type: Optional[vault.TypedRecord] if config_uid: if config_uid in pam_configurations: pam_config = pam_configurations[config_uid] + elif cfg_rec and cfg_rec.record_uid == config_uid: + pam_config = cfg_rec else: - raise CommandError('', f'Record uid {config_uid} is not a PAM Configuration record.') + loaded = vault.KeeperRecord.load(params, config_uid) + if (isinstance(loaded, vault.TypedRecord) and loaded.version == 6 + and loaded.record_type in PamConfigurationEditMixin.PAM_CONFIG_RECORD_TYPES): + pam_config = loaded + else: + raise CommandError('', f'Record uid {config_uid} is not a PAM Configuration record.') schedule_data = parse_schedule_data(kwargs) @@ -1504,7 +1540,8 @@ def add_folders(sub_folder): # type: (BaseFolderNode) -> None pwd_complexity_rule_list = {} resource_uid = kwargs.get('resource') - res_rec = RecordMixin.resolve_single_record(params, kwargs.get('resource', None)) + res_rec = resolve_pam_record( + params, kwargs.get('resource', None), rec_type=PamConfigurationEditMixin.PAM_RESOURCE_RECORD_TYPES) if res_rec and isinstance(res_rec, vault.TypedRecord): resource_uid = res_rec.record_uid @@ -1640,8 +1677,10 @@ def execute(self, params, **kwargs): enterprise_all_controllers = list(gateway_helper.get_all_gateways(params)) enterprise_controllers_connected_resp = router_get_connected_gateways(params) - enterprise_controllers_connected_uids_bytes = \ - [x.controllerUid for x in enterprise_controllers_connected_resp.controllers] + enterprise_controllers_connected_uids_bytes = [] + if enterprise_controllers_connected_resp and enterprise_controllers_connected_resp.controllers: + enterprise_controllers_connected_uids_bytes = \ + [x.controllerUid for x in enterprise_controllers_connected_resp.controllers] all_pam_config_records = pam_configurations_get_all(params) table = [] @@ -1676,19 +1715,11 @@ def execute(self, params, **kwargs): (poc for poc in enterprise_controllers_connected_uids_bytes if poc == controller_uid)) row_color = '' - if record_uid in params.record_cache: + if record_exists_in_vault(params, record_uid): row_color = bcolors.HIGHINTENSITYWHITE - rec = params.record_cache[record_uid] - - data_json = rec['data_unencrypted'].decode('utf-8') if isinstance(rec['data_unencrypted'], bytes) else \ - rec['data_unencrypted'] - data = json.loads(data_json) - - record_title = data.get('title') - record_type = data.get('type') or '' + record_title, record_type = get_vault_record_title_type(params, record_uid) else: row_color = bcolors.WHITE - record_title = '[record inaccessible]' record_type = '[record inaccessible]' @@ -1697,8 +1728,8 @@ def execute(self, params, **kwargs): continue row.append(f'{row_color}{record_uid}') - row.append(record_title) - row.append(record_type) + row.append(record_title or '[untitled]') + row.append(record_type or '[unknown]') if s.noSchedule is True: # Per Sergey A: @@ -1753,17 +1784,32 @@ def execute(self, params, **kwargs): f"{bcolors.FAIL}[No config found. Looks like configuration {configuration_uid_str} was removed but rotation schedule was not modified{bcolors.ENDC}") else: - pam_data_decrypted = pam_decrypt_configuration_data(pam_configuration) - pam_config_name = pam_data_decrypted.get('title') - pam_config_type = pam_data_decrypted.get('type') - row.append(f"{pam_config_name} ({pam_config_type})") + pam_config_name, pam_config_type = get_vault_record_title_type(params, configuration_uid_str) + if pam_config_name == '[record inaccessible]': + try: + pam_data_decrypted = pam_decrypt_configuration_data(pam_configuration) + pam_config_name = pam_data_decrypted.get('title') or pam_config_name + pam_config_type = pam_data_decrypted.get('type') or '[unknown]' + except Exception as exc: + logging.warning( + 'Rotation list: PAM configuration %s is not accessible in the vault ' + 'and could not be decrypted from router data: %s', + configuration_uid_str, + exc, + ) + if pam_config_name == '[record inaccessible]': + logging.warning( + 'Rotation list: PAM configuration %s title/type remain inaccessible', + configuration_uid_str, + ) + row.append(f"{pam_config_name or '[untitled]'} ({pam_config_type or '[unknown]'})") if is_verbose: row.append(f'{utils.base64_url_encode(configuration_uid)}{bcolors.ENDC}') table.append(row) - table.sort(key=lambda x: (x[1])) + table.sort(key=lambda x: (x[1] or '')) dump_report_data(table, headers, fmt='table', filename="", row_number=False, column_width=None) @@ -1883,19 +1929,8 @@ def execute(self, params, **kwargs): continue ksm_app_uid_str = utils.base64_url_encode(c.applicationUid) - ksm_app = KSMCommand.get_app_record(params, ksm_app_uid_str) - - if ksm_app: - ksm_app_data_unencrypted_json = ksm_app.get('data_unencrypted') - ksm_app_data_unencrypted_dict = json.loads(ksm_app_data_unencrypted_json) - ksm_app_title = ksm_app_data_unencrypted_dict.get('title') - ksm_app_info_plain = f'{ksm_app_title} ({ksm_app_uid_str})' - ksm_app_name = ksm_app_title - ksm_app_accessible = True - else: - ksm_app_info_plain = f'[APP NOT ACCESSIBLE OR DELETED] ({ksm_app_uid_str})' - ksm_app_name = None - ksm_app_accessible = False + ksm_app_name, ksm_app_accessible, ksm_app_info_plain = KSMCommand.get_ksm_app_display_info( + params, ksm_app_uid_str) # Check if this is gateway pool is_pool = len(connected_instances) > 1 @@ -2256,25 +2291,20 @@ def print_pam_configuration_details(params, config_uid, is_verbose=False, format facade = PamConfigurationRecordFacade() facade.record = configuration - folder_uid = facade.folder_uid - sf = None - if folder_uid in params.shared_folder_cache: - sf = api.get_shared_folder(params, folder_uid) + folder_info = resolve_pam_config_folder_info( + params, facade, configuration.record_uid) if format_type == 'json': config_data = { "uid": configuration.record_uid, "name": configuration.title, "config_type": configuration.record_type, - "shared_folder": { - "name": sf.name if sf else None, - "uid": sf.shared_folder_uid if sf else None - } if sf else None, "gateway_uid": facade.controller_uid, "gateway_name": facade.title, "resource_record_uids": facade.resource_ref, "fields": {} } + config_data.update(pam_folder_json_payload(folder_info)) for field in itertools.chain(configuration.fields, configuration.custom): if field.type in ('pamResources', 'fileRef'): @@ -2303,7 +2333,7 @@ def print_pam_configuration_details(params, config_uid, is_verbose=False, format table.append(['UID', configuration.record_uid]) table.append(['Name', configuration.title]) table.append(['Config Type', configuration.record_type]) - table.append(['Shared Folder', f'{sf.name} ({sf.shared_folder_uid})' if sf else '']) + table.append(['Folder', format_pam_folder_display(folder_info)]) table.append(['Gateway UID', facade.controller_uid]) table.append(['Resource Record UIDs', facade.resource_ref]) @@ -2329,11 +2359,11 @@ def print_root_rotation_setting(params, is_verbose=False, format_type='table'): table = [] if format_type == 'json': - headers = ['uid', 'config_name', 'config_type', 'shared_folder', 'gateway_uid', 'resource_record_uids'] + headers = ['uid', 'config_name', 'config_type', 'folder', 'gateway_uid', 'resource_record_uids'] if is_verbose: headers.append('fields') else: - headers = ['UID', 'Config Name', 'Config Type', 'Shared Folder', 'Gateway UID', 'Resource Record UIDs'] + headers = ['UID', 'Config Name', 'Config Type', 'Folder', 'Gateway UID', 'Resource Record UIDs'] if is_verbose: headers.append('Fields') @@ -2342,22 +2372,20 @@ def print_root_rotation_setting(params, is_verbose=False, format_type='table'): 'pamDomainConfiguration', 'pamNetworkConfiguration', 'pamOciConfiguration', 'pamGitHubConfiguration'): facade.record = c - shared_folder_parents = find_parent_top_folder(params, c.record_uid) - if shared_folder_parents: - sf = shared_folder_parents[0] + folder_info = resolve_pam_config_folder_info( + params, facade, c.record_uid) + if folder_info and folder_info.get('type') != 'unknown': + folder_display = format_pam_folder_display(folder_info) if format_type == 'json': config_data = { "uid": c.record_uid, "config_name": c.title, "config_type": c.record_type, - "shared_folder": { - "name": sf.name, - "uid": sf.uid - }, "gateway_uid": facade.controller_uid, "resource_record_uids": facade.resource_ref } + config_data.update(pam_folder_json_payload(folder_info)) if is_verbose: fields = {} @@ -2371,7 +2399,7 @@ def print_root_rotation_setting(params, is_verbose=False, format_type='table'): configs_data.append(config_data) else: - row = [c.record_uid, c.title, c.record_type, f'{sf.name} ({sf.uid})', + row = [c.record_uid, c.title, c.record_type, folder_display, facade.controller_uid, facade.resource_ref] if is_verbose: @@ -2386,7 +2414,7 @@ def print_root_rotation_setting(params, is_verbose=False, format_type='table'): table.append(row) else: - logging.warning('Following configuration is not in the shared folder: UID: %s, Title: %s', + logging.warning(f'Following configuration folder was not found: UID: %s, Title: %s', c.record_uid, c.title) else: logging.warning('Following configuration has unsupported type: UID: %s, Title: %s', c.record_uid, @@ -2406,8 +2434,8 @@ def print_root_rotation_setting(params, is_verbose=False, format_type='table'): common_parser.add_argument('--title', '-t', dest='title', action='store', help='Title of the PAM Configuration') common_parser.add_argument('--gateway', '-g', dest='gateway_uid', action='store', help='Gateway UID or Name') common_parser.add_argument('--shared-folder', '-sf', dest='shared_folder_uid', action='store', - help='Share Folder where this PAM Configuration is stored. Should be one of the folders to ' - 'which the gateway has access to.') + help='Shared Folder or Nested Share Folder where this PAM Configuration is stored. ' + 'Should be one of the folders to which the gateway has access.') common_parser.add_argument('--schedule', '-sc', dest='default_schedule', action='store', help='Default Schedule: Use CRON syntax') common_parser.add_argument('--port-mapping', '-pm', dest='port_mapping', action='append', help='Port Mapping') @@ -2470,6 +2498,14 @@ def print_root_rotation_setting(params, is_verbose=False, format_type='table'): class PamConfigurationEditMixin(RecordEditMixin): pam_record_types = None + PAM_CONFIG_RECORD_TYPES = frozenset({ + 'pamAwsConfiguration', 'pamAzureConfiguration', 'pamGcpConfiguration', + 'pamDomainConfiguration', 'pamNetworkConfiguration', 'pamOciConfiguration', + }) + PAM_RESOURCE_RECORD_TYPES = frozenset({ + 'pamDatabase', 'pamDirectory', 'pamMachine', 'pamRemoteBrowser', + }) + ROTATION_TARGET_RECORD_TYPES = PAM_RESOURCE_RECORD_TYPES | frozenset({'pamUser'}) def __init__(self): super().__init__() @@ -2521,9 +2557,8 @@ def parse_pam_configuration(self, params, record, **kwargs): shared_folder_uid = None # type: Optional[str] folder_name = kwargs.get('shared_folder_uid') # type: Optional[str] if folder_name: - if folder_name in params.shared_folder_cache: - shared_folder_uid = folder_name - else: + shared_folder_uid = resolve_pam_folder_uid(params, folder_name) + if not shared_folder_uid: for sf_uid in params.shared_folder_cache: sf = api.get_shared_folder(params, sf_uid) if sf and sf.name.casefold() == folder_name.casefold(): @@ -2543,9 +2578,23 @@ def parse_pam_configuration(self, params, record, **kwargs): if rrr: pam_record_lookup = {} rti = PamConfigurationEditMixin.get_pam_record_types(params) + rti_set = set(rti) for r in vault_extensions.find_records(params, record_type=rti): pam_record_lookup[r.record_uid] = r.record_uid pam_record_lookup[r.title.lower()] = r.record_uid + nsf_data = getattr(params, 'nested_share_record_data', {}) + for uid in getattr(params, 'nested_share_records', {}): + rec = vault.KeeperRecord.load(params, uid) + if not rec or rec.record_type not in rti_set: + continue + pam_record_lookup[rec.record_uid] = rec.record_uid + rd = nsf_data.get(uid, {}) + data_json = rd.get('data_json', {}) if isinstance(rd, dict) else {} + title = data_json.get('title', '') if isinstance(data_json, dict) else '' + if title: + pam_record_lookup[title.lower()] = rec.record_uid + elif rec.title: + pam_record_lookup[rec.title.lower()] = rec.record_uid record_uids = set() if 'resourceRef' in value: @@ -2566,17 +2615,7 @@ def parse_pam_configuration(self, params, record, **kwargs): @staticmethod def resolve_single_record(params, record_name, rec_type=''): # type: (KeeperParams, str, str) -> Optional[vault.KeeperRecord] - rec = RecordMixin.resolve_single_record(params, record_name) - if not rec: - recs = [] - for rec in params.record_cache: - vrec = vault.KeeperRecord.load(params, rec) - if vrec and vrec.title == record_name and (not rec_type or rec_type == vrec.record_type): - recs.append(vrec) - if len(recs) > 1: break - if len(recs) == 1: - rec = recs[0] - return rec + return resolve_pam_record(params, record_name, rec_type=rec_type or None) @staticmethod def _domain_kwarg_supplied(kwargs, key, config_edit): @@ -2844,11 +2883,14 @@ def execute(self, params, **kwargs): # resolve folder path to UID sf_name = kwargs.get('shared_folder_uid', '') if sf_name: - fpath = try_resolve_path(params, sf_name) - # [-1] == '' -> existing folder, 'path/' -> non-existing folder - if fpath and len(fpath) >= 2 and fpath[-1] == '': - sfuid = fpath[-2].uid - if sfuid: kwargs['shared_folder_uid'] = sfuid + sfuid = resolve_pam_folder_uid(params, sf_name, allow_legacy_user=True) + if not sfuid: + fpath = try_resolve_path(params, sf_name) + # [-1] == '' -> existing folder, 'path/' -> non-existing folder + if fpath and len(fpath) >= 2 and fpath[-1] == '': + sfuid = fpath[-2].uid + if sfuid: + kwargs['shared_folder_uid'] = sfuid self.parse_properties(params, record, **kwargs) @@ -2875,7 +2917,7 @@ def execute(self, params, **kwargs): self.verify_required(record) - pam_configuration_create_record_v6(params, record, shared_folder_uid) + create_pam_configuration_in_folder(params, record, shared_folder_uid, command='pam-config-new') encrypted_session_token, encrypted_transmission_key, transmission_key = get_keeper_tokens(params) # Add DAG for configuration @@ -2895,10 +2937,6 @@ def execute(self, params, **kwargs): tmp_dag.link_user_to_config_with_options(admin_cred_ref, is_admin='on') tmp_dag.print_tunneling_config(record.record_uid, None) - # Moving v6 record into the folder - api.sync_down(params) - FolderMoveCommand().execute(params, src=record.record_uid, dst=shared_folder_uid, force=True) - params.environment_variables[LAST_RECORD_UID] = record.record_uid params.sync_data = True @@ -2953,14 +2991,11 @@ def execute(self, params, **kwargs): config_name = kwargs.get('uid') if not config_name: raise CommandError('pam config edit', 'PAM Configuration UID or Title is required') - if config_name in params.record_cache: - configuration = vault.KeeperRecord.load(params, config_name) - else: - l_name = config_name.casefold() - for c in vault_extensions.find_records(params, record_version=6): - if c.title.casefold() == l_name: - configuration = c - break + + config_uid = PAMConfigurationRemoveCommand._resolve_pam_config_uid(params, config_name) + if not config_uid: + raise CommandError('pam-config-edit', f'PAM configuration "{config_name}" not found') + configuration = vault.KeeperRecord.load(params, config_uid) if not configuration: raise CommandError('pam-config-edit', f'PAM configuration "{config_name}" not found') if not isinstance(configuration, vault.TypedRecord) or configuration.version != 6: @@ -3015,7 +3050,7 @@ def execute(self, params, **kwargs): self.parse_properties(params, configuration, config_edit=True, **kwargs) self.verify_required(configuration) - record_management.update_record(params, configuration) + update_pam_record(params, configuration, command='pam-config-edit') admin_cred_ref = '' value = field.get_default_value(dict) @@ -3028,7 +3063,7 @@ def execute(self, params, **kwargs): api.communicate_rest(params, pcc, 'pam/set_configuration_controller') shared_folder_uid = value.get('folderUid') or '' if shared_folder_uid != orig_shared_folder_uid: - FolderMoveCommand().execute(params, src=configuration.record_uid, dst=shared_folder_uid) + place_record_in_folder(params, configuration.record_uid, shared_folder_uid, command='pam-config-edit') if configuration.type_name == 'pamDomainConfiguration' and not kwargs.get('force_domain_admin', False) is True: # pamUser must exist or "403 Insufficient PAM access to perform this operation" @@ -3070,25 +3105,64 @@ class PAMConfigurationRemoveCommand(Command): help='PAM Configuration UID. To view all rotation settings with their UIDs, use command ' '`pam config list`') + _PAM_CONFIG_TYPES = PamConfigurationEditMixin.PAM_CONFIG_RECORD_TYPES + def get_parser(self): return PAMConfigurationRemoveCommand.parser + @classmethod + def _resolve_pam_config_uid(cls, params, identifier): + # type: (KeeperParams, str) -> Optional[str] + if identifier in params.record_cache: + rec = vault.KeeperRecord.load(params, identifier) + if isinstance(rec, vault.TypedRecord) and rec.version == 6: + if rec.record_type in cls._PAM_CONFIG_TYPES: + return rec.record_uid + logging.warning( + 'Record "%s" is v6 but is not a PAM configuration type (found %s)', + identifier, + rec.record_type, + ) + + from ..nested_share_folder import removal_api as _nsf + resolved_uid = _nsf.resolve_nested_share_record_uid(params, identifier) + if resolved_uid: + rec = vault.KeeperRecord.load(params, resolved_uid) + if isinstance(rec, vault.TypedRecord) and rec.version == 6: + if rec.record_type in cls._PAM_CONFIG_TYPES: + return resolved_uid + logging.warning( + 'Nested Share Record "%s" is v6 but is not a PAM configuration type (found %s)', + resolved_uid, + rec.record_type, + ) + + l_name = identifier.casefold() + matches = [] + for config in vault_extensions.find_records(params, record_version=6): + if config.record_type not in cls._PAM_CONFIG_TYPES: + continue + if config.record_uid == identifier: + return config.record_uid + if config.title.casefold() == l_name: + matches.append(config.record_uid) + if len(matches) == 1: + return matches[0] + if len(matches) > 1: + raise CommandError('pam config remove', + f'"{identifier}" matches multiple configurations. Use a UID.') + return None + def execute(self, params, **kwargs): pam_config_name = kwargs.get('uid') if not pam_config_name: - raise CommandError('pam config edit', 'PAM Configuration UID is required') - pam_config_uid = None - for config in vault_extensions.find_records(params, record_version=6): - if config.record_uid == pam_config_name: - pam_config_uid = config.record_uid - break - if config.title.casefold() == pam_config_name.casefold(): - pass - if not pam_config_name: - raise Exception(f'Configuration "{pam_config_name}" not found') + raise CommandError('pam config remove', 'PAM Configuration UID is required') + pam_config_uid = self._resolve_pam_config_uid(params, pam_config_name) + if not pam_config_uid: + raise CommandError('pam config remove', f'Configuration "{pam_config_name}" not found') pam_config = vault.KeeperRecord.load(params, pam_config_uid) if not pam_config: - raise Exception(f'Configuration "{pam_config_uid}" not found') + raise CommandError('pam config remove', f'Configuration "{pam_config_uid}" not found') encrypted_session_token, encrypted_transmission_key, transmission_key = get_keeper_tokens(params) tmp_dag = TunnelDAG(params, encrypted_session_token, encrypted_transmission_key, pam_config.record_uid, is_config=True, transmission_key=transmission_key) @@ -3122,7 +3196,7 @@ def execute(self, params, **kwargs): gateway_uid = utils.base64_url_encode(rri.controllerUid) if rri.controllerUid else '-' def is_resource_ok(resource_id, params, configuration_uid): - if resource_id not in params.record_cache: + if not record_exists_in_vault(params, resource_id): return False configuration = vault.KeeperRecord.load(params, configuration_uid) if not isinstance(configuration, vault.TypedRecord): @@ -3146,6 +3220,8 @@ def is_resource_ok(resource_id, params, configuration_uid): if pwd_complexity_raw: try: record = params.record_cache.get(record_uid) + if not record: + record = getattr(params, 'nested_share_records', {}).get(record_uid) if record: complexity = crypto.decrypt_aes_v2(utils.base64_url_decode(pwd_complexity_raw), record['record_key_unencrypted']) @@ -3251,8 +3327,8 @@ class PAMRouterScriptCommand(GroupCommand): def __init__(self): super().__init__() self.register_command('list', PAMScriptListCommand(), 'List script fields') - self.register_command('add', PAMScriptAddCommand(), 'List Record Rotation Schedulers') - self.register_command('edit', PAMScriptEditCommand(), 'Add, delete, or edit script field') + self.register_command('add', PAMScriptAddCommand(), 'Add script to record (record owner only)') + self.register_command('edit', PAMScriptEditCommand(), 'Edit script field') self.register_command('delete', PAMScriptDeleteCommand(), 'Delete script field') self.default_verb = 'list' @@ -3270,8 +3346,8 @@ def execute(self, params, **kwargs): table = [] header = ['record_uid', 'title', 'record_type', 'script_uid', 'script_name', 'records', 'command'] - for record in vault_extensions.find_records(params, search_str=pattern, record_version=3, - record_type=('pamUser', 'pamDirectory')): + for record in find_pam_records_by_search(params, pattern, record_version=3, + record_types=('pamUser', 'pamDirectory')): if not isinstance(record, vault.TypedRecord): continue for field in (x for x in record.fields if x.type == 'script'): @@ -3295,7 +3371,8 @@ def execute(self, params, **kwargs): class PAMScriptAddCommand(Command): - parser = argparse.ArgumentParser(prog='pam rotate script add', description='Add script to record') + parser = argparse.ArgumentParser(prog='pam rotate script add', + description='Add script to record (record owner only)') parser.add_argument('--script', required=True, dest='script', action='store', help='Script file name') parser.add_argument('--add-credential', dest='add_credential', action='append', @@ -3311,8 +3388,8 @@ def execute(self, params, **kwargs): record_name = kwargs.get('record') if not record_name: raise CommandError('rotate script', '"record" argument is required') - records = list(vault_extensions.find_records( - params, search_str=record_name, record_version=3, record_type=('pamUser', 'pamDirectory'))) + records = find_pam_records_by_search(params, record_name, record_version=3, + record_types=('pamUser', 'pamDirectory')) if len(records) == 0: raise CommandError('rotate script', f'Record "{record_name}" not found') if len(records) > 1: @@ -3350,7 +3427,10 @@ def execute(self, params, **kwargs): record_refs = kwargs.get('add_credential') if isinstance(record_refs, list): for ref in record_refs: - if ref in params.record_cache: + resolved_ref = resolve_pam_record(params, ref, rec_type='pamUser') + if resolved_ref: + script_value['recordRef'].append(resolved_ref.record_uid) + elif record_exists_in_vault(params, ref): script_value['recordRef'].append(ref) cmd = kwargs.get('script_command') if cmd: @@ -3384,8 +3464,8 @@ def execute(self, params, **kwargs): if not script_name: raise CommandError('rotate script', '"script" argument is required') - records = list(vault_extensions.find_records( - params, search_str=record_name, record_version=3, record_type=('pamUser', 'pamDirectory'))) + records = find_pam_records_by_search(params, record_name, record_version=3, + record_types=('pamUser', 'pamDirectory')) if len(records) == 0: raise CommandError('rotate script', f'Record "{record_name}" not found') if len(records) > 1: @@ -3421,11 +3501,21 @@ def execute(self, params, **kwargs): refs.update(record_refs) remove_credential = kwargs.get('remove_credential') if isinstance(remove_credential, list) and remove_credential: - refs.difference_update(remove_credential) + for ref in remove_credential: + resolved_ref = resolve_pam_record(params, ref, rec_type='pamUser') + if resolved_ref: + refs.discard(resolved_ref.record_uid) + else: + refs.discard(ref) modified = True add_credential = kwargs.get('add_credential') if isinstance(add_credential, list) and add_credential: - refs.update(add_credential) + for ref in add_credential: + resolved_ref = resolve_pam_record(params, ref, rec_type='pamUser') + if resolved_ref: + refs.add(resolved_ref.record_uid) + elif record_exists_in_vault(params, ref): + refs.add(ref) modified = True if modified: script_value['recordRef'] = list(refs) @@ -3459,8 +3549,8 @@ def execute(self, params, **kwargs): if not script_name: raise CommandError('rotate script', '"script" argument is required') - records = list(vault_extensions.find_records( - params, search_str=record_name, record_version=3, record_type=('pamUser', 'pamDirectory'))) + records = find_pam_records_by_search(params, record_name, record_version=3, + record_types=('pamUser', 'pamDirectory')) if len(records) == 0: raise CommandError('rotate script', f'Record "{record_name}" not found') if len(records) > 1: @@ -4224,8 +4314,9 @@ class PAMCreateGatewayCommand(Command): help='Name of the Gateway', action='store') dr_create_controller_parser.add_argument('--application', '-a', required=True, dest='ksm_app', - help='KSM Application name or UID. Use command `sm app list` to view ' - 'available KSM Applications.', action='store') + help='KSM Application name or UID. Use ' + '`secrets-manager app list` to view available applications.', + action='store') dr_create_controller_parser.add_argument('--token-expires-in-min', '-e', type=int, dest='token_expire_in_min', action='store', help='Time for the one time token to expire. Maximum 1440 minutes (24 hrs). Default: 60', @@ -4253,12 +4344,24 @@ def execute(self, params, **kwargs): logging.debug(f'ksm_app =[{ksm_app}]') logging.debug(f'ott_expire_in_min =[{ott_expire_in_min}]') - one_time_token = gateway_helper.create_gateway(params, gateway_name, ksm_app, config_init, ott_expire_in_min) + ksm_app_record = KSMCommand.get_app_record(params, ksm_app) + if not ksm_app_record: + raise CommandError( + 'pam gateway new', + f'KSM Application "{ksm_app}" not found. Run sync-down and verify the application ' + f'exists in your vault or Nested Share Folder.') + + ksm_app_uid = ksm_app_record.get('record_uid', ksm_app) + ksm_app_title, _, _ = KSMCommand.get_ksm_app_display_info(params, ksm_app_uid) + + one_time_token = gateway_helper.create_gateway( + params, gateway_name, ksm_app_uid, config_init, ott_expire_in_min) if is_return_value: return one_time_token else: - print(f'The one time token has been created in application [{bcolors.OKBLUE}{ksm_app}{bcolors.ENDC}].\n\n' + print(f'The one time token has been created in application ' + f'[{bcolors.OKBLUE}{ksm_app_title or ksm_app_uid}{bcolors.ENDC}].\n\n' f'The new Gateway named {bcolors.OKBLUE}{gateway_name}{bcolors.ENDC} will show up in a list ' f'of gateways once it is initialized.\n\n') @@ -4322,4 +4425,4 @@ def execute(self, params: KeeperParams, **kwargs): gateway_name = new_name if new_name else gateway.controllerName gateway_helper.edit_gateway(params, gateway.controllerUid, gateway_name, resolved_node_id) - logging.info('Gateway %s has been edited.', gateway_uid) \ No newline at end of file + logging.info('Gateway %s has been edited.', gateway_uid) diff --git a/keepercommander/commands/discoveryrotation_v1.py b/keepercommander/commands/discoveryrotation_v1.py index d25e0d4b6..cadd5f0c9 100644 --- a/keepercommander/commands/discoveryrotation_v1.py +++ b/keepercommander/commands/discoveryrotation_v1.py @@ -1272,8 +1272,8 @@ class PAMRouterScriptCommand(GroupCommand): def __init__(self): super().__init__() self.register_command('list', PAMScriptListCommand(), 'List script fields') - self.register_command('add', PAMScriptAddCommand(), 'List Record Rotation Schedulers') - self.register_command('edit', PAMScriptEditCommand(), 'Add, delete, or edit script field') + self.register_command('add', PAMScriptAddCommand(), 'Add script to record (record owner only)') + self.register_command('edit', PAMScriptEditCommand(), 'Edit script field') self.register_command('delete', PAMScriptDeleteCommand(), 'Delete script field') self.default_verb = 'list' @@ -1316,7 +1316,8 @@ def execute(self, params, **kwargs): class PAMScriptAddCommand(Command): - parser = argparse.ArgumentParser(prog='pam rotate script add', description='Add script to record') + parser = argparse.ArgumentParser(prog='pam rotate script add', + description='Add script to record (record owner only)') parser.add_argument('--script', required=True, dest='script', action='store', help='Script file name') parser.add_argument('--add-credential', dest='add_credential', action='append', diff --git a/keepercommander/commands/folder.py b/keepercommander/commands/folder.py index f473eb754..84a1ef7d5 100644 --- a/keepercommander/commands/folder.py +++ b/keepercommander/commands/folder.py @@ -899,13 +899,13 @@ def execute(self, params, **kwargs): if src_folder.type == BaseFolderNode.NestedShareFolderType: if dst_folder.type in {BaseFolderNode.SharedFolderType, BaseFolderNode.SharedFolderFolderType}: - raise CommandError('mv', 'Drive folders cannot be moved inside a Shared folder.') - raise CommandError('mv', 'Moving drive folders is currently not supported.') + raise CommandError('mv', 'Nested Share Folders cannot be moved inside a Shared folder.') + raise CommandError('mv', 'Moving Nested Share Folders is currently not supported.') if dst_folder.type == BaseFolderNode.NestedShareFolderType: if src_folder.type in {BaseFolderNode.SharedFolderType, BaseFolderNode.SharedFolderFolderType}: - raise CommandError('mv', 'Shared folders cannot be moved inside a drive folder.') - raise CommandError('mv', 'Folders cannot be moved inside a drive folder.') + raise CommandError('mv', 'Shared folders cannot be moved inside a Nested Share Folder.') + raise CommandError('mv', 'Folders cannot be moved inside a Nested Share Folder.') dp = set() f = dst_folder @@ -949,7 +949,7 @@ def execute(self, params, **kwargs): else: if src_folder.type == BaseFolderNode.NestedShareFolderType: - raise CommandError('mv', 'Moving drive records is currently not supported.') + raise CommandError('mv', 'Moving Nested Share Folder records is currently not supported.') if record_uid in getattr(params, 'nested_share_records', {}) \ and dst_folder.type != BaseFolderNode.NestedShareFolderType: diff --git a/keepercommander/commands/ksm.py b/keepercommander/commands/ksm.py index e55463f19..e6215b531 100644 --- a/keepercommander/commands/ksm.py +++ b/keepercommander/commands/ksm.py @@ -26,6 +26,11 @@ from .base import Command, dump_report_data, user_choice, as_boolean from . import record +from ..nested_share_folder.common import get_folder_key, get_record_key +from .nested_share_folder.helpers import ( + is_nested_share_folder, is_nested_share_record, load_record_metadata, resolve_folder_uid) +from ..nested_share_folder.removal_api import ( + resolve_nested_share_folder_uid, resolve_nested_share_record_uid) from .. import api, utils, crypto, vault from ..params import KeeperParams from ..display import bcolors @@ -90,16 +95,16 @@ --force : Do not prompt for confirmation {bcolors.BOLD}Add Secret to Application:{bcolors.ENDC} - {bcolors.OKGREEN}secrets-manager share add --app {bcolors.OKBLUE}[APP NAME OR UID] {bcolors.OKGREEN}--secret {bcolors.OKBLUE}[RECORD OR SHARED FOLDER UID]{bcolors.ENDC} + {bcolors.OKGREEN}secrets-manager share add --app {bcolors.OKBLUE}[APP NAME OR UID] {bcolors.OKGREEN}--secret {bcolors.OKBLUE}[RECORD, SHARED FOLDER, OR NSF UID/PATH] {bcolors.ENDC} Options: --editable : Allow secrets to be editable by the client {bcolors.BOLD}Update Secret Permissions:{bcolors.ENDC} - {bcolors.OKGREEN}secrets-manager share update --app {bcolors.OKBLUE}[APP NAME OR UID] {bcolors.OKGREEN}--secret {bcolors.OKBLUE}[RECORD OR SHARED FOLDER UID] {bcolors.OKGREEN}--editable{bcolors.ENDC} - {bcolors.OKGREEN}secrets-manager share update --app {bcolors.OKBLUE}[APP NAME OR UID] {bcolors.OKGREEN}--secret {bcolors.OKBLUE}[RECORD OR SHARED FOLDER UID] {bcolors.OKGREEN}--readonly{bcolors.ENDC} + {bcolors.OKGREEN}secrets-manager share update --app {bcolors.OKBLUE}[APP NAME OR UID] {bcolors.OKGREEN}--secret {bcolors.OKBLUE}[RECORD, SHARED FOLDER, OR NSF UID/PATH] {bcolors.OKGREEN}--editable{bcolors.ENDC} + {bcolors.OKGREEN}secrets-manager share update --app {bcolors.OKBLUE}[APP NAME OR UID] {bcolors.OKGREEN}--secret {bcolors.OKBLUE}[RECORD, SHARED FOLDER, OR NSF UID/PATH] {bcolors.OKGREEN}--readonly{bcolors.ENDC} {bcolors.BOLD}Remove Secret from Application:{bcolors.ENDC} - {bcolors.OKGREEN}secrets-manager share remove --app {bcolors.OKBLUE}[APP NAME OR UID] {bcolors.OKGREEN}--secret {bcolors.OKBLUE}[RECORD OR SHARED FOLDER UID]{bcolors.ENDC} + {bcolors.OKGREEN}secrets-manager share remove --app {bcolors.OKBLUE}[APP NAME OR UID] {bcolors.OKGREEN}--secret {bcolors.OKBLUE}[RECORD, SHARED FOLDER, OR NSF UID/PATH] {bcolors.ENDC} {bcolors.BOLD}Add Token to Application:{bcolors.ENDC} {bcolors.OKGREEN}secrets-manager token add {bcolors.OKBLUE}[APP NAME OR UID]{bcolors.ENDC} @@ -130,7 +135,7 @@ help='One of: "app list", "app get", "app create", "app update", "app remove", "app share", ' + '"app unshare", "client add", "client remove", "share add", "share update", "share remove" or "token add"') ksm_parser.add_argument('--secret', '-s', type=str, action='append', required=False, - help='Record UID') + help='Record, shared folder, or Nested Share Folder (NSF) UID or path') ksm_parser.add_argument('--app', '-a', type=str, action='store', required=False, help='Application Name or UID') ksm_parser.add_argument('--client', '-i', type=str, dest='client_names_or_ids', action='append', required=False, @@ -593,11 +598,15 @@ def add_app_share(params, secret_uids, app_name_or_uid, is_editable): app_record_uid = rec_cache_val.get('record_uid') master_key = rec_cache_val.get('record_key_unencrypted') + resolved_uids = KSMCommand.resolve_secret_uids(params, secret_uids) + if not resolved_uids: + return + KSMCommand.share_secret( params=params, app_uid=app_record_uid, master_key=master_key, - secret_uids=secret_uids, + secret_uids=resolved_uids, is_editable=is_editable ) @@ -838,8 +847,6 @@ def shorten_client_id(all_clients, original_id, number_of_characters): print(bcolors.BOLD + "\nApplication Access\n" + bcolors.ENDC) if ai.shares: - recs = params.record_cache - for s in ai.shares: uid_str = utils.base64_url_encode(s.secretUid) sht = APIRequest_pb2.ApplicationShareType.Name(s.shareType) @@ -851,18 +858,17 @@ def shorten_client_id(all_clients, original_id, number_of_characters): } if sht == 'SHARE_TYPE_RECORD': - rec = recs.get(uid_str) - if rec: - record_data_dict = KSMCommand.record_data_as_dict(rec) - share_data["title"] = record_data_dict.get('title') - share_data["type"] = "RECORD" + share_data["title"] = KSMCommand.get_secret_title(params, uid_str, sht) + share_data["type"] = "RECORD" + #ToDo: check if type nsf record is valid here + if is_nested_share_record(params, uid_str): + share_data["type"] = "NSF RECORD" elif sht == 'SHARE_TYPE_FOLDER': - if uid_str in params.shared_folder_cache: - cached_sf = params.shared_folder_cache[uid_str] - share_data["title"] = cached_sf.get('name_unencrypted') - share_data["type"] = "FOLDER" - else: - continue + share_data["title"] = KSMCommand.get_secret_title(params, uid_str, sht) + share_data["type"] = "FOLDER" + #ToDo: check if type nsf folder is valid here + if is_nested_share_folder(params, uid_str): + share_data["type"] = "NSF FOLDER" else: logging.warning("Unknown Share Type %s" % sht) continue @@ -900,33 +906,160 @@ def shorten_client_id(all_clients, original_id, number_of_characters): else: return json.dumps({"applications": result_data}, indent=2) + @staticmethod + def _secret_in_cache(params, uid): + if uid in getattr(params, 'record_cache', {}): + return True + if uid in getattr(params, 'nested_share_records', {}): + return True + if api.is_shared_folder(params, uid): + return True + if is_nested_share_folder(params, uid): + return True + return False + + @staticmethod + def resolve_secret_uid(params, identifier): + if not identifier: + return None + identifier = str(identifier).strip() + if identifier.startswith('[') and identifier.endswith(']') and len(identifier) > 2: + identifier = identifier[1:-1].strip() + if KSMCommand._secret_in_cache(params, identifier): + return identifier + record_uid = resolve_nested_share_record_uid(params, identifier) + if record_uid: + return record_uid + folder_uid = resolve_folder_uid(params, identifier) + if folder_uid and (api.is_shared_folder(params, folder_uid) + or is_nested_share_folder(params, folder_uid)): + return folder_uid + folder_uid = resolve_nested_share_folder_uid(params, identifier) + if folder_uid and is_nested_share_folder(params, folder_uid): + return folder_uid + return None + + @staticmethod + def resolve_secret_uids(params, identifiers): + if not identifiers: + return [] + if isinstance(identifiers, str): + identifiers = [identifiers] + resolved = [] + for ident in identifiers: + uid = KSMCommand.resolve_secret_uid(params, ident) + if uid: + resolved.append(uid) + else: + logging.warning('Could not resolve secret "%s". Run sync-down and try again.', ident) + return resolved + + @staticmethod + def classify_secret(params, uid): + share_key = None + share_type = None + + if uid in getattr(params, 'record_cache', {}) or is_nested_share_record(params, uid): + share_type = 'SHARE_TYPE_RECORD' + if uid in params.record_cache: + share_key = params.record_cache[uid].get('record_key_unencrypted') + if not share_key: + share_key = get_record_key(params, uid, raise_on_missing=False) + elif api.is_shared_folder(params, uid) or is_nested_share_folder(params, uid): + share_type = 'SHARE_TYPE_FOLDER' + cached_sf = getattr(params, 'shared_folder_cache', {}).get(uid, {}) + share_key = cached_sf.get('shared_folder_key_unencrypted') + if not share_key: + share_key = get_folder_key(params, uid, raise_on_missing=False) + + if share_type and share_key: + return {'uid': uid, 'share_type': share_type, 'share_key': share_key} + return None + + @staticmethod + def get_secret_title(params, uid, share_type): + if share_type == 'SHARE_TYPE_RECORD': + rec = getattr(params, 'record_cache', {}).get(uid) + if rec and rec.get('data_unencrypted'): + try: + return KSMCommand.record_data_as_dict(rec).get('title', uid) + except Exception: + pass + if is_nested_share_record(params, uid): + return load_record_metadata(params, uid).get('title', uid) + elif share_type == 'SHARE_TYPE_FOLDER': + cached_sf = getattr(params, 'shared_folder_cache', {}).get(uid, {}) + if cached_sf.get('name_unencrypted'): + return cached_sf.get('name_unencrypted') + nsf = getattr(params, 'nested_share_folders', {}).get(uid, {}) + if nsf.get('name'): + return nsf.get('name') + folder = getattr(params, 'folder_cache', {}).get(uid) + if folder and getattr(folder, 'name', None): + return folder.name + return uid + + @staticmethod + def _share_nsf_secret(params, app_uid, master_key, secret, is_editable=False): + """Share an NSF folder/record with an application using v3 access APIs.""" + from ..nested_share_folder.folder_api import grant_folder_access_to_application_v3 + from ..nested_share_folder.record_api import share_record_to_application_v3 + + uid = secret['uid'] + if secret['share_type'] == 'SHARE_TYPE_FOLDER' and is_nested_share_folder(params, uid): + result = grant_folder_access_to_application_v3( + params, uid, app_uid, master_key, is_editable=is_editable) + if not result.get('success'): + raise KeeperApiError( + result.get('status') or 'access_denied', + result.get('message') or 'Failed to share Nested Share Folder with application') + return True + + if secret['share_type'] == 'SHARE_TYPE_RECORD' and is_nested_share_record(params, uid): + result = share_record_to_application_v3( + params, uid, app_uid, master_key, is_editable=is_editable) + if not result.get('success'): + message = '; '.join( + r.get('message') or r.get('status') or 'share failed' + for r in result.get('results', [])) or 'Failed to share Nested Share Record with application' + raise KeeperApiError('share_failed', message) + return True + + return False + @staticmethod def share_secret(params, app_uid, master_key, secret_uids, is_editable=False): app_shares = [] - added_secret_uids_type_pairs = [] for uid in secret_uids: - is_record = uid in params.record_cache - is_shared_folder = api.is_shared_folder(params, uid) - - if is_record: - rec = params.record_cache[uid] - share_key_decrypted = rec['record_key_unencrypted'] - share_type = 'SHARE_TYPE_RECORD' - elif is_shared_folder: - cached_sf = params.shared_folder_cache[uid] - shared_folder_key_unencrypted = cached_sf.get('shared_folder_key_unencrypted') - share_key_decrypted = shared_folder_key_unencrypted - share_type = 'SHARE_TYPE_FOLDER' - else: - print(f"""{bcolors.WARNING}\tUID="{uid}" is not a Record nor Shared Folder. Only individual records or - Shared Folders can be added to the application.{bcolors.ENDC} Make sure your local cache is up to date by + secret = KSMCommand.classify_secret(params, uid) + if not secret: + print(f"""{bcolors.WARNING}\tUID="{uid}" is not a Record, Shared Folder, or Nested Share Folder record. + Only individual records or folders can be added to the application.{bcolors.ENDC} Make sure your local cache is up to date by running 'sync-down' command and trying again.""") + continue + share_type = secret['share_type'] + uid = secret['uid'] + + # NSF folders/records must use v3 access_update / records share APIs. + if ((share_type == 'SHARE_TYPE_FOLDER' and is_nested_share_folder(params, uid)) + or (share_type == 'SHARE_TYPE_RECORD' and is_nested_share_record(params, uid))): + try: + KSMCommand._share_nsf_secret( + params, app_uid, master_key, secret, is_editable=is_editable) + added_secret_uids_type_pairs.append((uid, share_type)) + except KeeperApiError as kae: + if 'already' in (kae.message or '').lower(): + logging.error("One of the secret UIDs is already shared to this application. " + "Please remove already shared UIDs from your command and try again.") + else: + raise kae continue + share_key_decrypted = secret['share_key'] added_secret_uids_type_pairs.append((uid, share_type)) encrypted_secret_key = crypto.encrypt_aes_v2(share_key_decrypted, master_key) @@ -942,15 +1075,20 @@ def share_secret(params, app_uid, master_key, secret_uids, is_editable=False): if len(added_secret_uids_type_pairs) == 0: return - app_share_add_rq = APIRequest_pb2.AddAppSharesRequest() - app_share_add_rq.appRecordUid = utils.base64_url_decode(app_uid) - app_share_add_rq.shares.extend(app_shares) - try: - api.communicate_rest(params, app_share_add_rq, 'vault/app_share_add') + if app_shares: + app_share_add_rq = APIRequest_pb2.AddAppSharesRequest() + app_share_add_rq.appRecordUid = utils.base64_url_decode(app_uid) + app_share_add_rq.shares.extend(app_shares) + api.communicate_rest(params, app_share_add_rq, 'vault/app_share_add') + print(bcolors.OKGREEN + f'\nSuccessfully added secrets to app uid={app_uid}, ' f'editable=' + bcolors.BOLD + f'{is_editable}:' + bcolors.ENDC) - print('\n'.join(map(lambda x: ('\t' + str(x[0])) + ' ' + ('Record' if ('RECORD' in str(x[1])) else 'Shared Folder'), added_secret_uids_type_pairs))) + print('\n'.join(map(lambda x: ('\t' + str(x[0])) + ' ' + ( + 'Nested Share Folder' if is_nested_share_folder(params, x[0]) else + 'Nested Share Record' if is_nested_share_record(params, x[0]) else + 'Record' if 'RECORD' in str(x[1]) else 'Shared Folder'), + added_secret_uids_type_pairs))) print('\n') return True except KeeperApiError as kae: @@ -961,21 +1099,125 @@ def share_secret(params, app_uid, master_key, secret_uids, is_editable=False): raise kae return False + @staticmethod + def _is_ksm_app_data(data_dict): + return isinstance(data_dict, dict) and data_dict.get('type') == 'app' + + @staticmethod + def _app_record_from_cache_entry(rec_cache_val): + if not rec_cache_val or rec_cache_val.get('version') != 5: + return None + data_unencrypted = rec_cache_val.get('data_unencrypted') + if not data_unencrypted: + return None + try: + data_dict = json.loads(data_unencrypted.decode('utf-8')) + except Exception: + return None + if KSMCommand._is_ksm_app_data(data_dict): + return rec_cache_val + return None + + @staticmethod + def _normalize_nsf_app_record(params, record_uid): + nsf_rec = getattr(params, 'nested_share_records', {}).get(record_uid) + if not nsf_rec: + return None + + nsf_data = getattr(params, 'nested_share_record_data', {}).get(record_uid, {}) + data_json = nsf_data.get('data_json', {}) + if not KSMCommand._is_ksm_app_data(data_json): + return None + + record_key = nsf_rec.get('record_key_unencrypted') + if not record_key: + record_key = get_record_key(params, record_uid, raise_on_missing=False) + if not record_key: + return None + + return { + 'record_uid': record_uid, + 'version': nsf_rec.get('version', 5), + 'revision': nsf_rec.get('revision', 0), + 'record_key_unencrypted': record_key, + 'data_unencrypted': json.dumps(data_json).encode('utf-8'), + 'source': 'nested_share_folder', + } + @staticmethod def get_app_record(params, app_name_or_uid): + if not app_name_or_uid: + return None + + if app_name_or_uid in getattr(params, 'record_cache', {}): + rec = KSMCommand._app_record_from_cache_entry(params.record_cache[app_name_or_uid]) + if rec: + return rec + + nsf_rec = KSMCommand._normalize_nsf_app_record(params, app_name_or_uid) + if nsf_rec: + return nsf_rec for rec_cache_val in params.record_cache.values(): + rec = KSMCommand._app_record_from_cache_entry(rec_cache_val) + if not rec: + continue + r_uid = rec.get('record_uid') + try: + r_unencr_dict = json.loads(rec.get('data_unencrypted').decode('utf-8')) + except Exception: + continue + if r_unencr_dict.get('title') == app_name_or_uid or r_uid == app_name_or_uid: + return rec + + resolved_uid = resolve_nested_share_record_uid(params, app_name_or_uid) + if resolved_uid: + if resolved_uid in getattr(params, 'record_cache', {}): + rec = KSMCommand._app_record_from_cache_entry(params.record_cache[resolved_uid]) + if rec: + return rec + nsf_rec = KSMCommand._normalize_nsf_app_record(params, resolved_uid) + if nsf_rec: + return nsf_rec - if rec_cache_val.get('version') == 5: - r_uid = rec_cache_val.get('record_uid') - r_unencr_json_data = rec_cache_val.get('data_unencrypted').decode('utf-8') - r_unencr_dict = json.loads(r_unencr_json_data) + return None - if r_unencr_dict.get('title') == app_name_or_uid or r_uid == app_name_or_uid: - return rec_cache_val + @staticmethod + def get_app_title(params, app_uid): + rec = KSMCommand.get_app_record(params, app_uid) + if rec and rec.get('data_unencrypted'): + try: + return json.loads(rec.get('data_unencrypted').decode('utf-8')).get('title', app_uid) + except Exception: + pass + + if is_nested_share_record(params, app_uid): + meta = load_record_metadata(params, app_uid) + if meta.get('type') == 'app': + return meta.get('title', app_uid) + nsf_data = getattr(params, 'nested_share_record_data', {}).get(app_uid, {}) + data_json = nsf_data.get('data_json', {}) + if isinstance(data_json, dict) and data_json.get('type') == 'app': + return data_json.get('title', app_uid) return None + @staticmethod + def get_ksm_app_display_info(params, app_uid_str): + ksm_app = KSMCommand.get_app_record(params, app_uid_str) + if ksm_app: + try: + title = json.loads(ksm_app.get('data_unencrypted').decode('utf-8')).get('title', app_uid_str) + except Exception: + title = app_uid_str + return title, True, f'{title} ({app_uid_str})' + + title = KSMCommand.get_app_title(params, app_uid_str) + if title: + return title, False, f'{title} ({app_uid_str})' + + return None, False, f'[APP NOT ACCESSIBLE OR DELETED] ({app_uid_str})' + @staticmethod def search_app_records(params, search_str): @@ -1163,6 +1405,10 @@ def update_app_share(params, secret_uids, app_name_or_uid, is_editable): app_record_uid = rec_cache_val.get('record_uid') master_key = rec_cache_val.get('record_key_unencrypted') + resolved_secret_uids = KSMCommand.resolve_secret_uids(params, secret_uids) + if not resolved_secret_uids: + return + app_info = KSMCommand.get_app_info(params, app_record_uid) existing_shares = { utils.base64_url_encode(s.secretUid): s @@ -1170,7 +1416,18 @@ def update_app_share(params, secret_uids, app_name_or_uid, is_editable): } uids_to_update = [] - for uid in secret_uids: + nsf_uids_to_update = [] + for uid in resolved_secret_uids: + secret = KSMCommand.classify_secret(params, uid) + is_nsf = bool( + secret and ( + (secret['share_type'] == 'SHARE_TYPE_FOLDER' + and is_nested_share_folder(params, secret['uid'])) + or (secret['share_type'] == 'SHARE_TYPE_RECORD' + and is_nested_share_record(params, secret['uid'])))) + if is_nsf: + nsf_uids_to_update.append(secret['uid']) + continue if uid not in existing_shares: logging.warning('Secret "%s" is not currently shared with this application. ' 'Use "share add" to add it first.' % uid) @@ -1182,63 +1439,86 @@ def update_app_share(params, secret_uids, app_name_or_uid, is_editable): continue uids_to_update.append(uid) - if not uids_to_update: + if not uids_to_update and not nsf_uids_to_update: print(bcolors.WARNING + "No share permissions to update." + bcolors.ENDC) return - rq_remove = APIRequest_pb2.RemoveAppSharesRequest() - rq_remove.appRecordUid = utils.base64_url_decode(app_record_uid) - rq_remove.shares.extend(utils.base64_url_decode(uid) for uid in uids_to_update) + from ..nested_share_folder.folder_api import update_folder_access_to_application_v3 + from ..nested_share_folder.record_api import update_record_share_to_application_v3 - try: - api.communicate_rest(params, rq_remove, 'vault/app_share_remove') - except KeeperApiError as kae: - logging.error('Failed to remove shares for update: %s' % kae.message) - return - - app_shares = [] - for uid in uids_to_update: - is_record = uid in params.record_cache - is_shared_folder = api.is_shared_folder(params, uid) - - if is_record: - share_key = params.record_cache[uid]['record_key_unencrypted'] - share_type = 'SHARE_TYPE_RECORD' - elif is_shared_folder: - share_key = params.shared_folder_cache[uid].get('shared_folder_key_unencrypted') - share_type = 'SHARE_TYPE_FOLDER' - else: + updated = [] + for uid in nsf_uids_to_update: + secret = KSMCommand.classify_secret(params, uid) + if not secret: logging.warning('UID "%s" not found in local cache. Run sync-down and try again.' % uid) continue + if secret['share_type'] == 'SHARE_TYPE_FOLDER': + result = update_folder_access_to_application_v3( + params, uid, app_record_uid, is_editable=is_editable) + else: + result = update_record_share_to_application_v3( + params, uid, app_record_uid, master_key, is_editable=is_editable) + if not result.get('success'): + logging.error('Failed to update NSF share "%s": %s', + uid, result.get('message') or result) + continue + updated.append(uid) - encrypted_secret_key = crypto.encrypt_aes_v2(share_key, master_key) + if uids_to_update: + rq_remove = APIRequest_pb2.RemoveAppSharesRequest() + rq_remove.appRecordUid = utils.base64_url_decode(app_record_uid) + rq_remove.shares.extend(utils.base64_url_decode(uid) for uid in uids_to_update) - app_share = APIRequest_pb2.AppShareAdd() - app_share.secretUid = utils.base64_url_decode(uid) - app_share.shareType = APIRequest_pb2.ApplicationShareType.Value(share_type) - app_share.encryptedSecretKey = encrypted_secret_key - app_share.editable = is_editable + try: + api.communicate_rest(params, rq_remove, 'vault/app_share_remove') + except KeeperApiError as kae: + logging.error('Failed to remove shares for update: %s' % kae.message) + return - app_shares.append(app_share) + app_shares = [] + for uid in uids_to_update: + secret = KSMCommand.classify_secret(params, uid) + if not secret: + logging.warning('UID "%s" not found in local cache. Run sync-down and try again.' % uid) + continue - if not app_shares: - return + share_key = secret['share_key'] + share_type = secret['share_type'] + uid = secret['uid'] - rq_add = APIRequest_pb2.AddAppSharesRequest() - rq_add.appRecordUid = utils.base64_url_decode(app_record_uid) - rq_add.shares.extend(app_shares) + encrypted_secret_key = crypto.encrypt_aes_v2(share_key, master_key) - try: - api.communicate_rest(params, rq_add, 'vault/app_share_add') + app_share = APIRequest_pb2.AppShareAdd() + app_share.secretUid = utils.base64_url_decode(uid) + app_share.shareType = APIRequest_pb2.ApplicationShareType.Value(share_type) + app_share.encryptedSecretKey = encrypted_secret_key + app_share.editable = is_editable + + app_shares.append(app_share) + + if not app_shares and not updated: + return + + if app_shares: + rq_add = APIRequest_pb2.AddAppSharesRequest() + rq_add.appRecordUid = utils.base64_url_decode(app_record_uid) + rq_add.shares.extend(app_shares) + + try: + api.communicate_rest(params, rq_add, 'vault/app_share_add') + updated.extend(uids_to_update) + except KeeperApiError as kae: + logging.error('Failed to re-add shares with updated permissions: %s' % kae.message) + return + + if updated: perm = "editable" if is_editable else "read-only" print(bcolors.OKGREEN + f'\nSuccessfully updated share permissions to {perm} for app uid={app_record_uid}:' + bcolors.ENDC) - for uid in uids_to_update: + for uid in updated: print(f'\t{uid}') print() - except KeeperApiError as kae: - logging.error('Failed to re-add shares with updated permissions: %s' % kae.message) @staticmethod def remove_share(params, app_name_or_uid, secret_uids): @@ -1248,11 +1528,38 @@ def remove_share(params, app_name_or_uid, secret_uids): app_uid = app.get('record_uid') - rq = APIRequest_pb2.RemoveAppSharesRequest() + resolved_uids = KSMCommand.resolve_secret_uids(params, secret_uids) + if not resolved_uids: + raise Exception("No valid record or folder secrets were found for removal") + + from ..nested_share_folder.folder_api import revoke_folder_access_from_application_v3 + from ..nested_share_folder.record_api import unshare_record_from_application_v3 + + classic_uids = [] + for uid in resolved_uids: + secret = KSMCommand.classify_secret(params, uid) + if secret and secret['share_type'] == 'SHARE_TYPE_FOLDER' and is_nested_share_folder(params, uid): + result = revoke_folder_access_from_application_v3(params, uid, app_uid) + if not result.get('success'): + raise KeeperApiError( + result.get('status') or 'access_denied', + result.get('message') or f'Failed to remove NSF folder share {uid}') + continue + if secret and secret['share_type'] == 'SHARE_TYPE_RECORD' and is_nested_share_record(params, uid): + result = unshare_record_from_application_v3(params, uid, app_uid) + if not result.get('success'): + message = '; '.join( + r.get('message') or r.get('status') or 'revoke failed' + for r in result.get('results', [])) or f'Failed to remove NSF record share {uid}' + raise KeeperApiError('share_failed', message) + continue + classic_uids.append(uid) - rq.appRecordUid = utils.base64_url_decode(app_uid) - rq.shares.extend((utils.base64_url_decode(x) for x in secret_uids)) - api.communicate_rest(params, rq, 'vault/app_share_remove') + if classic_uids: + rq = APIRequest_pb2.RemoveAppSharesRequest() + rq.appRecordUid = utils.base64_url_decode(app_uid) + rq.shares.extend((utils.base64_url_decode(x) for x in classic_uids)) + api.communicate_rest(params, rq, 'vault/app_share_remove') print(bcolors.OKGREEN + "Secret share was successfully removed from the application\n" + bcolors.ENDC) @staticmethod diff --git a/keepercommander/commands/nested_share_folder/folder_commands.py b/keepercommander/commands/nested_share_folder/folder_commands.py index eb8be8341..52eb39dbb 100644 --- a/keepercommander/commands/nested_share_folder/folder_commands.py +++ b/keepercommander/commands/nested_share_folder/folder_commands.py @@ -21,9 +21,11 @@ from ..base import Command from ...error import CommandError from ... import nested_share_folder as _nsf +from ... import vault_extensions from .helpers import ( ROOT_FOLDER_UID, normalize_parent_uid, resolve_folder_uid, parse_expiration, + validate_rotate_on_expiration, command_error_handler, check_result, check_folder_edit_permission, check_folder_share_permission, check_folder_delete_permission, classify_share_recipient, @@ -238,18 +240,32 @@ def execute(self, params, **kwargs): show_folders = kwargs.get('folders', False) show_records = kwargs.get('records', False) + roe_eligible = bool(kwargs.get('roe_eligible')) fmt = kwargs.get('format', 'table') - if not show_folders and not show_records: + if roe_eligible: + show_folders, show_records = True, False + elif not show_folders and not show_records: show_folders = show_records = True combined = [] if show_folders: - combined.extend(self._collect_folders(params)) + folders = self._collect_folders(params) + if roe_eligible: + folders = [ + row for row in folders + if vault_extensions.nested_share_folder_has_pam_user_with_rotation( + params, row[1]) + ] + combined.extend(folders) if show_records: combined.extend(self._collect_records(params)) if not combined: + if roe_eligible: + logging.info( + "No Nested Share Folders eligible for --rotate-on-expiration.") + return self._print_empty_summary(params, show_folders, show_records) return @@ -341,6 +357,7 @@ def execute(self, params, **kwargs): recipients = kwargs.get('user') or [] folder_args = kwargs.get('folder') or [] role = kwargs.get('role') or 'viewer' + rotate_on_expiration = bool(kwargs.get('rotate_on_expiration')) if not folder_args: raise CommandError('nsf-share-folder', 'Folder path or UID is required') @@ -353,6 +370,9 @@ def execute(self, params, **kwargs): expiration = parse_expiration( kwargs.get('expire_at'), kwargs.get('expire_in'), 'nsf-share-folder') + if rotate_on_expiration: + validate_rotate_on_expiration('nsf-share-folder', action, expiration) + for folder_arg in folder_args: folder_uid = resolve_folder_uid(params, folder_arg) if not folder_uid: @@ -361,6 +381,13 @@ def execute(self, params, **kwargs): identifier=folder_arg) check_folder_share_permission(params, folder_uid, 'nsf-share-folder') + if rotate_on_expiration and \ + not vault_extensions.nested_share_folder_has_pam_user_with_rotation(params, folder_uid): + raise CommandError( + 'nsf-share-folder', + '--rotate-on-expiration requires the folder to contain at least one pamUser ' + f'record with rotation configured. Ineligible folder: {folder_arg!r}') + targets = self._collect_targets(params, recipients, folder_uid, folder_arg) if not targets: raise CommandError( @@ -368,7 +395,8 @@ def execute(self, params, **kwargs): f'No valid recipients resolved for folder {folder_arg!r}') for recipient, is_team in targets: self._apply(params, action, folder_uid, recipient, role, - expiration, as_team=is_team) + expiration, as_team=is_team, + rotate_on_expiration=rotate_on_expiration) @classmethod def _collect_targets(cls, params, recipients, folder_uid, folder_arg): @@ -464,7 +492,7 @@ def _expand_existing(params, folder_uid, folder_arg): @classmethod def _apply(cls, params, action, folder_uid, recipient, role, expiration, - as_team=False): + as_team=False, rotate_on_expiration=False): api_name, verb = cls._ACTIONS[action] api_func = getattr(_nsf, api_name) kw = dict(params=params, folder_uid=folder_uid, user_uid=recipient, @@ -473,6 +501,8 @@ def _apply(cls, params, action, folder_uid, recipient, role, expiration, kw['role'] = role if action == 'grant' and expiration is not None: kw['expiration_timestamp'] = expiration + if action == 'grant' and rotate_on_expiration: + kw['rotate_on_expiration'] = True kind = 'Team' if as_team else 'User' try: result = api_func(**kw) diff --git a/keepercommander/commands/nested_share_folder/helpers.py b/keepercommander/commands/nested_share_folder/helpers.py index b4352a1dd..e5dd397ec 100644 --- a/keepercommander/commands/nested_share_folder/helpers.py +++ b/keepercommander/commands/nested_share_folder/helpers.py @@ -103,6 +103,15 @@ def command_error_handler(cmd_name): raise CommandError(cmd_name, str(exc)) +def normalize_nsf_user_message(message): + """Replace legacy server terminology in user-facing error text.""" + if not message: + return message + return (message + .replace('Keeper Drive', 'Nested Share Folder') + .replace('keeper drive', 'nested share folder')) + + def check_result(result, cmd_name): """Raise ``CommandError`` when *result['success']* is falsy. @@ -110,7 +119,8 @@ def check_result(result, cmd_name): appears in almost every command. """ if not result.get('success'): - raise CommandError(cmd_name, result.get('message', 'Unknown error')) + raise CommandError(cmd_name, normalize_nsf_user_message( + result.get('message', 'Unknown error'))) # ═══════════════════════════════════════════════════════════════════════════ @@ -327,6 +337,19 @@ def validate_share_expiration_timestamp(expiration_ms, cmd_name, *, now_ms=None) ) +def validate_rotate_on_expiration(cmd_name, action, expiration): + """Reject ``--rotate-on-expiration`` unless granting with a positive expiry.""" + if action != 'grant': + raise CommandError( + cmd_name, + '--rotate-on-expiration is only valid when granting access') + if not isinstance(expiration, int) or expiration <= 0: + raise CommandError( + cmd_name, + '--rotate-on-expiration requires a positive --expire-at / --expire-in ' + '(cannot be "never").') + + def parse_expiration(expire_at, expire_in, cmd_name): """Parse ``--expire-at`` / ``--expire-in`` into a millisecond timestamp. @@ -364,7 +387,9 @@ def parse_expiration(expire_at, expire_in, cmd_name): cmd_name, 'Share expiration must be at least 1 minute.', ) + # Freeze now for compute + validate (classic share-record / share-folder pattern). now = datetime.datetime.now(timezone.utc) + now_ms = int(now.timestamp() * 1000) delta_map = { 'mi': timedelta(minutes=amount), 'h': timedelta(hours=amount), @@ -374,7 +399,7 @@ def parse_expiration(expire_at, expire_in, cmd_name): } delta = next(v for k, v in delta_map.items() if unit.startswith(k)) expiration_ms = int((now + delta).timestamp() * 1000) - validate_share_expiration_timestamp(expiration_ms, cmd_name) + validate_share_expiration_timestamp(expiration_ms, cmd_name, now_ms=now_ms) return expiration_ms diff --git a/keepercommander/commands/nested_share_folder/parsers.py b/keepercommander/commands/nested_share_folder/parsers.py index ff9b3ac9f..37ad1baf6 100644 --- a/keepercommander/commands/nested_share_folder/parsers.py +++ b/keepercommander/commands/nested_share_folder/parsers.py @@ -71,6 +71,11 @@ def _make_parser(prog, description): '--folders', action='store_true', help='Show only folders') nested_share_folder_list_parser.add_argument( '--records', action='store_true', help='Show only records') +nested_share_folder_list_parser.add_argument( + '--roe-eligible', dest='roe_eligible', action='store_true', + help='only list Nested Share Folders eligible for --rotate-on-expiration ' + '(contain at least one pamUser record with rotation configured; ' + 'implies --folders)') nested_share_folder_list_parser.add_argument( '--format', dest='format', choices=['table', 'csv', 'json'], default='table', help='Output format (default: table)') @@ -104,6 +109,12 @@ def _make_parser(prog, description): _sf_expire.add_argument( '--expire-in', dest='expire_in', action='store', metavar='PERIOD', help='share expiration: never or period (e.g. 30d, 6mo, 1y, 24h, 30mi)') +nested_share_folder_share_parser.add_argument( + '-roe', '--rotate-on-expiration', dest='rotate_on_expiration', action='store_true', + help='rotate the password when the share access expires. ' + 'Only valid on grant; requires a positive --expire-at/--expire-in ' + '(not "never") and at least one pamUser record with rotation ' + 'configured in the folder.') nested_share_folder_share_parser.add_argument( 'folder', nargs='+', type=str, help='Nested Share Folder path or UID') @@ -227,6 +238,11 @@ def _make_parser(prog, description): '--expire-in', dest='expire_in', metavar='[(mi)nutes|(h)ours|(d)ays|(mo)nths|(y)ears]', type=str, help='share expiration: never or period (e.g. 30d, 6mo, 1y)') +nested_share_record_share_parser.add_argument( + '-roe', '--rotate-on-expiration', dest='rotate_on_expiration', action='store_true', + help='rotate the password when the share access expires. ' + 'Only valid on grant; requires a positive --expire-at/--expire-in ' + '(not "never") and a pamUser record with rotation configured.') nested_share_record_permission_parser = _make_parser( diff --git a/keepercommander/commands/nested_share_folder/record_commands.py b/keepercommander/commands/nested_share_folder/record_commands.py index 6fde8bc25..6a0480646 100644 --- a/keepercommander/commands/nested_share_folder/record_commands.py +++ b/keepercommander/commands/nested_share_folder/record_commands.py @@ -97,7 +97,12 @@ def execute(self, params, **kwargs): return with command_error_handler('nsf-record-add'): - result = _nsf.create_record_v3(params=params, folder_uid=folder_uid, record_data=data) + result = _nsf.create_record_v3( + params=params, + folder_uid=folder_uid, + record_data=data, + record_uid=kwargs.get('record_uid'), + ) check_result(result, 'nsf-record-add') params.sync_data = True return result['record_uid'] diff --git a/keepercommander/commands/nested_share_folder/sharing_commands.py b/keepercommander/commands/nested_share_folder/sharing_commands.py index d4029fac5..36128473c 100644 --- a/keepercommander/commands/nested_share_folder/sharing_commands.py +++ b/keepercommander/commands/nested_share_folder/sharing_commands.py @@ -26,8 +26,10 @@ from ..base import Command from ...error import CommandError from ... import nested_share_folder as _nsf +from ... import vault_extensions from .helpers import ( parse_expiration, get_access_role_label, + validate_rotate_on_expiration, command_error_handler, check_result, check_record_share_permission, collect_records_in_folder, @@ -58,6 +60,7 @@ def execute(self, params, **kwargs): dry_run = kwargs.get('dry_run', False) recursive = kwargs.get('recursive', False) force = kwargs.get('force', False) + rotate_on_expiration = bool(kwargs.get('rotate_on_expiration')) if not record_arg: raise CommandError('nsf-share-record', 'Record path or UID is required') @@ -76,23 +79,38 @@ def execute(self, params, **kwargs): access_role_type = _nsf.resolve_role_name(role) if role else None record_uids = self._resolve_record_uids(params, record_arg, recursive) + if rotate_on_expiration: + validate_rotate_on_expiration('nsf-share-record', action, expiration) + ineligible = [ + uid for uid in record_uids + if not vault_extensions.nested_share_record_is_pam_user_with_rotation(params, uid) + ] + if ineligible: + raise CommandError( + 'nsf-share-record', + '--rotate-on-expiration requires a pamUser record with rotation configured. ' + 'Ineligible record(s): ' + ', '.join(sorted(ineligible))) + for uid in record_uids: check_record_share_permission(params, uid, 'nsf-share-record') if dry_run: - self._print_dry_run(action, record_uids, emails, role, expiration) + self._print_dry_run(action, record_uids, emails, role, expiration, + rotate_on_expiration) return with command_error_handler('nsf-share-record'): for email in emails: for record_uid in record_uids: result, effective_action = self._dispatch( - params, action, record_uid, email, access_role_type, expiration) + params, action, record_uid, email, access_role_type, expiration, + rotate_on_expiration) self._log_results(result, effective_action, email) # Strategy dispatch — returns (result, effective_action) @staticmethod - def _dispatch(params, action, record_uid, email, access_role_type, expiration): + def _dispatch(params, action, record_uid, email, access_role_type, expiration, + rotate_on_expiration=False): if action == 'owner': return (_nsf.transfer_record_ownership_v3( params=params, record_uid=record_uid, new_owner_email=email), 'owner') @@ -102,7 +120,8 @@ def _dispatch(params, action, record_uid, email, access_role_type, expiration): params, record_uid, email) if existing: if _nsf.is_record_share_update_noop( - existing, access_role_type, expiration): + existing, access_role_type, expiration, + rotate_on_expiration=rotate_on_expiration): logging.info( "Record '%s' already shared with '%s' at the requested " "role and expiration; no change needed.", @@ -121,11 +140,13 @@ def _dispatch(params, action, record_uid, email, access_role_type, expiration): return (_nsf.update_record_share_v3( params=params, record_uid=record_uid, recipient_email=email, access_role_type=access_role_type, - expiration_timestamp=expiration), 'update') + expiration_timestamp=expiration, + rotate_on_expiration=rotate_on_expiration), 'update') return (_nsf.share_record_v3( params=params, record_uid=record_uid, recipient_email=email, access_role_type=access_role_type, - expiration_timestamp=expiration), 'grant') + expiration_timestamp=expiration, + rotate_on_expiration=rotate_on_expiration), 'grant') return (_nsf.unshare_record_v3( params=params, record_uid=record_uid, recipient_email=email), 'revoke') @@ -233,7 +254,8 @@ def _resolve_record_uids(params, record_arg, recursive): return [resolved_uid] @staticmethod - def _print_dry_run(action, record_uids, emails, role, expiration): + def _print_dry_run(action, record_uids, emails, role, expiration, + rotate_on_expiration=False): print(f"[dry-run] Action : {action.upper()}") print(f"[dry-run] Records : {', '.join(record_uids)}") if action == 'owner': @@ -245,6 +267,8 @@ def _print_dry_run(action, record_uids, emails, role, expiration): print(f"[dry-run] Role : {role}") if expiration: print(f"[dry-run] Expires : {expiration} ms") + if rotate_on_expiration: + print("[dry-run] Rotate : rotate password on share expiration") # ══════════════════════════════════════════════════════════════════════════ diff --git a/keepercommander/commands/pam/config_helper.py b/keepercommander/commands/pam/config_helper.py index d2aded194..a011fd862 100644 --- a/keepercommander/commands/pam/config_helper.py +++ b/keepercommander/commands/pam/config_helper.py @@ -1,15 +1,16 @@ -import base64 import json import logging import os from keeper_secrets_manager_core.utils import string_to_bytes, bytes_to_string -from ..folder import FolderMoveCommand from ..record import RecordRemoveCommand -from ... import api, crypto, utils, vault, vault_extensions +from ... import api, crypto, utils, vault, vault_extensions, subfolder +from ...error import KeeperApiError +from ...nested_share_folder.common import get_folder_key +from ...nested_share_folder.record_api import create_record_data_v3, record_add_pam_configuration_v3 from ...params import KeeperParams -from ...proto import pam_pb2, router_pb2 +from ...proto import folder_pb2, pam_pb2, record_pb2, router_pb2 def pam_decrypt_configuration_data(pam_config_v6_record): @@ -66,8 +67,27 @@ def pam_configuration_get_field(unencrypted_record, field_identifier): return field +def _resolve_pam_configuration_folder_key(params, folder_uid): + # type: (KeeperParams, str) -> bytes | None + folder_key = get_folder_key(params, folder_uid, raise_on_missing=False) + if folder_key: + return folder_key + + folder = params.folder_cache.get(folder_uid) + shared_folder_uid = None + if isinstance(folder, subfolder.SharedFolderFolderNode): + shared_folder_uid = folder.shared_folder_uid + elif isinstance(folder, subfolder.SharedFolderNode): + shared_folder_uid = folder.uid + if shared_folder_uid and shared_folder_uid in params.shared_folder_cache: + shared_folder = params.shared_folder_cache.get(shared_folder_uid) + return shared_folder.get('shared_folder_key_unencrypted') + return None + + def pam_configuration_create_record_v6(params, record, folder_uid): - # type: (KeeperParams, vault.TypedRecord, str, str) -> None + # type: (KeeperParams, vault.TypedRecord, str) -> None + """Create a classic PAM configuration via pam/add_configuration_record.""" if not record.record_uid: record.record_uid = utils.generate_uid() @@ -85,6 +105,66 @@ def pam_configuration_create_record_v6(params, record, folder_uid): api.communicate_rest(params, car, 'pam/add_configuration_record') +def pam_configuration_create_record_nsf(params, record, folder_uid): + # type: (KeeperParams, vault.TypedRecord, str) -> None + """Create a PAM configuration in an NSF folder via vault/records/v3/add_pam_configuration.""" + if not record.record_uid: + record.record_uid = utils.generate_uid() + + if not record.record_key: + record.record_key = utils.generate_aes_key() + + record_data = vault_extensions.extract_typed_record_data(record) + folder_key = _resolve_pam_configuration_folder_key(params, folder_uid) if folder_uid else None + client_time = utils.current_milli_time() + + audit = None + if params.enterprise_ec_key: + audit_data = vault_extensions.extract_audit_data(record) + if audit_data: + audit = record_pb2.RecordAudit() + audit.version = 0 + audit.data = crypto.encrypt_ec( + json.dumps(audit_data).encode('utf-8'), params.enterprise_ec_key) + + if folder_uid and folder_key: + record_add = create_record_data_v3( + record_uid=record.record_uid, + record_key=record.record_key, + data=record_data, + folder_uid=folder_uid, + folder_key=folder_key, + data_key=params.data_key, + owner_key=params.data_key, + client_modified_time=client_time, + audit=audit, + ) + else: + record_add = create_record_data_v3( + record_uid=record.record_uid, + record_key=record.record_key, + data=record_data, + data_key=params.data_key, + owner_key=params.data_key, + client_modified_time=client_time, + audit=audit, + ) + if folder_uid: + record_add.folderUid = utils.base64_url_decode(folder_uid) + record_add.recordKeyEncryptedBy = folder_pb2.ENCRYPTED_BY_USER_KEY + + response = record_add_pam_configuration_v3(params, [record_add], client_time=client_time) + if not response.records: + raise KeeperApiError('no_results', 'No results from PAM configuration creation') + + record_rs = response.records[0] + if record_rs.status != record_pb2.RS_SUCCESS: + raise KeeperApiError( + record_pb2.RecordModifyResult.Name(record_rs.status), + record_rs.message or 'Failed to create PAM configuration record') + record.revision = response.revision + + def pam_configuration_create(params, gateway_uid_bytes, config_json_str, child_config_json_strings=None, parent_uid_bytes=None): config_operation = pam_pb2.PAMDataOperation() @@ -162,10 +242,36 @@ def pam_configurations_get_all(params): def pam_configuration_remove(params, configuration_uid): # TODO: Check if there are record rotations associated with this config and warn user about that before removing. - RecordRemoveCommand().execute(params, record=configuration_uid, force=True) + from ..nested_share_folder.helpers import is_nested_share_record + from ... import nested_share_folder as _nsf + from ...subfolder import find_folders + from .config_facades import PamConfigurationRecordFacade + + if is_nested_share_record(params, configuration_uid): + folder_uids = list(find_folders(params, configuration_uid)) + folder_uid = folder_uids[0] if folder_uids else None + if not folder_uid: + config = vault.KeeperRecord.load(params, configuration_uid) + if config and isinstance(config, vault.TypedRecord): + facade = PamConfigurationRecordFacade() + facade.record = config + folder_uid = facade.folder_uid + result = _nsf.remove_record_v3(params, [{ + 'record_uid': configuration_uid, + 'folder_uid': folder_uid, + 'operation_type': 'owner-trash', + }], dry_run=False) + if not result.get('confirmed'): + raise Exception( + 'PAM Configuration NSF removal was not confirmed by the server.') + else: + RecordRemoveCommand().execute(params, record=configuration_uid, force=True) if configuration_uid in params.record_cache: del params.record_cache[configuration_uid] + nested_recs = getattr(params, 'nested_share_records', {}) + if configuration_uid in nested_recs: + del nested_recs[configuration_uid] logging.info('PAM Configuration was removed successfully.') diff --git a/keepercommander/commands/pam/vault_target.py b/keepercommander/commands/pam/vault_target.py new file mode 100644 index 000000000..45d28e589 --- /dev/null +++ b/keepercommander/commands/pam/vault_target.py @@ -0,0 +1,680 @@ +from ..folder import FolderMoveCommand +from ... import api, record_management, vault, vault_extensions +from ...error import CommandError +from ...nested_share_folder.folder_record_api import move_record_v3 +from ...subfolder import BaseFolderNode, get_folder_path, try_resolve_path +from .config_facades import PamConfigurationRecordFacade + + +def is_nested_share_folder(params, folder_uid): + if not folder_uid: + return False + + if folder_uid in getattr(params, 'nested_share_folders', {}): + return True + + subfolder = getattr(params, 'subfolder_cache', {}).get(folder_uid) + if isinstance(subfolder, dict) and subfolder.get('source') == 'nested_share_folder': + return True + + folder = getattr(params, 'folder_cache', {}).get(folder_uid) + return bool(folder and getattr(folder, 'type', None) == BaseFolderNode.NestedShareFolderType) + + +def resolve_pam_folder_uid(params, folder_name, allow_legacy_user=False): + if not folder_name: + return None + + if folder_name in getattr(params, 'shared_folder_cache', {}): + return folder_name + + if allow_legacy_user and folder_name in getattr(params, 'folder_cache', {}): + return folder_name + + if is_nested_share_folder(params, folder_name): + return folder_name + + rs = try_resolve_path(params, folder_name) + if rs: + folder, remainder = rs + if folder and not remainder and folder.uid: + if (folder.type == BaseFolderNode.SharedFolderType + or (allow_legacy_user and folder.uid in getattr(params, 'folder_cache', {})) + or is_nested_share_folder(params, folder.uid)): + return folder.uid + + nsf_matches = [ + uid for uid, folder in getattr(params, 'nested_share_folders', {}).items() + if str(folder.get('name', '')).casefold() == str(folder_name).casefold() + ] + if len(nsf_matches) == 1: + return nsf_matches[0] + + return None + + +def pam_folder_exists(params, folder_uid): + if not folder_uid: + return False + if folder_uid in getattr(params, 'folder_cache', {}): + return True + return is_nested_share_folder(params, folder_uid) + + +def get_pam_folder_path(params, folder_uid, delimiter='/'): + if not folder_uid: + return '' + + parts = [] + uid = folder_uid + seen = set() + while uid and uid not in seen: + seen.add(uid) + folder = getattr(params, 'folder_cache', {}).get(uid) + if folder is not None: + name = str(folder.name or '').replace(delimiter, delimiter * 2) + parts.insert(0, name) + uid = folder.parent_uid + continue + + nsf = getattr(params, 'nested_share_folders', {}).get(uid) + if nsf: + name = str(nsf.get('name', '')).replace(delimiter, delimiter * 2) + parts.insert(0, name) + uid = nsf.get('parent_uid') + continue + break + + if parts: + return delimiter.join(parts) + return get_folder_path(params, folder_uid, delimiter=delimiter) + + +def resolve_pam_application_folder(params, pam_config_uid, command='pam'): + pam_config_record = vault.KeeperRecord.load(params, pam_config_uid) + if not pam_config_record: + raise CommandError(command, f'PAM Configuration not found: {pam_config_uid}') + + facade = PamConfigurationRecordFacade() + facade.record = pam_config_record + facade.load_typed_fields() + folder_uid = facade.folder_uid + if not folder_uid: + raise CommandError( + command, + f"PAM Configuration '{pam_config_record.title}' has no application folder configured.\n" + f'Please configure the application folder in the PAM Configuration record.') + + if not pam_folder_exists(params, folder_uid): + raise CommandError( + command, + f'Application folder (UID: {folder_uid}) not found in vault.\n' + f'Ensure the folder is shared with you.') + + return folder_uid, get_pam_folder_path(params, folder_uid) + + +def _find_child_folder(params, parent_uid, name=None, name_suffix=None): + if not parent_uid: + return None + + parent_uid = parent_uid or None + for uid, folder in getattr(params, 'folder_cache', {}).items(): + if folder.parent_uid != parent_uid: + continue + folder_name = str(folder.name or '') + if name is not None and folder_name == name: + return uid + if name_suffix is not None and folder_name.endswith(name_suffix): + return uid + + for uid, folder in getattr(params, 'nested_share_folders', {}).items(): + if folder.get('parent_uid') != parent_uid: + continue + folder_name = str(folder.get('name', '')) + if name is not None and folder_name == name: + return uid + if name_suffix is not None and folder_name.endswith(name_suffix): + return uid + + return None + + +def find_nsf_users_subfolder(params, parent_uid): + return _find_child_folder(params, parent_uid, name_suffix=' - Users') + + +def records_in_folder(params, folder_uid): + records = set((getattr(params, 'subfolder_record_cache', None) or {}).get(folder_uid, set()) or set()) + nsf_records = getattr(params, 'nested_share_folder_records', None) or {} + if folder_uid in nsf_records: + records.update(nsf_records[folder_uid] or set()) + return records + + +def resolve_provision_target_folder(params, pam_config_uid, folder_spec=None, department='Default', + command='pam'): + app_uid, app_path = resolve_pam_application_folder(params, pam_config_uid, command=command) + + if folder_spec: + folder_spec = str(folder_spec).strip() + resolved = resolve_pam_folder_uid(params, folder_spec, allow_legacy_user=True) + if resolved: + return resolved + if folder_spec in getattr(params, 'shared_folder_cache', {}): + return folder_spec + relative = folder_spec.strip('/') + if is_nested_share_folder(params, app_uid): + return ensure_pam_folder_path(params, app_uid, relative, command=command) + if app_path: + return _ensure_legacy_folder_path(params, f'{app_path}/{relative}', command=command) + return _ensure_legacy_folder_path(params, relative, command=command) + + if is_nested_share_folder(params, app_uid): + users_uid = find_nsf_users_subfolder(params, app_uid) + if users_uid: + return users_uid + return ensure_pam_folder_path(params, app_uid, f'PAM Users/{department}', command=command) + + target_path = f'{app_path}/PAM Users/{department}' if app_path else f'PAM Users/{department}' + return _ensure_legacy_folder_path(params, target_path, command=command) + + +def resolve_access_user_save_folder(params, config_uid, folder_spec=None, command='pam-access-user-provision'): + if folder_spec: + folder_uid = resolve_pam_folder_uid(params, folder_spec, allow_legacy_user=True) + if not folder_uid: + raise CommandError(command, f'Folder not found: {folder_spec}') + return folder_uid + + app_uid, _ = resolve_pam_application_folder(params, config_uid, command=command) + if is_nested_share_folder(params, app_uid): + return find_nsf_users_subfolder(params, app_uid) or app_uid + return app_uid + + +def _ensure_legacy_folder_path(params, folder_path, command='pam'): + folder_uid = None + rs = try_resolve_path(params, folder_path) + if rs: + folder_node, remainder = rs + if folder_node and not remainder: + folder_uid = folder_node.uid + + if folder_uid: + return folder_uid + + from ..folder import FolderMakeCommand + components = [x.strip() for x in str(folder_path or '').replace('\\', '/').split('/') if x.strip()] + current_path = '' + for i, component in enumerate(components): + current_path = f'{current_path}/{component}' if current_path else component + rs = try_resolve_path(params, current_path) + if rs and rs[0] and not rs[1]: + continue + FolderMakeCommand().execute( + params, + folder=current_path, + shared_folder=(i == 0), + user_folder=(i != 0), + ) + api.sync_down(params) + + rs = try_resolve_path(params, folder_path) + if rs and rs[0] and not rs[1]: + return rs[0].uid + raise CommandError(command, f'Folder path creation succeeded but final UID not found: {folder_path}') + + +def get_pam_folder_info(params, folder_uid): + # type: (...) -> Optional[dict] + """Return folder name, uid, and type for a PAM configuration target folder.""" + if not folder_uid: + return None + if folder_uid in getattr(params, 'shared_folder_cache', {}): + sf = api.get_shared_folder(params, folder_uid) + return { + 'uid': folder_uid, + 'name': sf.name if sf else folder_uid, + 'type': 'shared_folder', + } + if is_nested_share_folder(params, folder_uid): + nsf = getattr(params, 'nested_share_folders', {}).get(folder_uid, {}) + return { + 'uid': folder_uid, + 'name': nsf.get('name', folder_uid), + 'type': 'nested_share_folder', + } + folder = getattr(params, 'folder_cache', {}).get(folder_uid) + if folder: + return { + 'uid': folder_uid, + 'name': folder.name, + 'type': 'user_folder', + } + return {'uid': folder_uid, 'name': folder_uid, 'type': 'unknown'} + + +def format_pam_folder_display(folder_info): + # type: (Optional[dict]) -> str + if not folder_info: + return '' + suffix = ' [NSF]' if folder_info.get('type') == 'nested_share_folder' else '' + return f'{folder_info["name"]} ({folder_info["uid"]}){suffix}' + + +def resolve_pam_config_folder_info(params, facade, record_uid): + # type: (...) -> Optional[dict] + from ...subfolder import find_parent_top_folder + + folder_info = get_pam_folder_info(params, facade.folder_uid) + if folder_info and folder_info.get('type') != 'unknown': + return folder_info + shared_folder_parents = find_parent_top_folder(params, record_uid) + if shared_folder_parents: + sf = shared_folder_parents[0] + return {'uid': sf.uid, 'name': sf.name, 'type': 'shared_folder'} + return folder_info + + +def pam_folder_json_payload(folder_info): + # type: (Optional[dict]) -> dict + payload = {} + if not folder_info: + return payload + payload['folder'] = folder_info + if folder_info.get('type') == 'shared_folder': + payload['shared_folder'] = { + 'name': folder_info.get('name'), + 'uid': folder_info.get('uid'), + } + return payload + + +def record_exists_in_vault(params, record_uid): + # type: (...) -> bool + from ..nested_share_folder.helpers import is_nested_share_record + + if not record_uid: + return False + return (record_uid in getattr(params, 'record_cache', {}) + or is_nested_share_record(params, record_uid)) + + +def _record_matches_type(record, rec_type): + # type: (...) -> bool + if not rec_type: + return True + record_type = getattr(record, 'record_type', None) + if isinstance(rec_type, str): + return record_type == rec_type + try: + return record_type in rec_type + except TypeError: + return record_type == rec_type + + +def resolve_pam_record(params, identifier, rec_type=None): + # type: (...) -> Optional[vault.KeeperRecord] + """Resolve a record by UID, folder path, or title including Nested Share Records. + + *rec_type* may be a single record type string or a collection of allowed types. + """ + if not identifier: + return None + + if identifier in getattr(params, 'record_cache', {}): + rec = vault.KeeperRecord.load(params, identifier) + if rec and _record_matches_type(rec, rec_type): + return rec + + from ...nested_share_folder import removal_api as _nsf + resolved_uid = _nsf.resolve_nested_share_record_uid(params, identifier) + if resolved_uid: + rec = vault.KeeperRecord.load(params, resolved_uid) + if rec and _record_matches_type(rec, rec_type): + return rec + + rs = try_resolve_path(params, identifier) + if rs is not None: + folder, record_title = rs + if folder is not None and record_title is not None: + folder_uid = folder.uid or '' + subfolder_cache = getattr(params, 'subfolder_record_cache', None) or {} + if folder_uid in subfolder_cache: + for uid in subfolder_cache[folder_uid]: + record = vault.KeeperRecord.load(params, uid) + if record and record.title.casefold() == record_title.casefold(): + if _record_matches_type(record, rec_type): + return record + + l_name = identifier.casefold() + matches = [] + for record_uid in getattr(params, 'record_cache', {}): + record = vault.KeeperRecord.load(params, record_uid) + if record and record.title.casefold() == l_name: + if _record_matches_type(record, rec_type): + matches.append(record) + if len(matches) > 1: + break + if len(matches) == 1: + return matches[0] + return None + + +def get_vault_record_title_type(params, record_uid): + # type: (...) -> tuple + rec = vault.KeeperRecord.load(params, record_uid) + if rec: + return rec.title or '[untitled]', rec.record_type or '[unknown]' + nsf_data = getattr(params, 'nested_share_record_data', {}).get(record_uid, {}) + data_json = nsf_data.get('data_json', {}) if isinstance(nsf_data, dict) else {} + if isinstance(data_json, dict) and data_json: + return (data_json.get('title') or '[record inaccessible]', + data_json.get('type') or '[record inaccessible]') + return '[record inaccessible]', '[record inaccessible]' + + +def traverse_pam_folder_subtree(params, root_folder_uid, callback): + # type: (...) -> None + seen = set() + queue = [root_folder_uid] + while queue: + f_uid = queue.pop(0) + if not f_uid or f_uid in seen: + continue + seen.add(f_uid) + callback(f_uid) + folder = getattr(params, 'folder_cache', {}).get(f_uid) + if folder and folder.subfolders: + for child_uid in folder.subfolders: + if child_uid not in seen: + queue.append(child_uid) + for uid, nsf in getattr(params, 'nested_share_folders', {}).items(): + if nsf.get('parent_uid') == f_uid and uid not in seen: + queue.append(uid) + + +def collect_pam_folder_uids(params, folder_name): + # type: (...) -> set + folder_uids = set() + if not folder_name: + return folder_uids + + resolved = resolve_pam_folder_uid(params, folder_name, allow_legacy_user=True) + if resolved: + traverse_pam_folder_subtree(params, resolved, folder_uids.add) + return folder_uids + + rs = try_resolve_path(params, folder_name, find_all_matches=True) + if rs is not None: + folder, record_title = rs + if not record_title: + folders = folder if isinstance(folder, list) else [folder] + for f in folders: + if isinstance(f, BaseFolderNode) and f.uid: + traverse_pam_folder_subtree(params, f.uid, folder_uids.add) + + return folder_uids + + +def find_pam_records_by_search(params, search_str, record_version=3, record_types=None): + # type: (...) -> list + types = tuple(record_types) if record_types else None + records = list(vault_extensions.find_records( + params, search_str=search_str, record_version=record_version, record_type=types)) + if search_str and len(records) == 0: + rec = resolve_pam_record(params, search_str) + if isinstance(rec, vault.TypedRecord): + if rec.version == record_version and (not types or rec.record_type in types): + records = [rec] + return [r for r in records if isinstance(r, vault.TypedRecord)] + + +def _find_child_folder_uid(params, parent_uid, name): + return _find_child_folder(params, parent_uid, name=name) + + +def ensure_pam_folder_path(params, base_folder_uid, relative_path, command='pam'): + if not base_folder_uid: + raise CommandError(command, 'Base folder UID is required') + + if base_folder_uid not in getattr(params, 'folder_cache', {}) \ + and base_folder_uid not in getattr(params, 'nested_share_folders', {}): + raise CommandError(command, f'Base folder "{base_folder_uid}" not found') + + components = [x.strip() for x in str(relative_path or '').replace('\\', '/').split('/') if x.strip()] + current_uid = base_folder_uid + if not components: + return current_uid + + for component in components: + child_uid = _find_child_folder_uid(params, current_uid, component) + if child_uid: + current_uid = child_uid + continue + + if is_nested_share_folder(params, current_uid): + from ...nested_share_folder.folder_api import create_folder_v3 + result = create_folder_v3(params, component, parent_uid=current_uid) + if isinstance(result, dict) and result.get('success') is False: + raise CommandError(command, result.get('message') or 'Failed to create Nested Share Folder') + current_uid = result.get('folder_uid') if isinstance(result, dict) else None + api.sync_down(params) + else: + from ..folder import FolderMakeCommand + parent_path = get_folder_path(params, current_uid) + folder_path = f'{parent_path}{component}' if parent_path else component + FolderMakeCommand().execute(params, folder=folder_path, user_folder=True) + api.sync_down(params) + current_uid = _find_child_folder_uid(params, current_uid, component) + + if not current_uid: + raise CommandError(command, f'Folder creation succeeded but UID not found: {component}') + + return current_uid + + +def place_record_in_folder(params, record_uid, folder_uid, command='pam'): + from ..nested_share_folder.helpers import normalize_nsf_user_message + + if not folder_uid: + raise CommandError(command, 'Target folder UID is required') + + folder_cache = getattr(params, 'folder_cache', {}) + nsf_cache = getattr(params, 'nested_share_folders', {}) + if folder_uid not in folder_cache and folder_uid not in nsf_cache: + raise CommandError(command, f'Folder "{folder_uid}" not found') + + if is_nested_share_folder(params, folder_uid): + result = move_record_v3(params, record_uid, to_folder_uid=folder_uid) + if isinstance(result, dict) and result.get('success') is False: + message = normalize_nsf_user_message(result.get('message')) or \ + 'Failed to place record in Nested Share Folder' + lowered = message.casefold() + if any(token in lowered for token in ('denied', 'permission', 'forbidden', 'read-only')): + message = ( + f'{message}. Verify you have record-management permission ' + f'on the Nested Share Folder.' + ) + raise CommandError(command, message) + api.sync_down(params) + else: + FolderMoveCommand().execute(params, src=record_uid, dst=folder_uid, force=True) + + +def create_record_in_folder(params, record, folder_uid=None, command='pam'): + if folder_uid and is_nested_share_folder(params, folder_uid): + from ... import vault_extensions + from ...nested_share_folder.record_api import create_record_v3 + from ..nested_share_folder.helpers import normalize_nsf_user_message + + if not isinstance(record, vault.TypedRecord): + raise CommandError(command, 'Nested Share Folder record creation requires a typed record') + + result = create_record_v3( + params, + folder_uid=folder_uid, + record_data=vault_extensions.extract_typed_record_data(record), + ) + if not result.get('success'): + raise CommandError(command, normalize_nsf_user_message(result.get('message')) or + 'Failed to create record in Nested Share Folder') + record.record_uid = result['record_uid'] + from ..pam_import.nsf_helpers import sync_down_preserving_nsf_keys + sync_down_preserving_nsf_keys(params) + else: + record_management.add_record_to_folder(params, record, folder_uid) + + +def create_pam_configuration_in_folder(params, record, folder_uid, command='pam-config-new'): + """Create a v6 PAM configuration in *folder_uid* using NSF or classic placement.""" + from .config_helper import pam_configuration_create_record_nsf, pam_configuration_create_record_v6 + + if is_nested_share_folder(params, folder_uid): + pam_configuration_create_record_nsf(params, record, folder_uid) + from ..pam_import.nsf_helpers import sync_down_preserving_nsf_keys + sync_down_preserving_nsf_keys(params) + return + + pam_configuration_create_record_v6(params, record, folder_uid) + api.sync_down(params) + place_record_in_folder(params, record.record_uid, folder_uid, command=command) + + +def is_pam_nsf_record(params, record_uid): + """Return True when a PAM record lives in NSF caches or an NSF folder.""" + if not record_uid: + return False + if record_uid in (getattr(params, 'nested_share_records', None) or {}): + return True + if record_uid in (getattr(params, 'nested_share_record_data', None) or {}): + return True + try: + from ...subfolder import find_folders + for folder_uid in find_folders(params, record_uid): + if is_nested_share_folder(params, folder_uid): + return True + except Exception: + pass + return False + + +def update_pam_record(params, record, command='pam', force_nsf=False): + """Update a PAM record via NSF v3 API or classic record_management. + """ + from ..nested_share_folder.helpers import normalize_nsf_user_message + from ...nested_share_folder.record_api import update_record_v3 + + use_nsf = force_nsf or is_pam_nsf_record(params, getattr(record, 'record_uid', None)) + if use_nsf: + if not isinstance(record, vault.TypedRecord): + raise CommandError(command, 'Nested Share Folder record update requires a typed record') + + result = update_record_v3( + params, + record.record_uid, + data=vault_extensions.extract_typed_record_data(record), + ) + if not result.get('success'): + raise CommandError(command, normalize_nsf_user_message(result.get('message')) or + 'Failed to update record in Nested Share Folder') + from ..pam_import.nsf_helpers import sync_down_preserving_nsf_keys + sync_down_preserving_nsf_keys(params) + else: + record_management.update_record(params, record) + + +def execute_record_add_in_folder(params, args, folder_uid, command='pam'): + """Add a record in *folder_uid*, using NSF-native creation when needed.""" + from ..record_edit import RecordAddCommand + from ..nested_share_folder.record_commands import NestedShareRecordAddCommand + + record_args = dict(args or {}) + if folder_uid and is_nested_share_folder(params, folder_uid): + nsf_args = dict(record_args) + nsf_args.pop('folder', None) + nsf_args['folder_uid'] = folder_uid + uid = NestedShareRecordAddCommand().execute(params, **nsf_args) + if uid: + from ..pam_import.nsf_helpers import sync_down_preserving_nsf_keys + sync_down_preserving_nsf_keys(params) + return uid + + record_args['folder'] = folder_uid + return RecordAddCommand().execute(params, **record_args) + + +def execute_record_v3_add_in_folder(params, args, folder_uid, command='pam'): + """Add a v3 typed record in *folder_uid*, using NSF-native creation when needed.""" + import json + + from ..recordv3 import RecordAddCommand + from ..nested_share_folder.helpers import normalize_nsf_user_message + from ...nested_share_folder.record_api import create_record_v3 + + record_args = dict(args or {}) + if folder_uid and is_nested_share_folder(params, folder_uid): + data = record_args.get('data') + if not data: + raise CommandError(command, 'Record data is required for Nested Share Folder creation') + if isinstance(data, str): + data = json.loads(data) + result = create_record_v3( + params, + folder_uid=folder_uid, + record_data=data, + record_uid=record_args.get('record_uid') or data.get('uid'), + ) + if not result.get('success'): + raise CommandError(command, normalize_nsf_user_message(result.get('message')) or + 'Failed to create record in Nested Share Folder') + from ..pam_import.nsf_helpers import sync_down_preserving_nsf_keys + sync_down_preserving_nsf_keys(params) + return result['record_uid'] + + record_args['folder'] = folder_uid + return RecordAddCommand().execute(params, **record_args) + + +def grant_pam_folder_permissions(params, folder_uid, permissions, command='pam'): + if not permissions: + return + if not is_nested_share_folder(params, folder_uid): + return + + from ..nested_share_folder.helpers import classify_share_recipient + from ...nested_share_folder.folder_api import grant_folder_access_v3 + + for perm in permissions: + if not any(map(lambda x: x is not None, perm.values())): + continue + recipient = perm.get('name') or perm.get('uid') + if not recipient: + continue + + classified = classify_share_recipient(params, recipient) + if not classified: + continue + + kind, identifier = classified + manage_users = bool(perm.get('manage_users')) + manage_records = bool(perm.get('manage_records')) + if manage_users and manage_records: + role = 'full-manager' + elif manage_records: + role = 'content-manager' + elif manage_users: + role = 'share-manager' + else: + role = 'viewer' + + result = grant_folder_access_v3( + params, + folder_uid, + identifier, + role=role, + as_team=kind == 'team', + ) + if isinstance(result, dict) and result.get('success') is False: + raise CommandError(command, result.get('message') or 'Failed to grant Nested Share Folder access') diff --git a/keepercommander/commands/pam_cloud/pam_privileged_access.py b/keepercommander/commands/pam_cloud/pam_privileged_access.py index 21940efa0..768302c17 100644 --- a/keepercommander/commands/pam_cloud/pam_privileged_access.py +++ b/keepercommander/commands/pam_cloud/pam_privileged_access.py @@ -14,10 +14,11 @@ GatewayActionIdpGroupList, ) from keepercommander.commands.pam.router_helper import router_send_action_to_gateway +from keepercommander.commands.pam.vault_target import ( + create_record_in_folder, resolve_access_user_save_folder) from keepercommander.error import CommandError -from keepercommander import api, crypto, record_management, vault +from keepercommander import api, crypto, vault from keepercommander.proto import pam_pb2 -from keepercommander.subfolder import find_parent_top_folder logger = logging.getLogger(__name__) @@ -202,7 +203,7 @@ class PAMAccessUserProvisionCommand(Command): parser.add_argument('--save-record', '-s', dest='save_record', action='store_true', help='Save provisioned credentials as a pamUser record') parser.add_argument('--folder', '-f', dest='folder_uid', - help='Folder UID to save the record in (used with --save-record)') + help='Folder UID, name, or path to save the record in (used with --save-record)') parser.add_argument('--gateway', '-g', dest='gateway', help='Gateway UID or name') @@ -304,13 +305,10 @@ def execute(self, params, **kwargs): user_id_label = idp_label_map.get(idp_type, 'IdP User ID') record.custom.append(vault.TypedField.new_field('text', user_id, user_id_label)) - folder_uid = kwargs.get('folder_uid') - if not folder_uid: - shared_folders = find_parent_top_folder(params, config_uid) - if shared_folders: - sf = shared_folders[0] - folder_uid = sf.parent_uid if sf.parent_uid else sf.uid - record_management.add_record_to_folder(params, record, folder_uid) + folder_uid = resolve_access_user_save_folder( + params, config_uid, folder_spec=kwargs.get('folder_uid')) + + create_record_in_folder(params, record, folder_uid, command='pam-access-user-provision') params.sync_data = True print(f' Record UID: {record.record_uid}') @@ -570,4 +568,4 @@ def execute(self, params, **kwargs): _dispatch_idp_action(params, action, kwargs.get('gateway')) - logging.info(f'User "{username}" removed from group "{group_id}".') \ No newline at end of file + logging.info(f'User "{username}" removed from group "{group_id}".') diff --git a/keepercommander/commands/pam_import/README.md b/keepercommander/commands/pam_import/README.md index 78d62be8b..de43eec19 100644 --- a/keepercommander/commands/pam_import/README.md +++ b/keepercommander/commands/pam_import/README.md @@ -302,7 +302,8 @@ Each Machine (pamMachine, pamDatabase, pamDirectory) can specify **Administrativ > **Note 1:** `pam_settings` _(options, connection)_ are explained only in pamMachine section below (per protocol) but they are present in all machine types. > **Note 2:** `attachments` and `scripts` examples are in `pam_configuration: local` section. > **Note 3:** Post rotation scripts (a.k.a. `scripts`) are executed in following order: `pamUser` scripts after any **successful** rotation for that user, `pamMachine` scripts after any **successful** rotation on the machine and `pamConfiguration` scripts after any rotation using that configuration. - > **Note 4:** When `allow_supply_user` is false and JIT ephemeral is not used, vault may require a launch credential; import can provide it via `launch_credentials` in the resource's `connection` block. + > **Note 4:** Post-rotation scripts can only be attached by the **record owner**. Non-owners will see an upload error during import or when using `pam rotate script add`. + > **Note 5:** When `allow_supply_user` is false and JIT ephemeral is not used, vault may require a launch credential; import can provide it via `launch_credentials` in the resource's `connection` block. JIT and KeeperAI settings below are shared across all resource types (pamMachine, pamDatabase, pamDirectory) except User and RBI (pamRemoteBrowser) records. **Workflow** (approvals / checkout / temporal restrictions) is supported on all four resource types: pamMachine, pamDatabase, pamDirectory, **and** pamRemoteBrowser. diff --git a/keepercommander/commands/pam_import/base.py b/keepercommander/commands/pam_import/base.py index 3ad394261..f3056f377 100644 --- a/keepercommander/commands/pam_import/base.py +++ b/keepercommander/commands/pam_import/base.py @@ -21,7 +21,7 @@ from pathlib import Path from typing import Any, Dict, Optional, List, Union -from ..record_edit import RecordAddCommand as RecordEditAddCommand +from ..pam.vault_target import execute_record_add_in_folder from ..workflow.helpers import RecordResolver, WorkflowFormatter from ... import api, attachment, utils, vault, vault_extensions, \ record_facades, record_management @@ -1068,7 +1068,7 @@ def create_record(self, params, folder_uid): fields.append(f"file=@{x.file}") if fields: args["fields"] = fields - uid = RecordEditAddCommand().execute(params, **args) + uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import') if uid and isinstance(uid, str): self.uid = uid @@ -1163,7 +1163,7 @@ def create_record(self, params, folder_uid): fields.append(f"file=@{x.file}") if fields: args["fields"] = fields - uid = RecordEditAddCommand().execute(params, **args) + uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import') if uid and isinstance(uid, str): self.uid = uid return uid @@ -1433,7 +1433,7 @@ def create_record(self, params, folder_uid): # switch to f.* once RT definition(s) update w/ pamSettings field if fields: args["fields"] = fields - uid = RecordEditAddCommand().execute(params, **args) + uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import') if uid and isinstance(uid, str): self.uid = uid @@ -1626,7 +1626,7 @@ def create_record(self, params, folder_uid): # switch to f.* once RT definition(s) update w/ pamSettings field if fields: args["fields"] = fields - uid = RecordEditAddCommand().execute(params, **args) + uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import') if uid and isinstance(uid, str): self.uid = uid @@ -1774,7 +1774,7 @@ def create_record(self, params, folder_uid): # switch to f.* once RT definition(s) update w/ pamSettings field if fields: args["fields"] = fields - uid = RecordEditAddCommand().execute(params, **args) + uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import') if uid and isinstance(uid, str): self.uid = uid @@ -1879,7 +1879,7 @@ def create_record(self, params, folder_uid): # switch to f.* once RT definition(s) update w/ pamRemoteBrowserSettings field if fields: args["fields"] = fields - uid = RecordEditAddCommand().execute(params, **args) + uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import') if uid and isinstance(uid, str): self.uid = uid diff --git a/keepercommander/commands/pam_import/edit.py b/keepercommander/commands/pam_import/edit.py index 149938837..8bd69c2cd 100644 --- a/keepercommander/commands/pam_import/edit.py +++ b/keepercommander/commands/pam_import/edit.py @@ -50,7 +50,13 @@ from ..ksm import KSMCommand from ..pam import gateway_helper from ..pam.config_helper import pam_configurations_get_all -from ..recordv3 import RecordAddCommand +from ..pam.vault_target import ( + execute_record_v3_add_in_folder, + grant_pam_folder_permissions, + is_nested_share_folder, + is_pam_nsf_record, + update_pam_record, +) from ..record_edit import RecordUploadAttachmentCommand from ..tunnel.port_forward.TunnelGraph import TunnelDAG from ..tunnel.port_forward.tunnel_helpers import get_keeper_tokens @@ -66,7 +72,7 @@ from ...params import LAST_FOLDER_UID, LAST_SHARED_FOLDER_UID from ...proto import record_pb2, APIRequest_pb2, enterprise_pb2 from ...recordv3 import RecordV3 -from ...subfolder import BaseFolderNode +from ...subfolder import BaseFolderNode, NestedShareFolderNode class PAMProjectImportCommand(Command): @@ -76,6 +82,7 @@ class PAMProjectImportCommand(Command): parser.add_argument("--dry-run", "-d", required=False, dest="dry_run", action="store_true", default=False, help="Test import without modifying vault.") parser.add_argument("--sample-data", "-s", required=False, dest="sample_data", action="store_true", default=False, help="Generate sample data.") parser.add_argument("--show-template", "-t", required=False, dest="show_template", action="store_true", default=False, help="Print JSON template required for manual import.") + parser.add_argument("--nsf", required=False, dest="use_nsf", action="store_true", default=False, help="Create project folders and records in Nested Share Folders.") # parser.add_argument("--force", "-e", required=False, dest="force", action="store_true", default=False, help="Force data import (re/configure later)") parser.add_argument("--output", "-o", required=False, dest="output", action="store", choices=["token", "base64", "json", "k8s"], default="base64", help="Output format (token: one-time token, config: base64/json/k8s)") @@ -112,6 +119,7 @@ def execute(self, params, **kwargs): project["options"]["dry_run"] = kwargs.get("dry_run", False) project["options"]["sample_data"] = kwargs.get("sample_data", False) project["options"]["show_template"] = kwargs.get("show_template", False) + project["options"]["use_nsf"] = kwargs.get("use_nsf", False) project["options"]["force"] = kwargs.get("force", False) project["options"]["output"] = kwargs.get("output", "") or "" @@ -130,7 +138,7 @@ def execute(self, params, **kwargs): project["options"]["project_name"] = "Discovery Playground" project["options"]["file_name"] = "" # project["options"]["dry_run"] = False # dry-run is allowed - extra = self.get_extra_args(["sample_data", "dry_run"], **kwargs) + extra = self.get_extra_args(["sample_data", "dry_run", "use_nsf"], **kwargs) if extra: logging.warning(f"{bcolors.WARNING}Warning: --sample-data|-s overrides other options {extra}{bcolors.ENDC}") @@ -222,6 +230,13 @@ def _has_perms(section_key): PAM_ROOT_FOLDER_NAME = "PAM Environments" + @staticmethod + def _pam_folder_types(use_nsf=False): + types = {BaseFolderNode.UserFolderType} + if use_nsf: + types.add(BaseFolderNode.NestedShareFolderType) + return types + def process_folders(self, params, project: dict) -> dict: res = { "root_folder_target": self.PAM_ROOT_FOLDER_NAME, @@ -243,10 +258,16 @@ def process_folders(self, params, project: dict) -> dict: # if project["data"].get("tool_version", "") != "": # CLI generated export else: # Manually generated import file # FolderListCommand().execute(params, folders_only=True, pattern="/") + use_nsf = project["options"].get("use_nsf", False) is True + allowed_types = self._pam_folder_types(use_nsf) folders = self.find_folders(params, "", res["root_folder_target"], False) if folders: # select first non-root non-shared sub/folder - folders = [x for x in folders if x.type == x.UserFolderType] + folders = [x for x in folders if x.type in allowed_types] + if use_nsf: + folders = [x for x in folders if is_nested_share_folder(params, x.uid)] + else: + folders = [x for x in folders if not is_nested_share_folder(params, x.uid)] if len(folders) > 1: logging.warning(f"""Multiple user folders ({len(folders)}) match folder name "{res["root_folder_target"]}" """ f" using first match with UID: {bcolors.OKGREEN}{folders[0].uid}{bcolors.ENDC}") @@ -256,7 +277,7 @@ def process_folders(self, params, project: dict) -> dict: res["root_folder_uid"] = str(folders[0].uid) elif project["options"].get("dry_run", False) is not True: # FolderMakeCommand().execute(params, user_folder=True, folder=f"""/{res["root_folder_target"]}""") - fuid = self.create_subfolder(params, res["root_folder_target"]) + fuid = self.create_subfolder(params, res["root_folder_target"], use_nsf=use_nsf) res["root_folder_uid"] = fuid # find available project folder - incr. numeric suffix until distinct name found @@ -267,14 +288,14 @@ def process_folders(self, params, project: dict) -> dict: while True: folder_name = res["project_folder_target"] if n <= START_INDEX else f"""{res["project_folder_target"]} #{n}""" folders = self.find_folders(params, res["root_folder_uid"], folder_name, False) - folders = [x for x in folders if x.type == x.UserFolderType] + folders = [x for x in folders if x.type in allowed_types] n += 1 if len(folders) > 0: continue res["project_folder"] = folder_name if project["options"].get("dry_run", False) is not True: # FolderMakeCommand().execute(params, shared_folder=True, folder=f"""/{res["root_folder"]}/{res["project_folder"]}""") - fuid = self.create_subfolder(params, folder_name=res["project_folder"], parent_uid=res["root_folder_uid"]) + fuid = self.create_subfolder(params, folder_name=res["project_folder"], parent_uid=res["root_folder_uid"], use_nsf=use_nsf) res["project_folder_uid"] = fuid puid = res["project_folder_uid"] @@ -282,14 +303,14 @@ def process_folders(self, params, project: dict) -> dict: fname = sfn["folder_name"] if isinstance(sfn, dict) and isinstance(sfn.get("folder_name", None), str) else "" fname = fname.strip() or f"""{res["project_folder"]} - Resources""" fperm, rperm = self.get_folder_permissions(users_folder=False, data=project["data"]) - fuid = self.create_subfolder(params, folder_name=fname, parent_uid=puid, permissions=fperm) + fuid = self.create_subfolder(params, folder_name=fname, parent_uid=puid, permissions=fperm, use_nsf=use_nsf) res["resources_folder_uid"] = fuid sfn = project["data"].get("shared_folder_users", None) fname = sfn["folder_name"] if isinstance(sfn, dict) and isinstance(sfn.get("folder_name", None), str) else "" fname = fname.strip() or f"""{res["project_folder"]} - Users""" fperm, uperm = self.get_folder_permissions(users_folder=True, data=project["data"]) - fuid = self.create_subfolder(params, folder_name=fname, parent_uid=puid, permissions=fperm) + fuid = self.create_subfolder(params, folder_name=fname, parent_uid=puid, permissions=fperm, use_nsf=use_nsf) res["users_folder_uid"] = fuid # add users and teams @@ -302,10 +323,14 @@ def process_folders(self, params, project: dict) -> dict: if res["root_folder_uid"]: print(f"""Will use existing PAM root folder: {res["root_folder_uid"]} {res["root_folder"]}""") else: - print(f"""Will create new PAM root folder: {res["root_folder_target"]}""") - print(f"""Will create new Project folder: {res["project_folder"]}""") + print(f"""Will create new {"NSF " if use_nsf else ""}PAM root folder: {res["root_folder_target"]}""") + print(f"""Will create new {"NSF " if use_nsf else ""}Project folder: {res["project_folder"]}""") else: - api.sync_down(params) + if use_nsf: + from .nsf_helpers import sync_down_preserving_nsf_keys + sync_down_preserving_nsf_keys(params) + else: + api.sync_down(params) return res @@ -342,8 +367,15 @@ def process_ksm_app(self, params, project: dict) -> dict: print(f"""Will create new KSM application: {res["app_name"]}""") return res - # Create KSM App + # Create KSM App and share Resources/Users folders (classic SF or NSF). + # KSMCommand routes NSF folder UIDs through grant_folder_access_to_application_v3. + use_nsf = project["options"].get("use_nsf", False) is True + from .nsf_helpers import restore_nsf_folder_keys, snapshot_nsf_folder_keys, sync_down_preserving_nsf_keys + preserved = snapshot_nsf_folder_keys(params) if use_nsf else None res["app_uid"] = self.create_ksm_app(params, res["app_name"]) + if preserved is not None: + # create_ksm_app sync_down clears NSF caches; restore before NSF secret share. + restore_nsf_folder_keys(params, preserved) for sf_uid in [project["folders"].get("resources_folder_uid", ""), project["folders"].get("users_folder_uid", "")]: if sf_uid.strip(): @@ -352,7 +384,13 @@ def process_ksm_app(self, params, project: dict) -> dict: app=res["app_uid"], secret=[sf_uid], editable=True) - api.sync_down(params) + if use_nsf or any(is_nested_share_folder(params, uid) + for uid in (project["folders"].get("resources_folder_uid", ""), + project["folders"].get("users_folder_uid", "")) + if uid): + sync_down_preserving_nsf_keys(params) + else: + api.sync_down(params) return res def process_gateway(self, params, project: dict) -> dict: @@ -383,6 +421,9 @@ def process_gateway(self, params, project: dict) -> dict: return res # Create new Gateway - PAMCreateGatewayCommand() + use_nsf = project["options"].get("use_nsf", False) is True + from .nsf_helpers import restore_nsf_folder_keys, snapshot_nsf_folder_keys, sync_down_preserving_nsf_keys + preserved = snapshot_nsf_folder_keys(params) if use_nsf else None output_fmt = project["options"]["output"] token_format = None if output_fmt == "token" else ("k8s" if output_fmt == "k8s" else "b64") ksm_app_uid = project["ksm_app"]["app_uid"] @@ -391,6 +432,8 @@ def process_gateway(self, params, project: dict) -> dict: gateway_name=res["gateway_name"], ksm_app=ksm_app_uid, config_init=token_format) + if preserved is not None: + restore_nsf_folder_keys(params, preserved) if token_format is None: res["gateway_token"] = gw[0].get("oneTimeToken", "") if gw else "" # OTT @@ -409,7 +452,10 @@ def process_gateway(self, params, project: dict) -> dict: res["gateway_uid"] = utils.base64_url_encode(gw_names[0]) if gw_names else "" # gateway_helper.remove_gateway(params, utils.base64_url_decode(res["gateway_uid"])) - api.sync_down(params) + if use_nsf: + sync_down_preserving_nsf_keys(params) + else: + api.sync_down(params) return res def process_pam_config(self, params, project: dict) -> dict: @@ -425,10 +471,18 @@ def process_pam_config(self, params, project: dict) -> dict: if not res["pam_config_name_target"]: res["pam_config_name_target"] = project["options"]["project_name"] + " Configuration" - # Find unique PAM Configuration name + # Find unique PAM Configuration name (classic record_cache + NSF caches) n = 1 pams = pam_configurations_get_all(params) - pam_names = [json.loads(x.get("data_unencrypted", "{}")).get("title", "") for x in pams] + pam_names = {json.loads(x.get("data_unencrypted", "{}")).get("title", "") for x in pams} + for uid, nsf_rec in (getattr(params, 'nested_share_records', None) or {}).items(): + if nsf_rec.get('version') != 6: + continue + dj = ((getattr(params, 'nested_share_record_data', None) or {}) + .get(uid, {}).get('data_json') or {}) + title = dj.get('title') or '' + if title: + pam_names.add(title) pam_name = res["pam_config_name_target"] while pam_name in pam_names: n += 1 @@ -530,7 +584,12 @@ def process_pam_config(self, params, project: dict) -> dict: if pce.default_rotation_schedule: args["default_schedule"] = pce.default_rotation_schedule res["pam_config_uid"] = PAMConfigurationNewCommand().execute(params, **args) - api.sync_down(params) + users_folder_uid = project["folders"].get("users_folder_uid", "") + if project["options"].get("use_nsf", False) is True or is_nested_share_folder(params, users_folder_uid): + from .nsf_helpers import sync_down_preserving_nsf_keys + sync_down_preserving_nsf_keys(params) + else: + api.sync_down(params) # add scripts and attachments after record create if pce.attachments: @@ -609,7 +668,17 @@ def generate_discovery_playground_data(self, params, project: dict): # Fix: Rotation is disabled by the PAM configuration. tdag.set_resource_allowed(pam_config_uid, is_config=True, rotation=True, connections=True, tunneling=True, session_recording=True, typescript_recording=True, remote_browser_isolation=True) - command = RecordAddCommand() + class PamProjectRecordAddCommand: + @staticmethod + def execute(params, **kwargs): + return execute_record_v3_add_in_folder( + params, + kwargs, + kwargs.get('folder'), + command='pam-project-import' + ) + + command = PamProjectRecordAddCommand() pte = PAMTunnelEditCommand() # when NOOP rotation is added to PAMCreateRecordRotationCommand... @@ -1197,6 +1266,11 @@ def get_folder_permissions(self, users_folder: bool, data: dict): def add_folder_permissions(self, params, folder_uid: str, permissions: list): if permissions: + if is_nested_share_folder(params, folder_uid): + grant_pam_folder_permissions(params, folder_uid, permissions, command='pam-project-import') + api.sync_down(params) + return + shf = SharedFolder() shf.uid = folder_uid # type: ignore shf.path = imp_exp.get_folder_path(params, folder_uid) # type: ignore @@ -1232,7 +1306,8 @@ def add_folder_permissions(self, params, folder_uid: str, permissions: list): # args["manage_users"] = True if manage_users == False else False # ShareFolderCommand().execute(params, **args) - def create_subfolder(self, params, folder_name:str, parent_uid:str="", permissions:Optional[Dict]=None): + def create_subfolder(self, params, folder_name:str, parent_uid:str="", permissions:Optional[Dict]=None, + use_nsf: bool=False): """ Creates subfolder inside parent folder: either `user folder`, `shared folder` or `shared folder folder`. If `parent_uid == ""` then creates subfolder in root folder. @@ -1243,6 +1318,21 @@ def create_subfolder(self, params, folder_name:str, parent_uid:str="", permissio """ name = str(folder_name or "").strip() + if use_nsf or is_nested_share_folder(params, parent_uid): + from .nsf_helpers import seed_nsf_folder_cache, sync_down_preserving_nsf_keys + from ...nested_share_folder.folder_api import create_folder_v3 + result = create_folder_v3(params, name, parent_uid=parent_uid or None) + if isinstance(result, dict) and result.get('success') is False: + raise CommandError("pam", result.get('message') or 'Failed to create Nested Share Folder') + folder_uid = result.get('folder_uid') if isinstance(result, dict) else None + if not folder_uid: + raise CommandError("pam", f'Nested Share Folder creation did not return UID: {name}') + folder_key = result.get('folder_key_unencrypted') if isinstance(result, dict) else None + seed_nsf_folder_cache(params, folder_uid, name, parent_uid or None, folder_key) + sync_down_preserving_nsf_keys(params) + params.environment_variables[LAST_FOLDER_UID] = folder_uid + return folder_uid + base_folder = params.folder_cache.get(parent_uid, None) or params.root_folder shared_folder = True if permissions else False @@ -1314,6 +1404,15 @@ def find_folders(self, params, parent_uid:str, folder:str, is_shared_folder:bool result = [v for k, v in matches.items() if (is_shared_folder and v.type == BaseFolderNode.SharedFolderType) or (not is_shared_folder and v.type == BaseFolderNode.UserFolderType)] + if not is_shared_folder: + for uid, nsf in getattr(params, 'nested_share_folders', {}).items(): + nsf_parent = nsf.get('parent_uid') or None + if nsf_parent == puid and nsf.get('name') == folder: + nsf_folder = NestedShareFolderNode() + nsf_folder.uid = uid + nsf_folder.name = nsf.get('name') + nsf_folder.parent_uid = nsf_parent + result.append(nsf_folder) return result def create_ksm_app(self, params, app_name) -> str: @@ -1814,8 +1913,9 @@ def process_data(self, params, project): # PAM Domain Config - update domain admin creds if pce and pce.environment == "domain": if pce.admin_credential_ref: + from .record_loader import load_pam_record pcuid = project["pam_config"].get("pam_config_uid") - pcrec = vault.KeeperRecord.load(params, pcuid) if pcuid else None + pcrec = load_pam_record(params, pcuid) if pcuid else None if pcrec and isinstance(pcrec, vault.TypedRecord) and pcrec.version == 6: if pcrec.record_type == "pamDomainConfiguration": prf = pcrec.get_typed_field('pamResources') @@ -1825,7 +1925,17 @@ def process_data(self, params, project): prf.value = prf.value or [{}] if isinstance(prf.value[0], dict): prf.value[0]["adminCredentialRef"] = pce.admin_credential_ref - record_management.update_record(params, pcrec) + users_folder_uid = (project.get("folders") or {}).get("users_folder_uid", "") + force_nsf = ( + project["options"].get("use_nsf", False) is True + or is_nested_share_folder(params, users_folder_uid) + or is_pam_nsf_record(params, pcuid) + ) + if force_nsf: + update_pam_record( + params, pcrec, command='pam-project-import', force_nsf=True) + else: + record_management.update_record(params, pcrec) tdag.link_user_to_config_with_options(pce.admin_credential_ref, is_admin='on') else: logging.error(f"Unable to add adminCredentialRef - bad pamResources field in PAM Config {pcuid}") diff --git a/keepercommander/commands/pam_import/export.py b/keepercommander/commands/pam_import/export.py index 1effb4ee3..d847797ee 100644 --- a/keepercommander/commands/pam_import/export.py +++ b/keepercommander/commands/pam_import/export.py @@ -21,6 +21,7 @@ ) from ..base import Command from ..pam.config_facades import PamConfigurationRecordFacade +from .record_loader import iter_accessible_record_uids, load_pam_record from ... import vault from ...display import bcolors @@ -79,7 +80,7 @@ def execute(self, params, **kwargs): return # 1. Load PAM configuration record (v6) - config_record = vault.KeeperRecord.load(params, project_uid) + config_record = load_pam_record(params, project_uid) if not config_record: logging.warning( f"{bcolors.FAIL}PAM configuration '{project_uid}' not found in vault{bcolors.ENDC}" @@ -203,7 +204,7 @@ def _build_resources_and_users(self, params, resource_uids): title_to_uid = self._build_user_title_index(params) for res_uid in resource_uids: - res_record = vault.KeeperRecord.load(params, res_uid) + res_record = load_pam_record(params, res_uid) if not res_record or not isinstance(res_record, vault.TypedRecord): logging.debug("Export: skipping resource UID %s (not found or not TypedRecord)", res_uid) continue @@ -251,10 +252,9 @@ def _build_resources_and_users(self, params, resource_uids): def _build_user_title_index(self, params): """Index every pamUser / login record by lowercased title for title-based linking.""" index = {} - record_cache = getattr(params, "record_cache", {}) or {} - for uid in record_cache: + for uid in iter_accessible_record_uids(params): try: - rec = vault.KeeperRecord.load(params, uid) + rec = load_pam_record(params, uid) except Exception: continue if not rec or not isinstance(rec, vault.TypedRecord): @@ -302,7 +302,7 @@ def _extract_user_uids(self, pam_settings_dict, title_to_uid=None): def _load_user_obj(self, params, usr_uid): """Load a pamUser/login record and return a plain dict, or None on failure.""" - usr_record = vault.KeeperRecord.load(params, usr_uid) + usr_record = load_pam_record(params, usr_uid) if not usr_record or not isinstance(usr_record, vault.TypedRecord): logging.debug("Export: user UID %s not found or not TypedRecord", usr_uid) return None diff --git a/keepercommander/commands/pam_import/extend.py b/keepercommander/commands/pam_import/extend.py index c21a2a6f2..b0a10b175 100644 --- a/keepercommander/commands/pam_import/extend.py +++ b/keepercommander/commands/pam_import/extend.py @@ -54,23 +54,34 @@ refresh_link_to_config_to_latest, ) from .workflow_apply import apply_workflow, validate_workflow_principals +from .nsf_helpers import ( + build_folder_tree, + create_nsf_subfolder, + extend_create_record, + find_pam_configuration, + get_folder_record_uids, + get_ksm_app_folders, + get_records_in_folder, +) +from .record_loader import load_pam_record from ...keeper_dag import EdgeType from ...keeper_dag.types import RefType from ..base import Command from ..ksm import KSMCommand from ..pam import gateway_helper from ..pam.config_helper import configuration_controller_get +from ..pam.vault_target import is_nested_share_folder, is_pam_nsf_record, update_pam_record from ..tunnel.port_forward.TunnelGraph import TunnelDAG from ..tunnel.port_forward.tunnel_helpers import get_keeper_tokens from ..tunnel_and_connections import PAMTunnelEditCommand -from ... import api, crypto, utils, vault, vault_extensions, record_management +from ... import api, crypto, utils, vault, record_management from ... import enterprise as _enterprise_module from ...display import bcolors from ...error import CommandError from ...params import LAST_FOLDER_UID, LAST_SHARED_FOLDER_UID -from ...proto import APIRequest_pb2, enterprise_pb2, pam_pb2, record_pb2 +from ...proto import enterprise_pb2, pam_pb2, record_pb2 from ...recordv3 import RecordV3 -from ...subfolder import BaseFolderNode +from ...subfolder import BaseFolderNode, find_folders as find_record_folders def split_folder_path(path: str) -> list[str]: """Split folder path using path deilmiter / (escape: / -> //)""" @@ -191,23 +202,8 @@ def process_folder_paths(folder_paths, ksm_shared_folders): return good_paths, bad_paths def build_tree_recursive(params, folder_uid: str): - """Recursively build tree for a folder and its subfolders""" - tree = {} - folder = params.folder_cache.get(folder_uid) - if not folder: - return tree - - for subfolder_uid in folder.subfolders: - subfolder = params.folder_cache.get(subfolder_uid) - if subfolder: - folder_name = subfolder.name or '' - tree[folder_name] = { - 'uid': subfolder.uid, - 'name': folder_name, - 'subfolders': build_tree_recursive(params, subfolder.uid) - } - - return tree + """Recursively build tree for a folder and its subfolders (classic or NSF).""" + return build_folder_tree(params, folder_uid) def _collect_path_to_uid_from_tree(path_prefix: str, tree: dict, path_to_uid: dict, only_existing: bool) -> None: @@ -295,35 +291,14 @@ def _get_ksm_app_record_uids(params, ksm_shared_folders: list) -> set: """Return set of all record UIDs in any folder shared to the KSM app.""" folder_uids = _collect_all_folder_uids_under_ksm(ksm_shared_folders) record_uids = set() - subfolder_record_cache = getattr(params, "subfolder_record_cache", None) or {} for fuid in folder_uids: - if fuid in subfolder_record_cache: - record_uids.update(subfolder_record_cache[fuid]) + record_uids.update(get_folder_record_uids(params, fuid)) return record_uids def _get_records_in_folder(params, folder_uid: str): - """Return list of (record_uid, title, record_type, login) for records in folder_uid. - record_type from record for autodetect (e.g. pamUser, pamMachine, login).""" - subfolder_record_cache = getattr(params, "subfolder_record_cache", None) or {} - result = [] - for ruid in subfolder_record_cache.get(folder_uid, []): - try: - rec = vault.KeeperRecord.load(params, ruid) - title = getattr(rec, "title", "") or "" - rtype = "" - if hasattr(rec, "record_type"): - rtype = getattr(rec, "record_type", "") or "" - login = "" - fields = getattr(rec, "fields", None) - if isinstance(fields, list): - field = next((x for x in fields if getattr(x, "type", "") == "login"), None) - if field and hasattr(field, "get_default_value"): - login = (field.get_default_value() or "") or "" - result.append((ruid, title, rtype, login)) - except Exception: - pass - return result + """Return list of (record_uid, title, record_type, login) for records in folder_uid.""" + return get_records_in_folder(params, folder_uid) def _get_all_ksm_app_records(params, ksm_shared_folders: list) -> list: @@ -415,15 +390,7 @@ def execute(self, params, **kwargs): # no need to populate params.enterprise (users/teams caches). # since extend only adds new records to existing folders - configuration = None - if config_name in params.record_cache: - configuration = vault.KeeperRecord.load(params, config_name) - else: - l_name = config_name.casefold() - for c in vault_extensions.find_records(params, record_version=6): - if c.title.casefold() == l_name: - configuration = c - break + configuration = find_pam_configuration(params, config_name) if not (configuration and isinstance(configuration, vault.TypedRecord) and configuration.version == 6): raise CommandError("pam project extend", f"""PAM configuration not found: "{config_name}" """) @@ -478,7 +445,7 @@ def execute(self, params, **kwargs): raise CommandError("pam project extend", f"""PAM KSM Application record not found: "{ksmapp_uid}" """) # Find KSM Application shared folders - ksm_shared_folders = self.get_app_shared_folders(params, ksmapp_uid) + ksm_shared_folders = self.get_app_shared_folders(params, ksmapp_uid, configuration.record_uid) if not ksm_shared_folders: raise CommandError("pam project extend", f""" No shared folders found for KSM Application: "{ksmapp_uid}" """) @@ -559,32 +526,53 @@ def execute(self, params, **kwargs): return self.process_data(params, project) - def get_app_shared_folders(self, params, ksm_app_uid: str) -> list[dict]: - ksm_shared_folders = [] - - try: - app_info_list = KSMCommand.get_app_info(params, ksm_app_uid) - if app_info_list and len(app_info_list) > 0: - app_info = app_info_list[0] - shares = [x for x in app_info.shares if x.shareType == APIRequest_pb2.SHARE_TYPE_FOLDER] # pylint: disable=no-member - for share in shares: - folder_uid = utils.base64_url_encode(share.secretUid) - if folder_uid in params.shared_folder_cache: - cached_sf = params.shared_folder_cache[folder_uid] - folder_name = cached_sf.get('name_unencrypted', 'Unknown') - is_editable = share.editable if hasattr(share, 'editable') else False - - ksm_shared_folders.append({ - 'uid': folder_uid, - 'name': folder_name, - 'editable': is_editable, - 'permissions': "Editable" if is_editable else "Read-Only" - }) - except Exception as e: - logging.error(f"Could not retrieve KSM application shares: {e}") - + def get_app_shared_folders(self, params, ksm_app_uid: str, configuration_uid: Optional[str]=None) -> list[dict]: + ksm_shared_folders = get_ksm_app_folders(params, ksm_app_uid) + if not ksm_shared_folders and configuration_uid: + ksm_shared_folders.extend(self.get_nsf_project_folders(params, configuration_uid)) return ksm_shared_folders + @staticmethod + def get_nsf_project_folders(params, configuration_uid: str) -> list[dict]: + folder_uids = [] + for folder_uid in find_record_folders(params, configuration_uid): + if folder_uid and is_nested_share_folder(params, folder_uid): + folder_uids.append(folder_uid) + + if not folder_uids: + return [] + + project_folder_uids = [] + for folder_uid in folder_uids: + folder = params.folder_cache.get(folder_uid) + if not folder: + continue + parent_uid = folder.parent_uid + if parent_uid: + for uid, candidate in params.folder_cache.items(): + if candidate.parent_uid == parent_uid and is_nested_share_folder(params, uid): + project_folder_uids.append(uid) + else: + project_folder_uids.append(folder_uid) + + result = [] + seen = set() + for folder_uid in project_folder_uids: + if folder_uid in seen: + continue + seen.add(folder_uid) + folder = params.folder_cache.get(folder_uid) + if not folder: + continue + result.append({ + 'uid': folder_uid, + 'name': folder.name or folder_uid, + 'editable': True, + 'permissions': 'Editable', + 'source': 'nested_share_folder', + }) + return result + def process_folders(self, params, project: dict) -> dict: """Step 1: Parse folder_paths from pam_data, build tree, process paths, optionally create new folders. Fills project['folders'] with path_to_folder_uid, good_paths, bad_paths; updates project['error_count'].""" @@ -1103,7 +1091,6 @@ def autodetect_folders(self, params, project: dict) -> list: step3_errors = [] folders_out = project.get("folders") or {} ksm_shared_folders = project.get("ksm_shared_folders") or [] - subfolder_record_cache = getattr(params, "subfolder_record_cache", None) or {} new_no_path = [] for o in chain(project.get("mapped_resources", []), project.get("mapped_users", [])): @@ -1137,7 +1124,7 @@ def autodetect_folders(self, params, project: dict) -> list: non_empty = [] for shf in ksm_shared_folders: uids = _folder_uids_under_shf(shf) - if any(subfolder_record_cache.get(fuid) for fuid in uids): + if any(get_folder_record_uids(params, fuid) for fuid in uids): non_empty.append(shf) if len(non_empty) == 0: step3_errors.append("Autodetect: no folders contain records; cannot assign resources/users folders.") @@ -1189,6 +1176,20 @@ def create_subfolder(self, params, folder_name:str, parent_uid:str="", permissio # folder_uid: if provided, create folder with this UID (same as records with pre-generated uid). name = str(folder_name or "").strip() + if is_nested_share_folder(params, parent_uid): + if folder_uid: + return create_nsf_subfolder(params, name, parent_uid, folder_uid=folder_uid) + from ...nested_share_folder.folder_api import create_folder_v3 + result = create_folder_v3(params, name, parent_uid=parent_uid) + if isinstance(result, dict) and result.get('success') is False: + raise CommandError("pam project extend", result.get('message') or 'Failed to create Nested Share Folder') + new_uid = result.get('folder_uid') if isinstance(result, dict) else None + if not new_uid: + raise CommandError("pam project extend", f'Nested Share Folder creation did not return UID: {name}') + api.sync_down(params) + params.environment_variables[LAST_FOLDER_UID] = new_uid + return new_uid + base_folder = params.folder_cache.get(parent_uid, None) or params.root_folder shared_folder = True if permissions else False @@ -1255,6 +1256,18 @@ def find_folders(self, params, parent_uid:str, folder:str, is_shared_folder:bool result = [v for k, v in matches.items() if (is_shared_folder and v.type == BaseFolderNode.SharedFolderType) or (not is_shared_folder and v.type == BaseFolderNode.UserFolderType)] + if not is_shared_folder: + for uid, nsf in getattr(params, 'nested_share_folders', {}).items(): + nsf_parent = nsf.get('parent_uid') or None + if nsf_parent == puid and nsf.get('name') == folder: + result.append(SimpleNamespace( + uid=uid, + name=nsf.get('name'), + parent_uid=nsf_parent, + type=BaseFolderNode.UserFolderType, + UserFolderType=BaseFolderNode.UserFolderType, + SharedFolderType=BaseFolderNode.SharedFolderType, + )) return result def create_ksm_app(self, params, app_name) -> str: @@ -1382,7 +1395,7 @@ def process_data(self, params, project): logging.warning(f"Processing external users: {len(new_users)}") for n, user in enumerate(new_users): folder_uid = getattr(user, "resolved_folder_uid", None) or shfusr - user.create_record(params, folder_uid) + extend_create_record(params, user, folder_uid) if n % pdelta == 0: print(f"{n}/{len(new_users)}") print(f"{len(new_users)}/{len(new_users)}\n") @@ -1397,7 +1410,7 @@ def process_data(self, params, project): print(f"{n}/{len(new_resources)}") folder_uid = getattr(mach, "resolved_folder_uid", None) or shfres admin_uid = get_admin_credential(mach, True) - mach.create_record(params, folder_uid) + extend_create_record(params, mach, folder_uid) tdag.link_resource_to_config(mach.uid) if isinstance(mach, PamRemoteBrowserObject): args = parse_command_options(mach, True) @@ -1464,7 +1477,7 @@ def process_data(self, params, project): if isinstance(user, PamUserObject) and rs and (getattr(rs, "rotation", "") or "").lower() == "general": rs.resourceUid = mach.uid ufolder = getattr(user, "resolved_folder_uid", None) or shfusr - user.create_record(params, ufolder) + extend_create_record(params, user, ufolder) if isinstance(user, PamUserObject): tdag.link_user_to_resource(user.uid, mach.uid, admin_uid == user.uid, True) if rs: @@ -1499,7 +1512,7 @@ def process_data(self, params, project): if isinstance(user, PamUserObject) and rs and (getattr(rs, "rotation", "") or "").lower() == "general": rs.resourceUid = mach.uid ufolder = getattr(user, "resolved_folder_uid", None) or shfusr - user.create_record(params, ufolder) + extend_create_record(params, user, ufolder) if isinstance(user, PamUserObject): tdag.link_user_to_resource(user.uid, mach.uid, admin_uid == user.uid, True) if rs: @@ -1545,7 +1558,7 @@ def process_data(self, params, project): if pce and getattr(pce, "environment", "") == "domain": if getattr(pce, "admin_credential_ref", None): pcuid = (project.get("pam_config") or {}).get("pam_config_uid") - pcrec = vault.KeeperRecord.load(params, pcuid) if pcuid else None + pcrec = load_pam_record(params, pcuid) if pcuid else None if pcrec and isinstance(pcrec, vault.TypedRecord) and pcrec.version == 6: if pcrec.record_type == "pamDomainConfiguration": prf = pcrec.get_typed_field("pamResources") @@ -1555,7 +1568,18 @@ def process_data(self, params, project): prf.value = prf.value or [{}] if isinstance(prf.value[0], dict): prf.value[0]["adminCredentialRef"] = pce.admin_credential_ref - record_management.update_record(params, pcrec) + # NSF PAM configs live under NSF folders; classic still use record_management. + force_nsf = is_pam_nsf_record(params, pcuid) + if not force_nsf: + for folder_uid in find_record_folders(params, pcuid): + if is_nested_share_folder(params, folder_uid): + force_nsf = True + break + if force_nsf: + update_pam_record( + params, pcrec, command='pam-project-extend', force_nsf=True) + else: + record_management.update_record(params, pcrec) tdag.link_user_to_config_with_options(pce.admin_credential_ref, is_admin="on") else: logging.error(f"Unable to add adminCredentialRef - bad pamResources field in PAM Config {pcuid}") @@ -1569,4 +1593,3 @@ def process_data(self, params, project): add_pam_scripts(params, pam_cfg_uid, refs) logging.debug("Done processing project data.") return - diff --git a/keepercommander/commands/pam_import/nsf_helpers.py b/keepercommander/commands/pam_import/nsf_helpers.py new file mode 100644 index 000000000..48963cf58 --- /dev/null +++ b/keepercommander/commands/pam_import/nsf_helpers.py @@ -0,0 +1,311 @@ +# _ __ +# | |/ /___ ___ _ __ ___ _ _ ® +# | ' bool: + """Return True when *folder_uid* is a Nested Shared Folder.""" + if not folder_uid: + return False + nsf_folders = getattr(params, 'nested_share_folders', None) or {} + if folder_uid in nsf_folders: + return True + subfolder = (getattr(params, 'subfolder_cache', None) or {}).get(folder_uid) or {} + return subfolder.get('source') == 'nested_share_folder' + + +def find_pam_configuration(params, config_name: str) -> Optional[vault.TypedRecord]: + """Resolve a PAM configuration record by UID or title (classic + NSF).""" + config_name = (config_name or '').strip() + if not config_name: + return None + + rec = load_pam_record(params, config_name) + if rec and isinstance(rec, vault.TypedRecord) and rec.version == 6: + return rec + + l_name = config_name.casefold() + for uid in iter_accessible_record_uids(params): + if uid == config_name: + continue + rec = load_pam_record(params, uid) + if not rec or not isinstance(rec, vault.TypedRecord) or rec.version != 6: + continue + if rec.title and rec.title.casefold() == l_name: + return rec + return None + + +def get_ksm_app_folders(params, ksm_app_uid: str) -> List[dict]: + """Return KSM-application folder roots (classic shared folders and NSF).""" + from ..ksm import KSMCommand + from ... import utils as keeper_utils + from ...proto import APIRequest_pb2 + + folders = [] + try: + app_info_list = KSMCommand.get_app_info(params, ksm_app_uid) + if not app_info_list: + return folders + app_info = app_info_list[0] + shares = [x for x in app_info.shares if x.shareType == APIRequest_pb2.SHARE_TYPE_FOLDER] # pylint: disable=no-member + for share in shares: + folder_uid = keeper_utils.base64_url_encode(share.secretUid) + is_editable = share.editable if hasattr(share, 'editable') else False + entry = _folder_entry_for_uid(params, folder_uid, is_editable) + if entry: + folders.append(entry) + except Exception as exc: + logging.error('Could not retrieve KSM application shares: %s', exc) + return folders + + +def _folder_entry_for_uid(params, folder_uid: str, is_editable: bool) -> Optional[dict]: + if folder_uid in getattr(params, 'shared_folder_cache', {}): + cached_sf = params.shared_folder_cache[folder_uid] + return { + 'uid': folder_uid, + 'name': cached_sf.get('name_unencrypted', 'Unknown'), + 'editable': is_editable, + 'permissions': 'Editable' if is_editable else 'Read-Only', + 'source': 'classic', + } + nsf_folders = getattr(params, 'nested_share_folders', None) or {} + if folder_uid in nsf_folders: + return { + 'uid': folder_uid, + 'name': nsf_folders[folder_uid].get('name', 'Unknown'), + 'editable': is_editable, + 'permissions': 'Editable' if is_editable else 'Read-Only', + 'source': 'nested', + } + return None + + +def build_folder_tree(params, folder_uid: str) -> dict: + """Build a nested folder tree under *folder_uid* (classic or NSF).""" + if is_nsf_folder_uid(params, folder_uid): + return _build_nsf_folder_tree(params, folder_uid) + return _build_classic_folder_tree(params, folder_uid) + + +def _build_classic_folder_tree(params, folder_uid: str) -> dict: + tree = {} + folder = params.folder_cache.get(folder_uid) + if not folder: + return tree + for subfolder_uid in folder.subfolders: + subfolder = params.folder_cache.get(subfolder_uid) + if not subfolder: + continue + folder_name = subfolder.name or '' + tree[folder_name] = { + 'uid': subfolder.uid, + 'name': folder_name, + 'subfolders': _build_classic_folder_tree(params, subfolder.uid), + } + return tree + + +def _build_nsf_folder_tree(params, root_uid: str) -> dict: + nsf_folders = getattr(params, 'nested_share_folders', None) or {} + + def children_of(parent_uid: str) -> dict: + kids = {} + for fuid, finfo in nsf_folders.items(): + raw_parent = finfo.get('parent_uid') or '' + if raw_parent != parent_uid: + continue + name = finfo.get('name') or fuid + kids[name] = { + 'uid': fuid, + 'name': name, + 'subfolders': children_of(fuid), + } + return kids + + return children_of(root_uid) + + +def get_folder_record_uids(params, folder_uid: str) -> set: + """Return record UIDs directly associated with a folder.""" + record_uids = set() + subfolder_record_cache = getattr(params, 'subfolder_record_cache', None) or {} + nsf_folder_records = getattr(params, 'nested_share_folder_records', None) or {} + if folder_uid in subfolder_record_cache: + record_uids.update(subfolder_record_cache[folder_uid]) + if folder_uid in nsf_folder_records: + record_uids.update(nsf_folder_records[folder_uid]) + return record_uids + + +def get_records_in_folder(params, folder_uid: str) -> list: + """Return (uid, title, record_type, login) tuples for records in *folder_uid*.""" + result = [] + for ruid in get_folder_record_uids(params, folder_uid): + try: + rec = load_pam_record(params, ruid) + if not rec: + continue + title = getattr(rec, 'title', '') or '' + rtype = getattr(rec, 'record_type', '') or '' + login = '' + fields = getattr(rec, 'fields', None) + if isinstance(fields, list): + field = next((x for x in fields if getattr(x, 'type', '') == 'login'), None) + if field and hasattr(field, 'get_default_value'): + login = (field.get_default_value() or '') or '' + result.append((ruid, title, rtype, login)) + except Exception: + continue + return result + + +def snapshot_nsf_folder_keys(params) -> dict: + out = {} + for uid, info in (getattr(params, 'nested_share_folders', None) or {}).items(): + key = info.get('folder_key_unencrypted') if isinstance(info, dict) else None + if not key: + continue + out[uid] = { + 'name': info.get('name') or uid, + 'parent_uid': info.get('parent_uid'), + 'folder_key_unencrypted': key, + } + return out + + +def restore_nsf_folder_keys(params, snapshot: Optional[dict]) -> None: + for uid, info in (snapshot or {}).items(): + seed_nsf_folder_cache( + params, + uid, + info.get('name') or uid, + info.get('parent_uid'), + info.get('folder_key_unencrypted'), + ) + + +def sync_down_preserving_nsf_keys(params) -> None: + preserved = snapshot_nsf_folder_keys(params) + api.sync_down(params) + restore_nsf_folder_keys(params, preserved) + + +def seed_nsf_folder_cache(params, folder_uid: str, name: str, + parent_uid: Optional[str] = None, + folder_key: Optional[bytes] = None) -> None: + """Keep local NSF caches consistent right after folder creation. + """ + if not folder_uid: + return + + normalized_parent = parent_uid or None + nsf = getattr(params, 'nested_share_folders', None) + if nsf is None: + params.nested_share_folders = {} + nsf = params.nested_share_folders + entry = dict(nsf.get(folder_uid) or {}) + entry['name'] = name + entry['parent_uid'] = normalized_parent + if folder_key: + entry['folder_key_unencrypted'] = folder_key + nsf[folder_uid] = entry + + subfolder_cache = getattr(params, 'subfolder_cache', None) + if subfolder_cache is None: + params.subfolder_cache = {} + subfolder_cache = params.subfolder_cache + sf_entry = dict(subfolder_cache.get(folder_uid) or {}) + sf_entry.update({ + 'folder_uid': folder_uid, + 'type': 'user_folder', + 'name': name, + 'parent_uid': normalized_parent, + 'source': 'nested_share_folder', + }) + if folder_key: + sf_entry['folder_key_unencrypted'] = folder_key + subfolder_cache[folder_uid] = sf_entry + + # Folder nodes used by find_folders / NSF project discovery. + from ...subfolder import NestedShareFolderNode + folder_cache = getattr(params, 'folder_cache', None) + if isinstance(folder_cache, dict): + node = folder_cache.get(folder_uid) + if not isinstance(node, NestedShareFolderNode): + node = NestedShareFolderNode() + node.uid = folder_uid + node.subfolders = [] + folder_cache[folder_uid] = node + node.name = name + node.parent_uid = normalized_parent + if normalized_parent and normalized_parent in folder_cache: + parent = folder_cache[normalized_parent] + kids = getattr(parent, 'subfolders', None) + if kids is None: + parent.subfolders = [folder_uid] + elif folder_uid not in kids: + kids.append(folder_uid) + + env = getattr(params, 'environment_variables', None) + if isinstance(env, dict): + env['last_folder_uid'] = folder_uid + + +def create_nsf_subfolder(params, folder_name: str, parent_uid: str = '', + folder_uid: Optional[str] = None) -> str: + """Create an NSF subfolder; returns folder UID.""" + from ...nested_share_folder.folder_api import _prepare_folder_for_creation, folder_add_v3 + from ..nested_share_folder.helpers import command_error_handler, check_result + from ...proto import folder_pb2 + + name = str(folder_name or '').strip() + if not name: + raise CommandError('pam project extend', 'NSF subfolder name is required') + if not folder_uid: + folder_uid = api.generate_record_uid() + + parent = parent_uid or None + if parent: + nsf_folders = getattr(params, 'nested_share_folders', None) or {} + folder_cache = getattr(params, 'folder_cache', None) or {} + if parent not in nsf_folders and parent not in folder_cache: + raise CommandError('pam project extend', f'Parent folder "{parent_uid}" not found') + + with command_error_handler('pam project extend'): + fd, folder_key = _prepare_folder_for_creation( + params, folder_uid, name, parent, None, True, + ) + response = folder_add_v3(params, [fd]) + if not response.folderAddResults: + raise CommandError('pam project extend', 'No results from NSF folder creation') + r = response.folderAddResults[0] + check_result({ + 'success': r.status == folder_pb2.SUCCESS, + 'message': r.message, + }, 'pam project extend') + + seed_nsf_folder_cache(params, folder_uid, name, parent_uid, folder_key) + return folder_uid + + +def extend_create_record(params, obj, folder_uid: str) -> Optional[str]: + """Create a PAM import record in a classic or NSF folder.""" + return obj.create_record(params, folder_uid) diff --git a/keepercommander/commands/pam_import/record_loader.py b/keepercommander/commands/pam_import/record_loader.py new file mode 100644 index 000000000..306614798 --- /dev/null +++ b/keepercommander/commands/pam_import/record_loader.py @@ -0,0 +1,67 @@ +# _ __ +# | |/ /___ ___ _ __ ___ _ _ ® +# | ' Iterator[str]: + """Yield record UIDs from classic and Nested Shared Folder caches.""" + seen = set() + for attr in ('record_cache', 'nested_share_records'): + cache = getattr(params, attr, None) or {} + for uid in cache: + if uid not in seen: + seen.add(uid) + yield uid + + nsf_record_data = getattr(params, 'nested_share_record_data', None) or {} + for uid in nsf_record_data: + if uid not in seen: + seen.add(uid) + yield uid + + +def load_pam_record(params, record_uid: str) -> Optional[vault.KeeperRecord]: + """Load a vault record from classic cache, NSF cache, or NSF record data.""" + record_uid = (record_uid or '').strip() + if not record_uid: + return None + + cached = get_record_from_cache(params, record_uid) + if cached and cached.get('data_unencrypted'): + rec = vault.KeeperRecord.load(params, cached) + if rec: + return rec + + rec = vault.KeeperRecord.load(params, record_uid) + if rec: + return rec + + nsf_record_data = getattr(params, 'nested_share_record_data', None) or {} + nsf_records = getattr(params, 'nested_share_records', None) or {} + rd = nsf_record_data.get(record_uid) or {} + if 'data_json' not in rd: + return None + + dj = rd['data_json'] + version = nsf_records.get(record_uid, {}).get('version', 3) + if version not in (3, 6): + return None + + keeper_record = vault.TypedRecord(version=version) + keeper_record.record_uid = record_uid + keeper_record.load_record_data(dj, None) + return keeper_record diff --git a/keepercommander/commands/tunnel_and_connections.py b/keepercommander/commands/tunnel_and_connections.py index 65aaecd84..2b478e83e 100644 --- a/keepercommander/commands/tunnel_and_connections.py +++ b/keepercommander/commands/tunnel_and_connections.py @@ -36,6 +36,7 @@ wait_for_tunnel_connection, create_rust_webrtc_settings, \ print_above_keeper_prompt from .pam.router_helper import get_dag_leafs +from .pam.vault_target import update_pam_record from .tunnel_registry import ( PARENT_GRACE_SECONDS, is_pid_alive, @@ -431,8 +432,7 @@ def execute(self, params, **kwargs): record.custom.append(record_seed) dirty = True if dirty: - record_management.update_record(params, record) - api.sync_down(params) + update_pam_record(params, record, command='pam tunnel edit') traffic_encryption_key = record.get_typed_field('trafficEncryptionSeed') if not traffic_encryption_key: @@ -504,8 +504,7 @@ def execute(self, params, **kwargs): dirty = True # Persist the record changes (new pamSettings field or port modifications) if dirty: - record_management.update_record(params, record) - api.sync_down(params) + update_pam_record(params, record, command='pam tunnel edit') dirty = False if not tmp_dag.is_tunneling_config_set_up(record_uid): print(f"{bcolors.FAIL}No PAM Configuration UID set. This must be set for tunneling to work. " @@ -555,8 +554,7 @@ def execute(self, params, **kwargs): if dirty: tmp_dag.set_resource_allowed(resource_uid=record_uid, tunneling=_tunneling, allowed_settings_name=allowed_settings_name) - record_management.update_record(params, record) - api.sync_down(params) + update_pam_record(params, record, command='pam tunnel edit') # Print out the tunnel settings if not kwargs.get('silent'): @@ -4172,7 +4170,10 @@ def execute(self, params, **kwargs): print(f"{bcolors.FAIL}Please provide a valid PAM Configuration.{bcolors.ENDC}") return - folder_uid = resolve_folder(params, folder) + folder_uid = '' + if folder: + from .pam.vault_target import resolve_pam_folder_uid + folder_uid = resolve_pam_folder_uid(params, folder, allow_legacy_user=True) or resolve_folder(params, folder) if folder and not folder_uid: print(f"{bcolors.WARNING}Unable to find destination folder '{folder}' " "(Note: folder names/paths are case sensitive) " @@ -4243,7 +4244,8 @@ def execute(self, params, **kwargs): f"and PAM User record will be created in folder '{folders[0]}'.{bcolors.ENDC}") folder_uid = folders[0] if folders else '' # '' means root folder - record_management.add_record_to_folder(params, user_rec, folder_uid) + from .pam.vault_target import create_record_in_folder + create_record_in_folder(params, user_rec, folder_uid, command='pam-split') pam_user_uid = params.environment_variables.get(LAST_RECORD_UID, '') api.sync_down(params) diff --git a/keepercommander/nested_share_folder/__init__.py b/keepercommander/nested_share_folder/__init__.py index 8436b6ba1..1feda6a61 100644 --- a/keepercommander/nested_share_folder/__init__.py +++ b/keepercommander/nested_share_folder/__init__.py @@ -30,6 +30,9 @@ 'create_folder_data', 'encrypt_folder_key', 'folder_add_v3', 'create_folder_v3', 'create_folders_batch_v3', 'folder_access_update_v3', 'grant_folder_access_v3', + 'grant_folder_access_to_application_v3', + 'update_folder_access_to_application_v3', + 'revoke_folder_access_from_application_v3', 'update_folder_access_v3', 'revoke_folder_access_v3', 'manage_folder_access_batch_v3', 'folder_update_v3', 'resolve_folder_identifier', @@ -37,11 +40,13 @@ 'get_folder_access_v3', ], 'record_api': [ - 'create_record_data_v3', 'record_add_v3', 'record_update_v3', + 'create_record_data_v3', 'record_add_v3', 'record_add_pam_configuration_v3', 'record_update_v3', 'create_record_v3', 'update_record_v3', 'create_records_batch_v3', 'get_record_details_v3', 'get_record_accesses_v3', 'find_direct_user_share_access', 'is_record_share_update_noop', 'share_record_v3', 'update_record_share_v3', 'unshare_record_v3', + 'share_record_to_application_v3', 'update_record_share_to_application_v3', + 'unshare_record_from_application_v3', 'batch_update_record_shares_v3', 'batch_create_record_shares_v3', 'batch_unshare_records_v3', 'transfer_record_ownership_v3', 'transfer_records_ownership_batch_v3', diff --git a/keepercommander/nested_share_folder/folder_api.py b/keepercommander/nested_share_folder/folder_api.py index c2555bb21..378c0e181 100644 --- a/keepercommander/nested_share_folder/folder_api.py +++ b/keepercommander/nested_share_folder/folder_api.py @@ -12,7 +12,7 @@ from .. import utils, crypto, api from ..params import KeeperParams -from ..proto import folder_pb2 +from ..proto import folder_pb2, tla_pb2 from ..error import KeeperApiError from ..subfolder import try_resolve_path @@ -309,9 +309,20 @@ def _resolve_accessor(params, accessor_uid, as_team): return uid_bytes, accessor_uid, folder_pb2.AT_USER +def _apply_folder_expiration_tla(tla_props, expiration_timestamp, + rotate_on_expiration=False): + """Set expiration / ROE fields on folder-access TLAProperties.""" + if expiration_timestamp is None: + return + tla_props.expiration = expiration_timestamp + if rotate_on_expiration and expiration_timestamp > 0: + tla_props.timerNotificationType = tla_pb2.NOTIFY_OWNER + tla_props.rotateOnExpiration = True + + def grant_folder_access_v3(params, folder_uid, user_uid, role='viewer', share_folder_key=True, expiration_timestamp=None, - as_team=False): + as_team=False, rotate_on_expiration=False): """Grant a user *or team* access to a Nested Share Folder. """ resolved = resolve_folder_identifier(params, folder_uid) @@ -372,7 +383,8 @@ def grant_folder_access_v3(params, folder_uid, user_uid, role='viewer', 'success': True, 'action_taken': 'already_had_access'} result = update_folder_access_v3(params, folder_uid, identifier_label, role=role, as_team=as_team, - expiration_timestamp=expiration_timestamp) + expiration_timestamp=expiration_timestamp, + rotate_on_expiration=rotate_on_expiration) result['action_taken'] = 'updated' return result @@ -383,8 +395,8 @@ def grant_folder_access_v3(params, folder_uid, user_uid, role='viewer', ad.accessRoleType = access_role ad.permissions.CopyFrom(get_folder_permissions_for_role(access_role)) - if expiration_timestamp is not None: - ad.tlaProperties.expiration = expiration_timestamp + _apply_folder_expiration_tla( + ad.tlaProperties, expiration_timestamp, rotate_on_expiration) if share_folder_key: fk = get_folder_key(params, folder_uid) @@ -429,7 +441,8 @@ def _check_existing_access(params, folder_uid, uid_bytes, target_role_name, def update_folder_access_v3(params, folder_uid, user_uid, role=None, hidden=None, - expiration_timestamp=None, as_team=False): + expiration_timestamp=None, as_team=False, + rotate_on_expiration=False): if role is None and hidden is None and expiration_timestamp is None: raise ValueError("At least one field (role, hidden, or expiration) required") resolved = resolve_folder_identifier(params, folder_uid) @@ -452,8 +465,8 @@ def update_folder_access_v3(params, folder_uid, user_uid, role=None, hidden=None ad.permissions.CopyFrom(get_folder_permissions_for_role(resolved_role)) if hidden is not None: ad.hidden = hidden - if expiration_timestamp is not None: - ad.tlaProperties.expiration = expiration_timestamp + _apply_folder_expiration_tla( + ad.tlaProperties, expiration_timestamp, rotate_on_expiration) response = folder_access_update_v3(params, folder_access_updates=[ad]) result = parse_folder_access_result(response, folder_uid, identifier_label, @@ -523,6 +536,112 @@ def _evict_folder_accessor_cache(params, folder_uid, accessor_uid_b64): ] +def _application_folder_role(is_editable): + return 'content-manager' if is_editable else 'viewer' + + +def grant_folder_access_to_application_v3(params, folder_uid, app_uid, app_key, + is_editable=False): + """Grant a Secrets Manager application access to an NSF folder. + + Uses ``vault/folders/v3/access_update`` with ``AT_APPLICATION``, matching + the vault UI ``folderAccessAdds`` payload. + """ + resolved = resolve_folder_identifier(params, folder_uid) + if not resolved: + raise ValueError(f"Folder '{folder_uid}' not found") + folder_uid = resolved + if not app_uid or not app_key: + raise ValueError('Application UID and key are required') + + role = _application_folder_role(is_editable) + access_role = resolve_role_name(role) + target_role_name = folder_pb2.AccessRoleType.Name(access_role) + app_uid_bytes = utils.base64_url_decode(app_uid) + + existing = _check_existing_access( + params, folder_uid, app_uid_bytes, target_role_name, 'AT_APPLICATION') + if existing is not None: + if existing == target_role_name: + return { + 'folder_uid': folder_uid, + 'user_uid': app_uid, + 'access_type': 'AT_APPLICATION', + 'status': 'SUCCESS', + 'message': f'Application already has {role} access', + 'success': True, + 'action_taken': 'already_had_access', + } + return update_folder_access_to_application_v3( + params, folder_uid, app_uid, is_editable=is_editable) + + ad = folder_pb2.FolderAccessData() + ad.folderUid = utils.base64_url_decode(folder_uid) + ad.accessTypeUid = app_uid_bytes + ad.accessType = folder_pb2.AT_APPLICATION + ad.accessRoleType = access_role + ad.permissions.CopyFrom(get_folder_permissions_for_role(access_role)) + + folder_key = get_folder_key(params, folder_uid) + ek = folder_pb2.EncryptedDataKey() + ek.encryptedKey = crypto.encrypt_aes_v2(folder_key, app_key) + ek.encryptedKeyType = folder_pb2.encrypted_by_data_key_gcm + ad.folderKey.CopyFrom(ek) + + response = folder_access_update_v3(params, folder_access_adds=[ad]) + result = parse_folder_access_result( + response, folder_uid, app_uid, 'Application access granted successfully') + result['access_type'] = 'AT_APPLICATION' + result.setdefault('action_taken', 'granted' if result['success'] else 'grant_failed') + return result + + +def update_folder_access_to_application_v3(params, folder_uid, app_uid, + is_editable=False): + """Update an application's NSF folder role (viewer / content-manager).""" + resolved = resolve_folder_identifier(params, folder_uid) + if not resolved: + raise ValueError(f"Folder '{folder_uid}' not found") + folder_uid = resolved + + role = _application_folder_role(is_editable) + access_role = resolve_role_name(role) + + ad = folder_pb2.FolderAccessData() + ad.folderUid = utils.base64_url_decode(folder_uid) + ad.accessTypeUid = utils.base64_url_decode(app_uid) + ad.accessType = folder_pb2.AT_APPLICATION + ad.accessRoleType = access_role + ad.permissions.CopyFrom(get_folder_permissions_for_role(access_role)) + + response = folder_access_update_v3(params, folder_access_updates=[ad]) + result = parse_folder_access_result( + response, folder_uid, app_uid, 'Application access updated successfully') + result['access_type'] = 'AT_APPLICATION' + return result + + +def revoke_folder_access_from_application_v3(params, folder_uid, app_uid): + """Revoke a Secrets Manager application's access to an NSF folder.""" + resolved = resolve_folder_identifier(params, folder_uid) + if not resolved: + raise ValueError(f"Folder '{folder_uid}' not found") + folder_uid = resolved + + ad = folder_pb2.FolderAccessData() + ad.folderUid = utils.base64_url_decode(folder_uid) + ad.accessTypeUid = utils.base64_url_decode(app_uid) + ad.accessType = folder_pb2.AT_APPLICATION + + response = folder_access_update_v3(params, folder_access_removes=[ad]) + result = parse_folder_access_result( + response, folder_uid, app_uid, 'Application access revoked successfully') + result['access_type'] = 'AT_APPLICATION' + if result.get('success'): + params.sync_data = True + return result + + def revoke_folder_access_v3(params, folder_uid, user_uid, as_team=False): """Revoke user or team access to an NSF folder. diff --git a/keepercommander/nested_share_folder/folder_record_api.py b/keepercommander/nested_share_folder/folder_record_api.py index 1e64141a5..9070c78fc 100644 --- a/keepercommander/nested_share_folder/folder_record_api.py +++ b/keepercommander/nested_share_folder/folder_record_api.py @@ -13,6 +13,7 @@ encrypt_record_key_for_folder, ) from .folder_api import resolve_folder_identifier +from ..commands.nested_share_folder.helpers import normalize_nsf_user_message logger = logging.getLogger(__name__) @@ -175,7 +176,7 @@ def move_record_v3(params, record_uid, from_folder_uid=None, to_folder_uid=None) r = rs.folderRecordUpdateResult[0] if r.status != folder_pb2.SUCCESS: return _move_failure(record_uid, from_folder_uid, to_folder_uid, - f"Add failed: {r.message}") + f"Add failed: {normalize_nsf_user_message(r.message)}") except Exception as e: return _move_failure(record_uid, from_folder_uid, to_folder_uid, f"Add error: {e}") diff --git a/keepercommander/nested_share_folder/record_api.py b/keepercommander/nested_share_folder/record_api.py index f0bcc9e69..f3d13979a 100644 --- a/keepercommander/nested_share_folder/record_api.py +++ b/keepercommander/nested_share_folder/record_api.py @@ -29,7 +29,8 @@ def create_record_data_v3(record_uid, record_key, data, non_shared_data=None, folder_uid=None, folder_key=None, record_key_type=None, - client_modified_time=None, data_key=None): + client_modified_time=None, data_key=None, + owner_key=None, audit=None): ra = record_endpoints_pb2.RecordAdd() ra.recordUid = utils.base64_url_decode(record_uid) @@ -44,6 +45,10 @@ def create_record_data_v3(record_uid, record_key, data, raise ValueError("data_key required when creating at vault root") ra.recordKey = crypto.encrypt_aes_v2(record_key, data_key) + owner_encryption_key = owner_key or data_key + if owner_encryption_key is not None: + ra.recordKeyEncryptedByOwnerKey = crypto.encrypt_aes_v2(record_key, owner_encryption_key) + ra.recordKeyType = (record_key_type if record_key_type is not None else folder_pb2.encrypted_by_data_key_gcm) @@ -57,6 +62,8 @@ def create_record_data_v3(record_uid, record_key, data, ra.nonSharedData = crypto.encrypt_aes_v2(ns_bytes, record_key) if client_modified_time: ra.clientModifiedTime = client_modified_time + if audit is not None: + ra.audit.CopyFrom(audit) return ra @@ -77,6 +84,18 @@ def record_add_v3(params, records, client_time=None, security_data_key_type=None rs_type=record_pb2.RecordsModifyResponse) +def record_add_pam_configuration_v3(params, records, client_time=None, security_data_key_type=None): + if not records or len(records) > 1000: + raise ValueError("Provide 1..1000 records") + rq = record_endpoints_pb2.RecordsAddRequest() + rq.records.extend(records) + rq.clientTime = client_time if client_time is not None else utils.current_milli_time() + if security_data_key_type: + rq.securityDataKeyType = security_data_key_type + return api.communicate_rest(params, rq, 'vault/records/v3/add_pam_configuration', + rs_type=record_pb2.RecordsModifyResponse) + + def record_update_v3(params, records, client_time=None, security_data_key_type=None): if not records or len(records) > 1000: raise ValueError("Provide 1..1000 records") @@ -96,8 +115,8 @@ def record_update_v3(params, records, client_time=None, security_data_key_type=N def create_record_v3(params, record_type='', title='', fields=None, folder_uid=None, notes=None, custom_fields=None, - record_data=None): - uid = utils.generate_uid() + record_data=None, record_uid=None): + uid = record_uid or utils.generate_uid() rk = os.urandom(32) if record_data is not None: @@ -135,16 +154,15 @@ def create_record_v3(params, record_type='', title='', fields=None, def update_record_v3(params, record_uid, data=None, title=None, record_type=None, fields=None, notes=None, non_shared_data=None, revision=None): - if record_uid not in params.record_cache: + rec = get_record_from_cache(params, record_uid) + if not rec: from .. import sync_down sync_down.sync_down(params) - if record_uid not in params.record_cache: - raise ValueError(f"Record {record_uid} not found") + rec = get_record_from_cache(params, record_uid) + if not rec: + raise ValueError(f"Record {record_uid} not found") - rec = params.record_cache[record_uid] - rk = rec.get('record_key_unencrypted') - if not rk: - raise ValueError(f"Record key not available for {record_uid}") + rk = rec.get('record_key_unencrypted') or get_record_key(params, record_uid) if data is None: existing = None @@ -339,6 +357,8 @@ def get_record_accesses_v3(params, record_uids): # Proto3 scalar fields have no presence; only test the submessage. if d.HasField('tlaProperties'): ao['tla_expiration'] = d.tlaProperties.expiration + ao['tla_rotate_on_expiration'] = bool( + getattr(d.tlaProperties, 'rotateOnExpiration', False)) result['record_accesses'].append(ao) for fu in rs.forbiddenRecords: result['forbidden_records'].append(utils.base64_url_encode(fu)) @@ -363,8 +383,11 @@ def find_direct_user_share_access(access_result, record_uid, email): _SHARE_EXPIRATION_NOOP_TOLERANCE_MS = 60_000 -def is_record_share_update_noop(existing, access_role_type, expiration_timestamp): - """True when an update would leave role and expiration unchanged.""" +def is_record_share_update_noop(existing, access_role_type, expiration_timestamp, + rotate_on_expiration=False): + """True when an update would leave role, expiration, and ROE unchanged.""" + if rotate_on_expiration and not existing.get('tla_rotate_on_expiration'): + return False if existing.get('access_role_type') != access_role_type: return False existing_exp = existing.get('tla_expiration') @@ -383,13 +406,16 @@ def is_record_share_update_noop(existing, access_role_type, expiration_timestamp # Record sharing (Strategy: share / update / revoke) # ══════════════════════════════════════════════════════════════════════════ -def _apply_share_expiration_tla(tla_props, expiration_timestamp): - """Set expiration / notification fields on a TLAProperties proto.""" +def _apply_share_expiration_tla(tla_props, expiration_timestamp, + rotate_on_expiration=False): + """Set expiration / notification / ROE fields on a TLAProperties proto.""" if expiration_timestamp is None: return tla_props.expiration = expiration_timestamp if expiration_timestamp > 0: tla_props.timerNotificationType = tla_pb2.NOTIFY_OWNER + if rotate_on_expiration: + tla_props.rotateOnExpiration = True def _build_revoke_permission(params, record_uid, recipient_email): @@ -409,7 +435,8 @@ def _build_revoke_permission(params, record_uid, recipient_email): def _build_share_permissions(params, record_uid, recipient_email, access_role_type, - expiration_timestamp, include_role, skip_sync=False): + expiration_timestamp, include_role, skip_sync=False, + rotate_on_expiration=False): """Build a Permissions protobuf for share/update — single source of truth.""" if not skip_sync: from .. import sync_down as sd @@ -444,7 +471,9 @@ def _build_share_permissions(params, record_uid, recipient_email, access_role_ty perm.rules.owner = False if include_role and access_role_type is not None: perm.rules.accessRoleType = access_role_type - _apply_share_expiration_tla(perm.rules.tlaProperties, expiration_timestamp) + _apply_share_expiration_tla( + perm.rules.tlaProperties, expiration_timestamp, + rotate_on_expiration=rotate_on_expiration) return perm @@ -459,10 +488,12 @@ def _send_revoke_share_request(params, record_uid, recipient_email): def _send_create_share_request(params, record_uid, recipient_email, access_role_type, - expiration_timestamp, skip_sync=False): + expiration_timestamp, skip_sync=False, + rotate_on_expiration=False): perm = _build_share_permissions(params, record_uid, recipient_email, access_role_type, expiration_timestamp, - include_role=True, skip_sync=skip_sync) + include_role=True, skip_sync=skip_sync, + rotate_on_expiration=rotate_on_expiration) rq = record_sharing_pb2.Request() rq.createSharingPermissions.append(perm) rs = api.communicate_rest(params, rq, 'vault/records/v3/share', @@ -472,10 +503,11 @@ def _send_create_share_request(params, record_uid, recipient_email, access_role_ def share_record_v3(params, record_uid, recipient_email, access_role_type, - expiration_timestamp=None): + expiration_timestamp=None, rotate_on_expiration=False): perm = _build_share_permissions(params, record_uid, recipient_email, access_role_type, expiration_timestamp, - include_role=True) + include_role=True, + rotate_on_expiration=rotate_on_expiration) rq = record_sharing_pb2.Request() rq.createSharingPermissions.append(perm) rs = api.communicate_rest(params, rq, 'vault/records/v3/share', @@ -484,8 +516,82 @@ def share_record_v3(params, record_uid, recipient_email, access_role_type, return {'results': results, 'success': all(r['success'] for r in results)} +def _application_record_role(is_editable): + return folder_pb2.CONTENT_MANAGER if is_editable else folder_pb2.VIEWER + + +def _build_application_share_permission(params, record_uid, app_uid, app_key, + is_editable=False, include_key=True): + rec = get_record_from_cache(params, record_uid) + if not rec: + raise ValueError(f"Record {record_uid} not found in cache") + rk = rec.get('record_key_unencrypted') + if not rk and include_key: + rk = get_record_key(params, record_uid, raise_on_missing=False) + if include_key and not rk: + raise ValueError(f"Record {record_uid} has no decrypted key") + if not app_uid: + raise ValueError('Application UID is required') + + app_uid_bytes = utils.base64_url_decode(app_uid) + record_uid_bytes = utils.base64_url_decode(record_uid) + + perm = record_sharing_pb2.Permissions() + perm.recipientUid = app_uid_bytes + perm.recordUid = record_uid_bytes + if include_key: + perm.recordKey = crypto.encrypt_aes_v2(rk, app_key) + perm.useEccKey = False + + perm.rules.accessTypeUid = app_uid_bytes + perm.rules.accessType = folder_pb2.AT_APPLICATION + perm.rules.recordUid = record_uid_bytes + perm.rules.owner = False + perm.rules.accessRoleType = _application_record_role(is_editable) + return perm + + +def share_record_to_application_v3(params, record_uid, app_uid, app_key, + is_editable=False): + """Share an NSF record with a Secrets Manager application via records/v3/share.""" + perm = _build_application_share_permission( + params, record_uid, app_uid, app_key, is_editable=is_editable, include_key=True) + rq = record_sharing_pb2.Request() + rq.createSharingPermissions.append(perm) + rs = api.communicate_rest(params, rq, 'vault/records/v3/share', + rs_type=record_sharing_pb2.Response) + results = [parse_sharing_status(s) for s in rs.createdSharingStatus] + return {'results': results, 'success': all(r['success'] for r in results)} + + +def update_record_share_to_application_v3(params, record_uid, app_uid, app_key, + is_editable=False): + """Update an NSF record's application share role.""" + perm = _build_application_share_permission( + params, record_uid, app_uid, app_key, is_editable=is_editable, include_key=True) + rq = record_sharing_pb2.Request() + rq.updateSharingPermissions.append(perm) + rs = api.communicate_rest(params, rq, 'vault/records/v3/share', + rs_type=record_sharing_pb2.Response) + results = [parse_sharing_status(s) for s in rs.updatedSharingStatus] + return {'results': results, 'success': all(r['success'] for r in results)} + + +def unshare_record_from_application_v3(params, record_uid, app_uid): + """Revoke a Secrets Manager application's access to an NSF record.""" + perm = _build_application_share_permission( + params, record_uid, app_uid, app_key=None, is_editable=False, include_key=False) + rq = record_sharing_pb2.Request() + rq.revokeSharingPermissions.append(perm) + rs = api.communicate_rest(params, rq, 'vault/records/v3/share', + rs_type=record_sharing_pb2.Response) + results = [parse_sharing_status(s) for s in rs.revokedSharingStatus] + return {'results': results, 'success': all(r['success'] for r in results)} + + def update_record_share_v3(params, record_uid, recipient_email, - access_role_type=None, expiration_timestamp=None): + access_role_type=None, expiration_timestamp=None, + rotate_on_expiration=False): """Update an existing direct share. Role changes use ``updateSharingPermissions``. Positive expirations use @@ -518,11 +624,13 @@ def update_record_share_v3(params, record_uid, recipient_email, recipient_email) return _send_create_share_request( params, record_uid, recipient_email, access_role_type, - expiration_timestamp, skip_sync=True) + expiration_timestamp, skip_sync=True, + rotate_on_expiration=rotate_on_expiration) perm = _build_share_permissions(params, record_uid, recipient_email, access_role_type, expiration_timestamp, - include_role=True, skip_sync=True) + include_role=True, skip_sync=True, + rotate_on_expiration=rotate_on_expiration) rq = record_sharing_pb2.Request() rq.updateSharingPermissions.append(perm) rs = api.communicate_rest(params, rq, 'vault/records/v3/share', @@ -530,7 +638,6 @@ def update_record_share_v3(params, record_uid, recipient_email, results = [parse_sharing_status(s) for s in rs.updatedSharingStatus] return {'results': results, 'success': all(r['success'] for r in results)} - def unshare_record_v3(params, record_uid, recipient_email, skip_sync=False): if not skip_sync: from .. import sync_down as sd diff --git a/keepercommander/nested_share_folder/sync.py b/keepercommander/nested_share_folder/sync.py index 716e96441..32992276d 100644 --- a/keepercommander/nested_share_folder/sync.py +++ b/keepercommander/nested_share_folder/sync.py @@ -189,6 +189,7 @@ def _process_nested_share_folder_sync(params, acc): record_links = acc.get('record_links') or [] removed_record_links = acc.get('removed_record_links') or [] raw_dag_data = acc.get('raw_dag_data') or [] + record_rotations = acc.get('record_rotations') or [] _process_users(params, users) _process_folders(params, folders) @@ -204,6 +205,7 @@ def _process_nested_share_folder_sync(params, acc): _process_record_accesses(params, record_accesses) _process_revoked_record_accesses(params, revoked_record_accesses) _process_record_sharing_states(params, record_sharing_states) + _process_record_rotations(params, record_rotations) _process_record_links(params, record_links) _process_removed_record_links(params, removed_record_links) @@ -227,6 +229,13 @@ def _process_users(params, users): params.user_cache[account_uid] = user.username +def _process_record_rotations(params, record_rotations): + """Fold NSF ``recordRotationData`` into ``params.record_rotation_cache``.""" + from .. import vault_extensions + for rr in record_rotations: + vault_extensions.cache_record_rotation(params, rr) + + def _process_folders(params, folders): """Store base folder objects (encrypted; keys/data decrypted later).""" for folder_data in folders: diff --git a/keepercommander/proto/AccountSummary_pb2.py b/keepercommander/proto/AccountSummary_pb2.py index 353062c78..c6a89b29e 100644 --- a/keepercommander/proto/AccountSummary_pb2.py +++ b/keepercommander/proto/AccountSummary_pb2.py @@ -25,11 +25,11 @@ from . import APIRequest_pb2 as APIRequest__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14\x41\x63\x63ountSummary.proto\x12\x0e\x41\x63\x63ountSummary\x1a\x10\x41PIRequest.proto\"N\n\x15\x41\x63\x63ountSummaryRequest\x12\x16\n\x0esummaryVersion\x18\x01 \x01(\x05\x12\x1d\n\x15includeRecentActivity\x18\x02 \x01(\x08\"\xcc\x05\n\x16\x41\x63\x63ountSummaryElements\x12\x11\n\tclientKey\x18\x01 \x01(\x0c\x12*\n\x08settings\x18\x02 \x01(\x0b\x32\x18.AccountSummary.Settings\x12*\n\x08keysInfo\x18\x03 \x01(\x0b\x32\x18.AccountSummary.KeysInfo\x12)\n\x08syncLogs\x18\x04 \x03(\x0b\x32\x17.AccountSummary.SyncLog\x12\x19\n\x11isEnterpriseAdmin\x18\x05 \x01(\x08\x12(\n\x07license\x18\x06 \x01(\x0b\x32\x17.AccountSummary.License\x12$\n\x05group\x18\x07 \x01(\x0b\x32\x15.AccountSummary.Group\x12\x32\n\x0c\x45nforcements\x18\x08 \x01(\x0b\x32\x1c.AccountSummary.Enforcements\x12(\n\x06Images\x18\t \x03(\x0b\x32\x18.AccountSummary.KeyValue\x12\x30\n\x0fpersonalLicense\x18\n \x01(\x0b\x32\x17.AccountSummary.License\x12\x1e\n\x16\x66ixSharedFolderRecords\x18\x0b \x01(\x08\x12\x11\n\tusernames\x18\x0c \x03(\t\x12+\n\x07\x64\x65vices\x18\r \x03(\x0b\x32\x1a.AccountSummary.DeviceInfo\x12\x14\n\x0cisShareAdmin\x18\x0e \x01(\x08\x12\x17\n\x0f\x61\x63\x63ountRecovery\x18\x0f \x01(\x08\x12\x1d\n\x15\x61\x63\x63ountRecoveryPrompt\x18\x10 \x01(\x08\x12\'\n\x1fminMasterPasswordLengthNoPrompt\x18\x11 \x01(\x05\x12\x16\n\x0e\x66orbidKeyType2\x18\x12 \x01(\x08\x12\x16\n\x0e\x66orbidKeyType1\x18\x13 \x01(\x08\x12\x1a\n\x12\x64isallowedFeatures\x18\x14 \x03(\t\"\x8b\x03\n\nDeviceInfo\x12\x1c\n\x14\x65ncryptedDeviceToken\x18\x01 \x01(\x0c\x12\x12\n\ndeviceName\x18\x02 \x01(\t\x12\x32\n\x0c\x64\x65viceStatus\x18\x03 \x01(\x0e\x32\x1c.Authentication.DeviceStatus\x12\x17\n\x0f\x64\x65vicePublicKey\x18\x04 \x01(\x0c\x12 \n\x18\x65ncryptedDataKeyDoNotUse\x18\x05 \x01(\x0c\x12\x15\n\rclientVersion\x18\x06 \x01(\t\x12\x10\n\x08username\x18\x07 \x01(\t\x12\x11\n\tipAddress\x18\x08 \x01(\t\x12\x1a\n\x12\x61pproveRequestTime\x18\t \x01(\x03\x12\x1f\n\x17\x65ncryptedDataKeyPresent\x18\n \x01(\x08\x12\x0f\n\x07groupId\x18\x0b \x01(\x03\x12\x16\n\x0e\x64\x65vicePlatform\x18\x0c \x01(\t\x12:\n\x10\x63lientFormFactor\x18\r \x01(\x0e\x32 .Authentication.ClientFormFactor\"\xc1\x01\n\x08KeysInfo\x12\x18\n\x10\x65ncryptionParams\x18\x01 \x01(\x0c\x12\x18\n\x10\x65ncryptedDataKey\x18\x02 \x01(\x0c\x12\x19\n\x11\x64\x61taKeyBackupDate\x18\x03 \x01(\x01\x12\x13\n\x0buserAuthUid\x18\x04 \x01(\x0c\x12\x1b\n\x13\x65ncryptedPrivateKey\x18\x05 \x01(\x0c\x12\x1e\n\x16\x65ncryptedEccPrivateKey\x18\x06 \x01(\x0c\x12\x14\n\x0c\x65\x63\x63PublicKey\x18\x07 \x01(\x0c\"\x81\x01\n\x07SyncLog\x12\x13\n\x0b\x63ountryName\x18\x01 \x01(\t\x12\x12\n\nsecondsAgo\x18\x02 \x01(\x03\x12\x12\n\ndeviceName\x18\x03 \x01(\t\x12\x13\n\x0b\x63ountryCode\x18\x04 \x01(\t\x12\x11\n\tdeviceUID\x18\x05 \x01(\x0c\x12\x11\n\tipAddress\x18\x06 \x01(\t\"\xfd\x06\n\x07License\x12\x18\n\x10subscriptionCode\x18\x01 \x01(\t\x12\x15\n\rproductTypeId\x18\x02 \x01(\x05\x12\x17\n\x0fproductTypeName\x18\x03 \x01(\t\x12\x16\n\x0e\x65xpirationDate\x18\x04 \x01(\t\x12\x1e\n\x16secondsUntilExpiration\x18\x05 \x01(\x03\x12\x12\n\nmaxDevices\x18\x06 \x01(\x05\x12\x14\n\x0c\x66ilePlanType\x18\x07 \x01(\x05\x12\x11\n\tbytesUsed\x18\x08 \x01(\x03\x12\x12\n\nbytesTotal\x18\t \x01(\x03\x12%\n\x1dsecondsUntilStorageExpiration\x18\n \x01(\x03\x12\x1d\n\x15storageExpirationDate\x18\x0b \x01(\t\x12,\n$hasAutoRenewableAppstoreSubscription\x18\x0c \x01(\x08\x12\x13\n\x0b\x61\x63\x63ountType\x18\r \x01(\x05\x12\x18\n\x10uploadsRemaining\x18\x0e \x01(\x05\x12\x14\n\x0c\x65nterpriseId\x18\x0f \x01(\x05\x12\x13\n\x0b\x63hatEnabled\x18\x10 \x01(\x08\x12 \n\x18\x61uditAndReportingEnabled\x18\x11 \x01(\x08\x12!\n\x19\x62reachWatchFeatureDisable\x18\x12 \x01(\x08\x12\x12\n\naccountUid\x18\x13 \x01(\x0c\x12\x1c\n\x14\x61llowPersonalLicense\x18\x14 \x01(\x08\x12\x12\n\nlicensedBy\x18\x15 \x01(\t\x12\r\n\x05\x65mail\x18\x16 \x01(\t\x12\x1a\n\x12\x62reachWatchEnabled\x18\x17 \x01(\x08\x12\x1a\n\x12\x62reachWatchScanned\x18\x18 \x01(\x08\x12\x1d\n\x15\x62reachWatchExpiration\x18\x19 \x01(\x03\x12\x1e\n\x16\x62reachWatchDateCreated\x18\x1a \x01(\x03\x12%\n\x05\x65rror\x18\x1b \x01(\x0b\x32\x16.AccountSummary.Result\x12\x12\n\nexpiration\x18\x1d \x01(\x03\x12\x19\n\x11storageExpiration\x18\x1e \x01(\x03\x12\x14\n\x0cuploadsCount\x18\x1f \x01(\x05\x12\r\n\x05units\x18 \x01(\x05\x12\x19\n\x11pendingEnterprise\x18! \x01(\x08\x12\x14\n\x0cisPamEnabled\x18\" \x01(\x08\x12\x14\n\x0cisKsmEnabled\x18# \x01(\x08\"\xa3\x01\n\x05\x41\x64\x64On\x12\x14\n\x0clicenseKeyId\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x16\n\x0e\x65xpirationDate\x18\x03 \x01(\x03\x12\x13\n\x0b\x63reatedDate\x18\x04 \x01(\x03\x12\x0f\n\x07isTrial\x18\x05 \x01(\x08\x12\x0f\n\x07\x65nabled\x18\x06 \x01(\x08\x12\x0f\n\x07scanned\x18\x07 \x01(\x08\x12\x16\n\x0e\x66\x65\x61tureDisable\x18\x08 \x01(\x08\"\xf4\t\n\x08Settings\x12\r\n\x05\x61udit\x18\x01 \x01(\x08\x12!\n\x19mustPerformAccountShareBy\x18\x02 \x01(\x03\x12>\n\x0eshareAccountTo\x18\x03 \x03(\x0b\x32&.AccountSummary.MissingAccountShareKey\x12+\n\x05rules\x18\x04 \x03(\x0b\x32\x1c.AccountSummary.PasswordRule\x12\x1a\n\x12passwordRulesIntro\x18\x05 \x01(\t\x12\x16\n\x0e\x61utoBackupDays\x18\x06 \x01(\x05\x12\r\n\x05theme\x18\x07 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x08 \x01(\t\x12\x14\n\x0c\x63hannelValue\x18\t \x01(\t\x12\x15\n\rrsaConfigured\x18\n \x01(\x08\x12\x15\n\remailVerified\x18\x0b \x01(\x08\x12\"\n\x1amasterPasswordLastModified\x18\x0c \x01(\x01\x12\x18\n\x10\x61\x63\x63ountFolderKey\x18\r \x01(\x0c\x12\x31\n\x0csecurityKeys\x18\x0e \x03(\x0b\x32\x1b.AccountSummary.SecurityKey\x12+\n\tkeyValues\x18\x0f \x03(\x0b\x32\x18.AccountSummary.KeyValue\x12\x0f\n\x07ssoUser\x18\x10 \x01(\x08\x12\x18\n\x10onlineAccessOnly\x18\x11 \x01(\x08\x12\x1c\n\x14masterPasswordExpiry\x18\x12 \x01(\x05\x12\x19\n\x11twoFactorRequired\x18\x13 \x01(\x08\x12\x16\n\x0e\x64isallowExport\x18\x14 \x01(\x08\x12\x15\n\rrestrictFiles\x18\x15 \x01(\x08\x12\x1a\n\x12restrictAllSharing\x18\x16 \x01(\x08\x12\x17\n\x0frestrictSharing\x18\x17 \x01(\x08\x12\"\n\x1arestrictSharingIncomingAll\x18\x18 \x01(\x08\x12)\n!restrictSharingIncomingEnterprise\x18\x19 \x01(\x08\x12\x13\n\x0blogoutTimer\x18\x1a \x01(\x03\x12\x17\n\x0fpersistentLogin\x18\x1b \x01(\x08\x12\x1c\n\x14ipDisableAutoApprove\x18\x1c \x01(\x08\x12$\n\x1cshareDataKeyWithEccPublicKey\x18\x1d \x01(\x08\x12\'\n\x1fshareDataKeyWithDevicePublicKey\x18\x1e \x01(\x08\x12\x1a\n\x12RecordTypesCounter\x18\x1f \x01(\x05\x12$\n\x1cRecordTypesEnterpriseCounter\x18 \x01(\x05\x12\x1a\n\x12recordTypesEnabled\x18! \x01(\x08\x12\x1c\n\x14\x63\x61nManageRecordTypes\x18\" \x01(\x08\x12\x1d\n\x15recordTypesPAMCounter\x18# \x01(\x05\x12\x1a\n\x12logoutTimerMinutes\x18$ \x01(\x05\x12 \n\x18securityKeysNoUserVerify\x18% \x01(\x08\x12\x36\n\x08\x63hannels\x18& \x03(\x0e\x32$.Authentication.TwoFactorChannelType\x12\x19\n\x11personalUsernames\x18\' \x03(\t\x12\x15\n\rmaxIpDistance\x18( \x01(\x05\x12\x1e\n\x16maxIpDistanceEffective\x18) \x01(\x05\"&\n\x08KeyValue\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"-\n\x0fKeyValueBoolean\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x08\"*\n\x0cKeyValueLong\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x03\"=\n\x06Result\x12\x12\n\nresultCode\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0e\n\x06result\x18\x03 \x01(\t\"\xc2\x01\n\x0c\x45nforcements\x12)\n\x07strings\x18\x01 \x03(\x0b\x32\x18.AccountSummary.KeyValue\x12\x31\n\x08\x62ooleans\x18\x02 \x03(\x0b\x32\x1f.AccountSummary.KeyValueBoolean\x12+\n\x05longs\x18\x03 \x03(\x0b\x32\x1c.AccountSummary.KeyValueLong\x12\'\n\x05jsons\x18\x04 \x03(\x0b\x32\x18.AccountSummary.KeyValue\"<\n\x16MissingAccountShareKey\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x11\n\tpublicKey\x18\x02 \x01(\x0c\"u\n\x0cPasswordRule\x12\x10\n\x08ruleType\x18\x01 \x01(\t\x12\x0f\n\x07pattern\x18\x02 \x01(\t\x12\r\n\x05match\x18\x03 \x01(\x08\x12\x0f\n\x07minimum\x18\x04 \x01(\x05\x12\x13\n\x0b\x64\x65scription\x18\x05 \x01(\t\x12\r\n\x05value\x18\x06 \x01(\t\"\x97\x01\n\x0bSecurityKey\x12\x10\n\x08\x64\x65viceId\x18\x01 \x01(\x03\x12\x12\n\ndeviceName\x18\x02 \x01(\t\x12\x11\n\tdateAdded\x18\x03 \x01(\x03\x12\x0f\n\x07isValid\x18\x04 \x01(\x08\x12>\n\x12\x64\x65viceRegistration\x18\x05 \x01(\x0b\x32\".AccountSummary.DeviceRegistration\"y\n\x12\x44\x65viceRegistration\x12\x11\n\tkeyHandle\x18\x01 \x01(\t\x12\x11\n\tpublicKey\x18\x02 \x01(\x0c\x12\x17\n\x0f\x61ttestationCert\x18\x03 \x01(\t\x12\x0f\n\x07\x63ounter\x18\x04 \x01(\x03\x12\x13\n\x0b\x63ompromised\x18\x05 \x01(\x08\"k\n\x05Group\x12\r\n\x05\x61\x64min\x18\x01 \x01(\x08\x12\x1d\n\x15groupVerificationCode\x18\x02 \x01(\t\x12\x34\n\radministrator\x18\x04 \x01(\x0b\x32\x1d.AccountSummary.Administrator\"\xc0\x01\n\rAdministrator\x12\x11\n\tfirstName\x18\x01 \x01(\t\x12\x10\n\x08lastName\x18\x02 \x01(\t\x12\r\n\x05\x65mail\x18\x03 \x01(\t\x12\x1c\n\x14\x63urrentNumberOfUsers\x18\x04 \x01(\x05\x12\x15\n\rnumberOfUsers\x18\x05 \x01(\x05\x12\x18\n\x10subscriptionCode\x18\x07 \x01(\t\x12\x16\n\x0e\x65xpirationDate\x18\x08 \x01(\t\x12\x14\n\x0cpurchaseDate\x18\t \x01(\tB*\n\x18\x63om.keepersecurity.protoB\x0e\x41\x63\x63ountSummaryb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x14\x61\x63\x63ountsummary.proto\x12\x0e\x41\x63\x63ountSummary\x1a\x10\x41PIRequest.proto\"N\n\x15\x41\x63\x63ountSummaryRequest\x12\x16\n\x0esummaryVersion\x18\x01 \x01(\x05\x12\x1d\n\x15includeRecentActivity\x18\x02 \x01(\x08\"\xcc\x05\n\x16\x41\x63\x63ountSummaryElements\x12\x11\n\tclientKey\x18\x01 \x01(\x0c\x12*\n\x08settings\x18\x02 \x01(\x0b\x32\x18.AccountSummary.Settings\x12*\n\x08keysInfo\x18\x03 \x01(\x0b\x32\x18.AccountSummary.KeysInfo\x12)\n\x08syncLogs\x18\x04 \x03(\x0b\x32\x17.AccountSummary.SyncLog\x12\x19\n\x11isEnterpriseAdmin\x18\x05 \x01(\x08\x12(\n\x07license\x18\x06 \x01(\x0b\x32\x17.AccountSummary.License\x12$\n\x05group\x18\x07 \x01(\x0b\x32\x15.AccountSummary.Group\x12\x32\n\x0c\x45nforcements\x18\x08 \x01(\x0b\x32\x1c.AccountSummary.Enforcements\x12(\n\x06Images\x18\t \x03(\x0b\x32\x18.AccountSummary.KeyValue\x12\x30\n\x0fpersonalLicense\x18\n \x01(\x0b\x32\x17.AccountSummary.License\x12\x1e\n\x16\x66ixSharedFolderRecords\x18\x0b \x01(\x08\x12\x11\n\tusernames\x18\x0c \x03(\t\x12+\n\x07\x64\x65vices\x18\r \x03(\x0b\x32\x1a.AccountSummary.DeviceInfo\x12\x14\n\x0cisShareAdmin\x18\x0e \x01(\x08\x12\x17\n\x0f\x61\x63\x63ountRecovery\x18\x0f \x01(\x08\x12\x1d\n\x15\x61\x63\x63ountRecoveryPrompt\x18\x10 \x01(\x08\x12\'\n\x1fminMasterPasswordLengthNoPrompt\x18\x11 \x01(\x05\x12\x16\n\x0e\x66orbidKeyType2\x18\x12 \x01(\x08\x12\x16\n\x0e\x66orbidKeyType1\x18\x13 \x01(\x08\x12\x1a\n\x12\x64isallowedFeatures\x18\x14 \x03(\t\"\x8b\x03\n\nDeviceInfo\x12\x1c\n\x14\x65ncryptedDeviceToken\x18\x01 \x01(\x0c\x12\x12\n\ndeviceName\x18\x02 \x01(\t\x12\x32\n\x0c\x64\x65viceStatus\x18\x03 \x01(\x0e\x32\x1c.Authentication.DeviceStatus\x12\x17\n\x0f\x64\x65vicePublicKey\x18\x04 \x01(\x0c\x12 \n\x18\x65ncryptedDataKeyDoNotUse\x18\x05 \x01(\x0c\x12\x15\n\rclientVersion\x18\x06 \x01(\t\x12\x10\n\x08username\x18\x07 \x01(\t\x12\x11\n\tipAddress\x18\x08 \x01(\t\x12\x1a\n\x12\x61pproveRequestTime\x18\t \x01(\x03\x12\x1f\n\x17\x65ncryptedDataKeyPresent\x18\n \x01(\x08\x12\x0f\n\x07groupId\x18\x0b \x01(\x03\x12\x16\n\x0e\x64\x65vicePlatform\x18\x0c \x01(\t\x12:\n\x10\x63lientFormFactor\x18\r \x01(\x0e\x32 .Authentication.ClientFormFactor\"\xc1\x01\n\x08KeysInfo\x12\x18\n\x10\x65ncryptionParams\x18\x01 \x01(\x0c\x12\x18\n\x10\x65ncryptedDataKey\x18\x02 \x01(\x0c\x12\x19\n\x11\x64\x61taKeyBackupDate\x18\x03 \x01(\x01\x12\x13\n\x0buserAuthUid\x18\x04 \x01(\x0c\x12\x1b\n\x13\x65ncryptedPrivateKey\x18\x05 \x01(\x0c\x12\x1e\n\x16\x65ncryptedEccPrivateKey\x18\x06 \x01(\x0c\x12\x14\n\x0c\x65\x63\x63PublicKey\x18\x07 \x01(\x0c\"\x81\x01\n\x07SyncLog\x12\x13\n\x0b\x63ountryName\x18\x01 \x01(\t\x12\x12\n\nsecondsAgo\x18\x02 \x01(\x03\x12\x12\n\ndeviceName\x18\x03 \x01(\t\x12\x13\n\x0b\x63ountryCode\x18\x04 \x01(\t\x12\x11\n\tdeviceUID\x18\x05 \x01(\x0c\x12\x11\n\tipAddress\x18\x06 \x01(\t\"\xfd\x06\n\x07License\x12\x18\n\x10subscriptionCode\x18\x01 \x01(\t\x12\x15\n\rproductTypeId\x18\x02 \x01(\x05\x12\x17\n\x0fproductTypeName\x18\x03 \x01(\t\x12\x16\n\x0e\x65xpirationDate\x18\x04 \x01(\t\x12\x1e\n\x16secondsUntilExpiration\x18\x05 \x01(\x03\x12\x12\n\nmaxDevices\x18\x06 \x01(\x05\x12\x14\n\x0c\x66ilePlanType\x18\x07 \x01(\x05\x12\x11\n\tbytesUsed\x18\x08 \x01(\x03\x12\x12\n\nbytesTotal\x18\t \x01(\x03\x12%\n\x1dsecondsUntilStorageExpiration\x18\n \x01(\x03\x12\x1d\n\x15storageExpirationDate\x18\x0b \x01(\t\x12,\n$hasAutoRenewableAppstoreSubscription\x18\x0c \x01(\x08\x12\x13\n\x0b\x61\x63\x63ountType\x18\r \x01(\x05\x12\x18\n\x10uploadsRemaining\x18\x0e \x01(\x05\x12\x14\n\x0c\x65nterpriseId\x18\x0f \x01(\x05\x12\x13\n\x0b\x63hatEnabled\x18\x10 \x01(\x08\x12 \n\x18\x61uditAndReportingEnabled\x18\x11 \x01(\x08\x12!\n\x19\x62reachWatchFeatureDisable\x18\x12 \x01(\x08\x12\x12\n\naccountUid\x18\x13 \x01(\x0c\x12\x1c\n\x14\x61llowPersonalLicense\x18\x14 \x01(\x08\x12\x12\n\nlicensedBy\x18\x15 \x01(\t\x12\r\n\x05\x65mail\x18\x16 \x01(\t\x12\x1a\n\x12\x62reachWatchEnabled\x18\x17 \x01(\x08\x12\x1a\n\x12\x62reachWatchScanned\x18\x18 \x01(\x08\x12\x1d\n\x15\x62reachWatchExpiration\x18\x19 \x01(\x03\x12\x1e\n\x16\x62reachWatchDateCreated\x18\x1a \x01(\x03\x12%\n\x05\x65rror\x18\x1b \x01(\x0b\x32\x16.AccountSummary.Result\x12\x12\n\nexpiration\x18\x1d \x01(\x03\x12\x19\n\x11storageExpiration\x18\x1e \x01(\x03\x12\x14\n\x0cuploadsCount\x18\x1f \x01(\x05\x12\r\n\x05units\x18 \x01(\x05\x12\x19\n\x11pendingEnterprise\x18! \x01(\x08\x12\x14\n\x0cisPamEnabled\x18\" \x01(\x08\x12\x14\n\x0cisKsmEnabled\x18# \x01(\x08\"\xa3\x01\n\x05\x41\x64\x64On\x12\x14\n\x0clicenseKeyId\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x16\n\x0e\x65xpirationDate\x18\x03 \x01(\x03\x12\x13\n\x0b\x63reatedDate\x18\x04 \x01(\x03\x12\x0f\n\x07isTrial\x18\x05 \x01(\x08\x12\x0f\n\x07\x65nabled\x18\x06 \x01(\x08\x12\x0f\n\x07scanned\x18\x07 \x01(\x08\x12\x16\n\x0e\x66\x65\x61tureDisable\x18\x08 \x01(\x08\"\xf4\t\n\x08Settings\x12\r\n\x05\x61udit\x18\x01 \x01(\x08\x12!\n\x19mustPerformAccountShareBy\x18\x02 \x01(\x03\x12>\n\x0eshareAccountTo\x18\x03 \x03(\x0b\x32&.AccountSummary.MissingAccountShareKey\x12+\n\x05rules\x18\x04 \x03(\x0b\x32\x1c.AccountSummary.PasswordRule\x12\x1a\n\x12passwordRulesIntro\x18\x05 \x01(\t\x12\x16\n\x0e\x61utoBackupDays\x18\x06 \x01(\x05\x12\r\n\x05theme\x18\x07 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x08 \x01(\t\x12\x14\n\x0c\x63hannelValue\x18\t \x01(\t\x12\x15\n\rrsaConfigured\x18\n \x01(\x08\x12\x15\n\remailVerified\x18\x0b \x01(\x08\x12\"\n\x1amasterPasswordLastModified\x18\x0c \x01(\x01\x12\x18\n\x10\x61\x63\x63ountFolderKey\x18\r \x01(\x0c\x12\x31\n\x0csecurityKeys\x18\x0e \x03(\x0b\x32\x1b.AccountSummary.SecurityKey\x12+\n\tkeyValues\x18\x0f \x03(\x0b\x32\x18.AccountSummary.KeyValue\x12\x0f\n\x07ssoUser\x18\x10 \x01(\x08\x12\x18\n\x10onlineAccessOnly\x18\x11 \x01(\x08\x12\x1c\n\x14masterPasswordExpiry\x18\x12 \x01(\x05\x12\x19\n\x11twoFactorRequired\x18\x13 \x01(\x08\x12\x16\n\x0e\x64isallowExport\x18\x14 \x01(\x08\x12\x15\n\rrestrictFiles\x18\x15 \x01(\x08\x12\x1a\n\x12restrictAllSharing\x18\x16 \x01(\x08\x12\x17\n\x0frestrictSharing\x18\x17 \x01(\x08\x12\"\n\x1arestrictSharingIncomingAll\x18\x18 \x01(\x08\x12)\n!restrictSharingIncomingEnterprise\x18\x19 \x01(\x08\x12\x13\n\x0blogoutTimer\x18\x1a \x01(\x03\x12\x17\n\x0fpersistentLogin\x18\x1b \x01(\x08\x12\x1c\n\x14ipDisableAutoApprove\x18\x1c \x01(\x08\x12$\n\x1cshareDataKeyWithEccPublicKey\x18\x1d \x01(\x08\x12\'\n\x1fshareDataKeyWithDevicePublicKey\x18\x1e \x01(\x08\x12\x1a\n\x12RecordTypesCounter\x18\x1f \x01(\x05\x12$\n\x1cRecordTypesEnterpriseCounter\x18 \x01(\x05\x12\x1a\n\x12recordTypesEnabled\x18! \x01(\x08\x12\x1c\n\x14\x63\x61nManageRecordTypes\x18\" \x01(\x08\x12\x1d\n\x15recordTypesPAMCounter\x18# \x01(\x05\x12\x1a\n\x12logoutTimerMinutes\x18$ \x01(\x05\x12 \n\x18securityKeysNoUserVerify\x18% \x01(\x08\x12\x36\n\x08\x63hannels\x18& \x03(\x0e\x32$.Authentication.TwoFactorChannelType\x12\x19\n\x11personalUsernames\x18\' \x03(\t\x12\x15\n\rmaxIpDistance\x18( \x01(\x05\x12\x1e\n\x16maxIpDistanceEffective\x18) \x01(\x05\"&\n\x08KeyValue\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"-\n\x0fKeyValueBoolean\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x08\"*\n\x0cKeyValueLong\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x03\"=\n\x06Result\x12\x12\n\nresultCode\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0e\n\x06result\x18\x03 \x01(\t\"\xc2\x01\n\x0c\x45nforcements\x12)\n\x07strings\x18\x01 \x03(\x0b\x32\x18.AccountSummary.KeyValue\x12\x31\n\x08\x62ooleans\x18\x02 \x03(\x0b\x32\x1f.AccountSummary.KeyValueBoolean\x12+\n\x05longs\x18\x03 \x03(\x0b\x32\x1c.AccountSummary.KeyValueLong\x12\'\n\x05jsons\x18\x04 \x03(\x0b\x32\x18.AccountSummary.KeyValue\"<\n\x16MissingAccountShareKey\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x11\n\tpublicKey\x18\x02 \x01(\x0c\"u\n\x0cPasswordRule\x12\x10\n\x08ruleType\x18\x01 \x01(\t\x12\x0f\n\x07pattern\x18\x02 \x01(\t\x12\r\n\x05match\x18\x03 \x01(\x08\x12\x0f\n\x07minimum\x18\x04 \x01(\x05\x12\x13\n\x0b\x64\x65scription\x18\x05 \x01(\t\x12\r\n\x05value\x18\x06 \x01(\t\"\x97\x01\n\x0bSecurityKey\x12\x10\n\x08\x64\x65viceId\x18\x01 \x01(\x03\x12\x12\n\ndeviceName\x18\x02 \x01(\t\x12\x11\n\tdateAdded\x18\x03 \x01(\x03\x12\x0f\n\x07isValid\x18\x04 \x01(\x08\x12>\n\x12\x64\x65viceRegistration\x18\x05 \x01(\x0b\x32\".AccountSummary.DeviceRegistration\"y\n\x12\x44\x65viceRegistration\x12\x11\n\tkeyHandle\x18\x01 \x01(\t\x12\x11\n\tpublicKey\x18\x02 \x01(\x0c\x12\x17\n\x0f\x61ttestationCert\x18\x03 \x01(\t\x12\x0f\n\x07\x63ounter\x18\x04 \x01(\x03\x12\x13\n\x0b\x63ompromised\x18\x05 \x01(\x08\"k\n\x05Group\x12\r\n\x05\x61\x64min\x18\x01 \x01(\x08\x12\x1d\n\x15groupVerificationCode\x18\x02 \x01(\t\x12\x34\n\radministrator\x18\x04 \x01(\x0b\x32\x1d.AccountSummary.Administrator\"\xc0\x01\n\rAdministrator\x12\x11\n\tfirstName\x18\x01 \x01(\t\x12\x10\n\x08lastName\x18\x02 \x01(\t\x12\r\n\x05\x65mail\x18\x03 \x01(\t\x12\x1c\n\x14\x63urrentNumberOfUsers\x18\x04 \x01(\x05\x12\x15\n\rnumberOfUsers\x18\x05 \x01(\x05\x12\x18\n\x10subscriptionCode\x18\x07 \x01(\t\x12\x16\n\x0e\x65xpirationDate\x18\x08 \x01(\t\x12\x14\n\x0cpurchaseDate\x18\t \x01(\tB*\n\x18\x63om.keepersecurity.protoB\x0e\x41\x63\x63ountSummaryb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'AccountSummary_pb2', _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'accountsummary_pb2', _globals) if not _descriptor._USE_C_DESCRIPTORS: _globals['DESCRIPTOR']._loaded_options = None _globals['DESCRIPTOR']._serialized_options = b'\n\030com.keepersecurity.protoB\016AccountSummary' diff --git a/keepercommander/proto/AccountSummary_pb2.pyi b/keepercommander/proto/AccountSummary_pb2.pyi index 380597751..0121aa9b2 100644 --- a/keepercommander/proto/AccountSummary_pb2.pyi +++ b/keepercommander/proto/AccountSummary_pb2.pyi @@ -12,7 +12,7 @@ class AccountSummaryRequest(_message.Message): INCLUDERECENTACTIVITY_FIELD_NUMBER: _ClassVar[int] summaryVersion: int includeRecentActivity: bool - def __init__(self, summaryVersion: _Optional[int] = ..., includeRecentActivity: bool = ...) -> None: ... + def __init__(self, summaryVersion: _Optional[int] = ..., includeRecentActivity: _Optional[bool] = ...) -> None: ... class AccountSummaryElements(_message.Message): __slots__ = ("clientKey", "settings", "keysInfo", "syncLogs", "isEnterpriseAdmin", "license", "group", "Enforcements", "Images", "personalLicense", "fixSharedFolderRecords", "usernames", "devices", "isShareAdmin", "accountRecovery", "accountRecoveryPrompt", "minMasterPasswordLengthNoPrompt", "forbidKeyType2", "forbidKeyType1", "disallowedFeatures") @@ -56,7 +56,7 @@ class AccountSummaryElements(_message.Message): forbidKeyType2: bool forbidKeyType1: bool disallowedFeatures: _containers.RepeatedScalarFieldContainer[str] - def __init__(self, clientKey: _Optional[bytes] = ..., settings: _Optional[_Union[Settings, _Mapping]] = ..., keysInfo: _Optional[_Union[KeysInfo, _Mapping]] = ..., syncLogs: _Optional[_Iterable[_Union[SyncLog, _Mapping]]] = ..., isEnterpriseAdmin: bool = ..., license: _Optional[_Union[License, _Mapping]] = ..., group: _Optional[_Union[Group, _Mapping]] = ..., Enforcements: _Optional[_Union[Enforcements, _Mapping]] = ..., Images: _Optional[_Iterable[_Union[KeyValue, _Mapping]]] = ..., personalLicense: _Optional[_Union[License, _Mapping]] = ..., fixSharedFolderRecords: bool = ..., usernames: _Optional[_Iterable[str]] = ..., devices: _Optional[_Iterable[_Union[DeviceInfo, _Mapping]]] = ..., isShareAdmin: bool = ..., accountRecovery: bool = ..., accountRecoveryPrompt: bool = ..., minMasterPasswordLengthNoPrompt: _Optional[int] = ..., forbidKeyType2: bool = ..., forbidKeyType1: bool = ..., disallowedFeatures: _Optional[_Iterable[str]] = ...) -> None: ... + def __init__(self, clientKey: _Optional[bytes] = ..., settings: _Optional[_Union[Settings, _Mapping]] = ..., keysInfo: _Optional[_Union[KeysInfo, _Mapping]] = ..., syncLogs: _Optional[_Iterable[_Union[SyncLog, _Mapping]]] = ..., isEnterpriseAdmin: _Optional[bool] = ..., license: _Optional[_Union[License, _Mapping]] = ..., group: _Optional[_Union[Group, _Mapping]] = ..., Enforcements: _Optional[_Union[Enforcements, _Mapping]] = ..., Images: _Optional[_Iterable[_Union[KeyValue, _Mapping]]] = ..., personalLicense: _Optional[_Union[License, _Mapping]] = ..., fixSharedFolderRecords: _Optional[bool] = ..., usernames: _Optional[_Iterable[str]] = ..., devices: _Optional[_Iterable[_Union[DeviceInfo, _Mapping]]] = ..., isShareAdmin: _Optional[bool] = ..., accountRecovery: _Optional[bool] = ..., accountRecoveryPrompt: _Optional[bool] = ..., minMasterPasswordLengthNoPrompt: _Optional[int] = ..., forbidKeyType2: _Optional[bool] = ..., forbidKeyType1: _Optional[bool] = ..., disallowedFeatures: _Optional[_Iterable[str]] = ...) -> None: ... class DeviceInfo(_message.Message): __slots__ = ("encryptedDeviceToken", "deviceName", "deviceStatus", "devicePublicKey", "encryptedDataKeyDoNotUse", "clientVersion", "username", "ipAddress", "approveRequestTime", "encryptedDataKeyPresent", "groupId", "devicePlatform", "clientFormFactor") @@ -86,7 +86,7 @@ class DeviceInfo(_message.Message): groupId: int devicePlatform: str clientFormFactor: _APIRequest_pb2.ClientFormFactor - def __init__(self, encryptedDeviceToken: _Optional[bytes] = ..., deviceName: _Optional[str] = ..., deviceStatus: _Optional[_Union[_APIRequest_pb2.DeviceStatus, str]] = ..., devicePublicKey: _Optional[bytes] = ..., encryptedDataKeyDoNotUse: _Optional[bytes] = ..., clientVersion: _Optional[str] = ..., username: _Optional[str] = ..., ipAddress: _Optional[str] = ..., approveRequestTime: _Optional[int] = ..., encryptedDataKeyPresent: bool = ..., groupId: _Optional[int] = ..., devicePlatform: _Optional[str] = ..., clientFormFactor: _Optional[_Union[_APIRequest_pb2.ClientFormFactor, str]] = ...) -> None: ... + def __init__(self, encryptedDeviceToken: _Optional[bytes] = ..., deviceName: _Optional[str] = ..., deviceStatus: _Optional[_Union[_APIRequest_pb2.DeviceStatus, str]] = ..., devicePublicKey: _Optional[bytes] = ..., encryptedDataKeyDoNotUse: _Optional[bytes] = ..., clientVersion: _Optional[str] = ..., username: _Optional[str] = ..., ipAddress: _Optional[str] = ..., approveRequestTime: _Optional[int] = ..., encryptedDataKeyPresent: _Optional[bool] = ..., groupId: _Optional[int] = ..., devicePlatform: _Optional[str] = ..., clientFormFactor: _Optional[_Union[_APIRequest_pb2.ClientFormFactor, str]] = ...) -> None: ... class KeysInfo(_message.Message): __slots__ = ("encryptionParams", "encryptedDataKey", "dataKeyBackupDate", "userAuthUid", "encryptedPrivateKey", "encryptedEccPrivateKey", "eccPublicKey") @@ -192,7 +192,7 @@ class License(_message.Message): pendingEnterprise: bool isPamEnabled: bool isKsmEnabled: bool - def __init__(self, subscriptionCode: _Optional[str] = ..., productTypeId: _Optional[int] = ..., productTypeName: _Optional[str] = ..., expirationDate: _Optional[str] = ..., secondsUntilExpiration: _Optional[int] = ..., maxDevices: _Optional[int] = ..., filePlanType: _Optional[int] = ..., bytesUsed: _Optional[int] = ..., bytesTotal: _Optional[int] = ..., secondsUntilStorageExpiration: _Optional[int] = ..., storageExpirationDate: _Optional[str] = ..., hasAutoRenewableAppstoreSubscription: bool = ..., accountType: _Optional[int] = ..., uploadsRemaining: _Optional[int] = ..., enterpriseId: _Optional[int] = ..., chatEnabled: bool = ..., auditAndReportingEnabled: bool = ..., breachWatchFeatureDisable: bool = ..., accountUid: _Optional[bytes] = ..., allowPersonalLicense: bool = ..., licensedBy: _Optional[str] = ..., email: _Optional[str] = ..., breachWatchEnabled: bool = ..., breachWatchScanned: bool = ..., breachWatchExpiration: _Optional[int] = ..., breachWatchDateCreated: _Optional[int] = ..., error: _Optional[_Union[Result, _Mapping]] = ..., expiration: _Optional[int] = ..., storageExpiration: _Optional[int] = ..., uploadsCount: _Optional[int] = ..., units: _Optional[int] = ..., pendingEnterprise: bool = ..., isPamEnabled: bool = ..., isKsmEnabled: bool = ...) -> None: ... + def __init__(self, subscriptionCode: _Optional[str] = ..., productTypeId: _Optional[int] = ..., productTypeName: _Optional[str] = ..., expirationDate: _Optional[str] = ..., secondsUntilExpiration: _Optional[int] = ..., maxDevices: _Optional[int] = ..., filePlanType: _Optional[int] = ..., bytesUsed: _Optional[int] = ..., bytesTotal: _Optional[int] = ..., secondsUntilStorageExpiration: _Optional[int] = ..., storageExpirationDate: _Optional[str] = ..., hasAutoRenewableAppstoreSubscription: _Optional[bool] = ..., accountType: _Optional[int] = ..., uploadsRemaining: _Optional[int] = ..., enterpriseId: _Optional[int] = ..., chatEnabled: _Optional[bool] = ..., auditAndReportingEnabled: _Optional[bool] = ..., breachWatchFeatureDisable: _Optional[bool] = ..., accountUid: _Optional[bytes] = ..., allowPersonalLicense: _Optional[bool] = ..., licensedBy: _Optional[str] = ..., email: _Optional[str] = ..., breachWatchEnabled: _Optional[bool] = ..., breachWatchScanned: _Optional[bool] = ..., breachWatchExpiration: _Optional[int] = ..., breachWatchDateCreated: _Optional[int] = ..., error: _Optional[_Union[Result, _Mapping]] = ..., expiration: _Optional[int] = ..., storageExpiration: _Optional[int] = ..., uploadsCount: _Optional[int] = ..., units: _Optional[int] = ..., pendingEnterprise: _Optional[bool] = ..., isPamEnabled: _Optional[bool] = ..., isKsmEnabled: _Optional[bool] = ...) -> None: ... class AddOn(_message.Message): __slots__ = ("licenseKeyId", "name", "expirationDate", "createdDate", "isTrial", "enabled", "scanned", "featureDisable") @@ -212,7 +212,7 @@ class AddOn(_message.Message): enabled: bool scanned: bool featureDisable: bool - def __init__(self, licenseKeyId: _Optional[int] = ..., name: _Optional[str] = ..., expirationDate: _Optional[int] = ..., createdDate: _Optional[int] = ..., isTrial: bool = ..., enabled: bool = ..., scanned: bool = ..., featureDisable: bool = ...) -> None: ... + def __init__(self, licenseKeyId: _Optional[int] = ..., name: _Optional[str] = ..., expirationDate: _Optional[int] = ..., createdDate: _Optional[int] = ..., isTrial: _Optional[bool] = ..., enabled: _Optional[bool] = ..., scanned: _Optional[bool] = ..., featureDisable: _Optional[bool] = ...) -> None: ... class Settings(_message.Message): __slots__ = ("audit", "mustPerformAccountShareBy", "shareAccountTo", "rules", "passwordRulesIntro", "autoBackupDays", "theme", "channel", "channelValue", "rsaConfigured", "emailVerified", "masterPasswordLastModified", "accountFolderKey", "securityKeys", "keyValues", "ssoUser", "onlineAccessOnly", "masterPasswordExpiry", "twoFactorRequired", "disallowExport", "restrictFiles", "restrictAllSharing", "restrictSharing", "restrictSharingIncomingAll", "restrictSharingIncomingEnterprise", "logoutTimer", "persistentLogin", "ipDisableAutoApprove", "shareDataKeyWithEccPublicKey", "shareDataKeyWithDevicePublicKey", "RecordTypesCounter", "RecordTypesEnterpriseCounter", "recordTypesEnabled", "canManageRecordTypes", "recordTypesPAMCounter", "logoutTimerMinutes", "securityKeysNoUserVerify", "channels", "personalUsernames", "maxIpDistance", "maxIpDistanceEffective") @@ -298,7 +298,7 @@ class Settings(_message.Message): personalUsernames: _containers.RepeatedScalarFieldContainer[str] maxIpDistance: int maxIpDistanceEffective: int - def __init__(self, audit: bool = ..., mustPerformAccountShareBy: _Optional[int] = ..., shareAccountTo: _Optional[_Iterable[_Union[MissingAccountShareKey, _Mapping]]] = ..., rules: _Optional[_Iterable[_Union[PasswordRule, _Mapping]]] = ..., passwordRulesIntro: _Optional[str] = ..., autoBackupDays: _Optional[int] = ..., theme: _Optional[str] = ..., channel: _Optional[str] = ..., channelValue: _Optional[str] = ..., rsaConfigured: bool = ..., emailVerified: bool = ..., masterPasswordLastModified: _Optional[float] = ..., accountFolderKey: _Optional[bytes] = ..., securityKeys: _Optional[_Iterable[_Union[SecurityKey, _Mapping]]] = ..., keyValues: _Optional[_Iterable[_Union[KeyValue, _Mapping]]] = ..., ssoUser: bool = ..., onlineAccessOnly: bool = ..., masterPasswordExpiry: _Optional[int] = ..., twoFactorRequired: bool = ..., disallowExport: bool = ..., restrictFiles: bool = ..., restrictAllSharing: bool = ..., restrictSharing: bool = ..., restrictSharingIncomingAll: bool = ..., restrictSharingIncomingEnterprise: bool = ..., logoutTimer: _Optional[int] = ..., persistentLogin: bool = ..., ipDisableAutoApprove: bool = ..., shareDataKeyWithEccPublicKey: bool = ..., shareDataKeyWithDevicePublicKey: bool = ..., RecordTypesCounter: _Optional[int] = ..., RecordTypesEnterpriseCounter: _Optional[int] = ..., recordTypesEnabled: bool = ..., canManageRecordTypes: bool = ..., recordTypesPAMCounter: _Optional[int] = ..., logoutTimerMinutes: _Optional[int] = ..., securityKeysNoUserVerify: bool = ..., channels: _Optional[_Iterable[_Union[_APIRequest_pb2.TwoFactorChannelType, str]]] = ..., personalUsernames: _Optional[_Iterable[str]] = ..., maxIpDistance: _Optional[int] = ..., maxIpDistanceEffective: _Optional[int] = ...) -> None: ... + def __init__(self, audit: _Optional[bool] = ..., mustPerformAccountShareBy: _Optional[int] = ..., shareAccountTo: _Optional[_Iterable[_Union[MissingAccountShareKey, _Mapping]]] = ..., rules: _Optional[_Iterable[_Union[PasswordRule, _Mapping]]] = ..., passwordRulesIntro: _Optional[str] = ..., autoBackupDays: _Optional[int] = ..., theme: _Optional[str] = ..., channel: _Optional[str] = ..., channelValue: _Optional[str] = ..., rsaConfigured: _Optional[bool] = ..., emailVerified: _Optional[bool] = ..., masterPasswordLastModified: _Optional[float] = ..., accountFolderKey: _Optional[bytes] = ..., securityKeys: _Optional[_Iterable[_Union[SecurityKey, _Mapping]]] = ..., keyValues: _Optional[_Iterable[_Union[KeyValue, _Mapping]]] = ..., ssoUser: _Optional[bool] = ..., onlineAccessOnly: _Optional[bool] = ..., masterPasswordExpiry: _Optional[int] = ..., twoFactorRequired: _Optional[bool] = ..., disallowExport: _Optional[bool] = ..., restrictFiles: _Optional[bool] = ..., restrictAllSharing: _Optional[bool] = ..., restrictSharing: _Optional[bool] = ..., restrictSharingIncomingAll: _Optional[bool] = ..., restrictSharingIncomingEnterprise: _Optional[bool] = ..., logoutTimer: _Optional[int] = ..., persistentLogin: _Optional[bool] = ..., ipDisableAutoApprove: _Optional[bool] = ..., shareDataKeyWithEccPublicKey: _Optional[bool] = ..., shareDataKeyWithDevicePublicKey: _Optional[bool] = ..., RecordTypesCounter: _Optional[int] = ..., RecordTypesEnterpriseCounter: _Optional[int] = ..., recordTypesEnabled: _Optional[bool] = ..., canManageRecordTypes: _Optional[bool] = ..., recordTypesPAMCounter: _Optional[int] = ..., logoutTimerMinutes: _Optional[int] = ..., securityKeysNoUserVerify: _Optional[bool] = ..., channels: _Optional[_Iterable[_Union[_APIRequest_pb2.TwoFactorChannelType, str]]] = ..., personalUsernames: _Optional[_Iterable[str]] = ..., maxIpDistance: _Optional[int] = ..., maxIpDistanceEffective: _Optional[int] = ...) -> None: ... class KeyValue(_message.Message): __slots__ = ("key", "value") @@ -314,7 +314,7 @@ class KeyValueBoolean(_message.Message): VALUE_FIELD_NUMBER: _ClassVar[int] key: str value: bool - def __init__(self, key: _Optional[str] = ..., value: bool = ...) -> None: ... + def __init__(self, key: _Optional[str] = ..., value: _Optional[bool] = ...) -> None: ... class KeyValueLong(_message.Message): __slots__ = ("key", "value") @@ -368,7 +368,7 @@ class PasswordRule(_message.Message): minimum: int description: str value: str - def __init__(self, ruleType: _Optional[str] = ..., pattern: _Optional[str] = ..., match: bool = ..., minimum: _Optional[int] = ..., description: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... + def __init__(self, ruleType: _Optional[str] = ..., pattern: _Optional[str] = ..., match: _Optional[bool] = ..., minimum: _Optional[int] = ..., description: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... class SecurityKey(_message.Message): __slots__ = ("deviceId", "deviceName", "dateAdded", "isValid", "deviceRegistration") @@ -382,7 +382,7 @@ class SecurityKey(_message.Message): dateAdded: int isValid: bool deviceRegistration: DeviceRegistration - def __init__(self, deviceId: _Optional[int] = ..., deviceName: _Optional[str] = ..., dateAdded: _Optional[int] = ..., isValid: bool = ..., deviceRegistration: _Optional[_Union[DeviceRegistration, _Mapping]] = ...) -> None: ... + def __init__(self, deviceId: _Optional[int] = ..., deviceName: _Optional[str] = ..., dateAdded: _Optional[int] = ..., isValid: _Optional[bool] = ..., deviceRegistration: _Optional[_Union[DeviceRegistration, _Mapping]] = ...) -> None: ... class DeviceRegistration(_message.Message): __slots__ = ("keyHandle", "publicKey", "attestationCert", "counter", "compromised") @@ -396,7 +396,7 @@ class DeviceRegistration(_message.Message): attestationCert: str counter: int compromised: bool - def __init__(self, keyHandle: _Optional[str] = ..., publicKey: _Optional[bytes] = ..., attestationCert: _Optional[str] = ..., counter: _Optional[int] = ..., compromised: bool = ...) -> None: ... + def __init__(self, keyHandle: _Optional[str] = ..., publicKey: _Optional[bytes] = ..., attestationCert: _Optional[str] = ..., counter: _Optional[int] = ..., compromised: _Optional[bool] = ...) -> None: ... class Group(_message.Message): __slots__ = ("admin", "groupVerificationCode", "administrator") @@ -406,7 +406,7 @@ class Group(_message.Message): admin: bool groupVerificationCode: str administrator: Administrator - def __init__(self, admin: bool = ..., groupVerificationCode: _Optional[str] = ..., administrator: _Optional[_Union[Administrator, _Mapping]] = ...) -> None: ... + def __init__(self, admin: _Optional[bool] = ..., groupVerificationCode: _Optional[str] = ..., administrator: _Optional[_Union[Administrator, _Mapping]] = ...) -> None: ... class Administrator(_message.Message): __slots__ = ("firstName", "lastName", "email", "currentNumberOfUsers", "numberOfUsers", "subscriptionCode", "expirationDate", "purchaseDate") diff --git a/keepercommander/proto/GraphSync_pb2.pyi b/keepercommander/proto/GraphSync_pb2.pyi index 594a4eecc..a8e0514cd 100644 --- a/keepercommander/proto/GraphSync_pb2.pyi +++ b/keepercommander/proto/GraphSync_pb2.pyi @@ -137,7 +137,7 @@ class GraphSyncResult(_message.Message): syncPoint: int data: _containers.RepeatedCompositeFieldContainer[GraphSyncDataPlus] hasMore: bool - def __init__(self, streamId: _Optional[bytes] = ..., syncPoint: _Optional[int] = ..., data: _Optional[_Iterable[_Union[GraphSyncDataPlus, _Mapping]]] = ..., hasMore: bool = ...) -> None: ... + def __init__(self, streamId: _Optional[bytes] = ..., syncPoint: _Optional[int] = ..., data: _Optional[_Iterable[_Union[GraphSyncDataPlus, _Mapping]]] = ..., hasMore: _Optional[bool] = ...) -> None: ... class GraphSyncMultiQuery(_message.Message): __slots__ = ("queries",) diff --git a/keepercommander/proto/SyncDown_pb2.pyi b/keepercommander/proto/SyncDown_pb2.pyi index 8c1b62221..ea2677653 100644 --- a/keepercommander/proto/SyncDown_pb2.pyi +++ b/keepercommander/proto/SyncDown_pb2.pyi @@ -40,7 +40,7 @@ class SyncDownRequest(_message.Message): continuationToken: bytes dataVersion: int debug: bool - def __init__(self, continuationToken: _Optional[bytes] = ..., dataVersion: _Optional[int] = ..., debug: bool = ...) -> None: ... + def __init__(self, continuationToken: _Optional[bytes] = ..., dataVersion: _Optional[int] = ..., debug: _Optional[bool] = ...) -> None: ... class SyncDownResponse(_message.Message): __slots__ = ("continuationToken", "hasMore", "cacheStatus", "userFolders", "sharedFolders", "userFolderSharedFolders", "sharedFolderFolders", "records", "recordMetaData", "nonSharedData", "recordLinks", "userFolderRecords", "sharedFolderRecords", "sharedFolderFolderRecords", "sharedFolderUsers", "sharedFolderTeams", "recordAddAuditData", "teams", "sharingChanges", "profile", "profilePic", "pendingTeamMembers", "breachWatchRecords", "userAuths", "breachWatchSecurityData", "reusedPasswords", "removedUserFolders", "removedSharedFolders", "removedUserFolderSharedFolders", "removedSharedFolderFolders", "removedRecords", "removedRecordLinks", "removedUserFolderRecords", "removedSharedFolderRecords", "removedSharedFolderFolderRecords", "removedSharedFolderUsers", "removedSharedFolderTeams", "removedTeams", "ksmAppShares", "ksmAppClients", "shareInvitations", "diagnostics", "recordRotations", "users", "removedUsers", "securityScoreData", "notificationSync", "keeperDriveData") @@ -140,7 +140,7 @@ class SyncDownResponse(_message.Message): securityScoreData: _containers.RepeatedCompositeFieldContainer[SecurityScoreData] notificationSync: _containers.RepeatedCompositeFieldContainer[_NotificationCenter_pb2.NotificationWrapper] keeperDriveData: KeeperDriveData - def __init__(self, continuationToken: _Optional[bytes] = ..., hasMore: bool = ..., cacheStatus: _Optional[_Union[CacheStatus, str]] = ..., userFolders: _Optional[_Iterable[_Union[UserFolder, _Mapping]]] = ..., sharedFolders: _Optional[_Iterable[_Union[SharedFolder, _Mapping]]] = ..., userFolderSharedFolders: _Optional[_Iterable[_Union[UserFolderSharedFolder, _Mapping]]] = ..., sharedFolderFolders: _Optional[_Iterable[_Union[SharedFolderFolder, _Mapping]]] = ..., records: _Optional[_Iterable[_Union[Record, _Mapping]]] = ..., recordMetaData: _Optional[_Iterable[_Union[RecordMetaData, _Mapping]]] = ..., nonSharedData: _Optional[_Iterable[_Union[NonSharedData, _Mapping]]] = ..., recordLinks: _Optional[_Iterable[_Union[RecordLink, _Mapping]]] = ..., userFolderRecords: _Optional[_Iterable[_Union[UserFolderRecord, _Mapping]]] = ..., sharedFolderRecords: _Optional[_Iterable[_Union[SharedFolderRecord, _Mapping]]] = ..., sharedFolderFolderRecords: _Optional[_Iterable[_Union[SharedFolderFolderRecord, _Mapping]]] = ..., sharedFolderUsers: _Optional[_Iterable[_Union[SharedFolderUser, _Mapping]]] = ..., sharedFolderTeams: _Optional[_Iterable[_Union[SharedFolderTeam, _Mapping]]] = ..., recordAddAuditData: _Optional[_Iterable[bytes]] = ..., teams: _Optional[_Iterable[_Union[Team, _Mapping]]] = ..., sharingChanges: _Optional[_Iterable[_Union[SharingChange, _Mapping]]] = ..., profile: _Optional[_Union[Profile, _Mapping]] = ..., profilePic: _Optional[_Union[ProfilePic, _Mapping]] = ..., pendingTeamMembers: _Optional[_Iterable[_Union[PendingTeamMember, _Mapping]]] = ..., breachWatchRecords: _Optional[_Iterable[_Union[BreachWatchRecord, _Mapping]]] = ..., userAuths: _Optional[_Iterable[_Union[UserAuth, _Mapping]]] = ..., breachWatchSecurityData: _Optional[_Iterable[_Union[BreachWatchSecurityData, _Mapping]]] = ..., reusedPasswords: _Optional[_Union[ReusedPasswords, _Mapping]] = ..., removedUserFolders: _Optional[_Iterable[bytes]] = ..., removedSharedFolders: _Optional[_Iterable[bytes]] = ..., removedUserFolderSharedFolders: _Optional[_Iterable[_Union[UserFolderSharedFolder, _Mapping]]] = ..., removedSharedFolderFolders: _Optional[_Iterable[_Union[SharedFolderFolder, _Mapping]]] = ..., removedRecords: _Optional[_Iterable[bytes]] = ..., removedRecordLinks: _Optional[_Iterable[_Union[RecordLink, _Mapping]]] = ..., removedUserFolderRecords: _Optional[_Iterable[_Union[UserFolderRecord, _Mapping]]] = ..., removedSharedFolderRecords: _Optional[_Iterable[_Union[SharedFolderRecord, _Mapping]]] = ..., removedSharedFolderFolderRecords: _Optional[_Iterable[_Union[SharedFolderFolderRecord, _Mapping]]] = ..., removedSharedFolderUsers: _Optional[_Iterable[_Union[SharedFolderUser, _Mapping]]] = ..., removedSharedFolderTeams: _Optional[_Iterable[_Union[SharedFolderTeam, _Mapping]]] = ..., removedTeams: _Optional[_Iterable[bytes]] = ..., ksmAppShares: _Optional[_Iterable[_Union[KsmChange, _Mapping]]] = ..., ksmAppClients: _Optional[_Iterable[_Union[KsmChange, _Mapping]]] = ..., shareInvitations: _Optional[_Iterable[_Union[ShareInvitation, _Mapping]]] = ..., diagnostics: _Optional[_Union[SyncDiagnostics, _Mapping]] = ..., recordRotations: _Optional[_Iterable[_Union[RecordRotation, _Mapping]]] = ..., users: _Optional[_Iterable[_Union[User, _Mapping]]] = ..., removedUsers: _Optional[_Iterable[bytes]] = ..., securityScoreData: _Optional[_Iterable[_Union[SecurityScoreData, _Mapping]]] = ..., notificationSync: _Optional[_Iterable[_Union[_NotificationCenter_pb2.NotificationWrapper, _Mapping]]] = ..., keeperDriveData: _Optional[_Union[KeeperDriveData, _Mapping]] = ...) -> None: ... + def __init__(self, continuationToken: _Optional[bytes] = ..., hasMore: _Optional[bool] = ..., cacheStatus: _Optional[_Union[CacheStatus, str]] = ..., userFolders: _Optional[_Iterable[_Union[UserFolder, _Mapping]]] = ..., sharedFolders: _Optional[_Iterable[_Union[SharedFolder, _Mapping]]] = ..., userFolderSharedFolders: _Optional[_Iterable[_Union[UserFolderSharedFolder, _Mapping]]] = ..., sharedFolderFolders: _Optional[_Iterable[_Union[SharedFolderFolder, _Mapping]]] = ..., records: _Optional[_Iterable[_Union[Record, _Mapping]]] = ..., recordMetaData: _Optional[_Iterable[_Union[RecordMetaData, _Mapping]]] = ..., nonSharedData: _Optional[_Iterable[_Union[NonSharedData, _Mapping]]] = ..., recordLinks: _Optional[_Iterable[_Union[RecordLink, _Mapping]]] = ..., userFolderRecords: _Optional[_Iterable[_Union[UserFolderRecord, _Mapping]]] = ..., sharedFolderRecords: _Optional[_Iterable[_Union[SharedFolderRecord, _Mapping]]] = ..., sharedFolderFolderRecords: _Optional[_Iterable[_Union[SharedFolderFolderRecord, _Mapping]]] = ..., sharedFolderUsers: _Optional[_Iterable[_Union[SharedFolderUser, _Mapping]]] = ..., sharedFolderTeams: _Optional[_Iterable[_Union[SharedFolderTeam, _Mapping]]] = ..., recordAddAuditData: _Optional[_Iterable[bytes]] = ..., teams: _Optional[_Iterable[_Union[Team, _Mapping]]] = ..., sharingChanges: _Optional[_Iterable[_Union[SharingChange, _Mapping]]] = ..., profile: _Optional[_Union[Profile, _Mapping]] = ..., profilePic: _Optional[_Union[ProfilePic, _Mapping]] = ..., pendingTeamMembers: _Optional[_Iterable[_Union[PendingTeamMember, _Mapping]]] = ..., breachWatchRecords: _Optional[_Iterable[_Union[BreachWatchRecord, _Mapping]]] = ..., userAuths: _Optional[_Iterable[_Union[UserAuth, _Mapping]]] = ..., breachWatchSecurityData: _Optional[_Iterable[_Union[BreachWatchSecurityData, _Mapping]]] = ..., reusedPasswords: _Optional[_Union[ReusedPasswords, _Mapping]] = ..., removedUserFolders: _Optional[_Iterable[bytes]] = ..., removedSharedFolders: _Optional[_Iterable[bytes]] = ..., removedUserFolderSharedFolders: _Optional[_Iterable[_Union[UserFolderSharedFolder, _Mapping]]] = ..., removedSharedFolderFolders: _Optional[_Iterable[_Union[SharedFolderFolder, _Mapping]]] = ..., removedRecords: _Optional[_Iterable[bytes]] = ..., removedRecordLinks: _Optional[_Iterable[_Union[RecordLink, _Mapping]]] = ..., removedUserFolderRecords: _Optional[_Iterable[_Union[UserFolderRecord, _Mapping]]] = ..., removedSharedFolderRecords: _Optional[_Iterable[_Union[SharedFolderRecord, _Mapping]]] = ..., removedSharedFolderFolderRecords: _Optional[_Iterable[_Union[SharedFolderFolderRecord, _Mapping]]] = ..., removedSharedFolderUsers: _Optional[_Iterable[_Union[SharedFolderUser, _Mapping]]] = ..., removedSharedFolderTeams: _Optional[_Iterable[_Union[SharedFolderTeam, _Mapping]]] = ..., removedTeams: _Optional[_Iterable[bytes]] = ..., ksmAppShares: _Optional[_Iterable[_Union[KsmChange, _Mapping]]] = ..., ksmAppClients: _Optional[_Iterable[_Union[KsmChange, _Mapping]]] = ..., shareInvitations: _Optional[_Iterable[_Union[ShareInvitation, _Mapping]]] = ..., diagnostics: _Optional[_Union[SyncDiagnostics, _Mapping]] = ..., recordRotations: _Optional[_Iterable[_Union[RecordRotation, _Mapping]]] = ..., users: _Optional[_Iterable[_Union[User, _Mapping]]] = ..., removedUsers: _Optional[_Iterable[bytes]] = ..., securityScoreData: _Optional[_Iterable[_Union[SecurityScoreData, _Mapping]]] = ..., notificationSync: _Optional[_Iterable[_Union[_NotificationCenter_pb2.NotificationWrapper, _Mapping]]] = ..., keeperDriveData: _Optional[_Union[KeeperDriveData, _Mapping]] = ...) -> None: ... class DriveRecord(_message.Message): __slots__ = ("recordUid", "revision", "version", "shared", "clientModifiedTime", "fileSize", "thumbnailSize") @@ -158,7 +158,7 @@ class DriveRecord(_message.Message): clientModifiedTime: int fileSize: int thumbnailSize: int - def __init__(self, recordUid: _Optional[bytes] = ..., revision: _Optional[int] = ..., version: _Optional[int] = ..., shared: bool = ..., clientModifiedTime: _Optional[int] = ..., fileSize: _Optional[int] = ..., thumbnailSize: _Optional[int] = ...) -> None: ... + def __init__(self, recordUid: _Optional[bytes] = ..., revision: _Optional[int] = ..., version: _Optional[int] = ..., shared: _Optional[bool] = ..., clientModifiedTime: _Optional[int] = ..., fileSize: _Optional[int] = ..., thumbnailSize: _Optional[int] = ...) -> None: ... class FolderSharingState(_message.Message): __slots__ = ("folderUid", "shared", "count") @@ -168,7 +168,7 @@ class FolderSharingState(_message.Message): folderUid: bytes shared: bool count: int - def __init__(self, folderUid: _Optional[bytes] = ..., shared: bool = ..., count: _Optional[int] = ...) -> None: ... + def __init__(self, folderUid: _Optional[bytes] = ..., shared: _Optional[bool] = ..., count: _Optional[int] = ...) -> None: ... class KeeperDriveData(_message.Message): __slots__ = ("folders", "folderKeys", "folderAccesses", "revokedFolderAccesses", "recordData", "nonSharedData", "recordAccesses", "revokedRecordAccesses", "recordSharingStates", "recordLinks", "removedRecordLinks", "breachWatchRecords", "securityScoreData", "breachWatchSecurityData", "removedFolders", "removedFolderRecords", "folderRecords", "recordRotationData", "records", "folderSharingState", "rawDagData") @@ -260,7 +260,7 @@ class SharedFolder(_message.Message): owner: str ownerAccountUid: bytes name: bytes - def __init__(self, sharedFolderUid: _Optional[bytes] = ..., revision: _Optional[int] = ..., sharedFolderKey: _Optional[bytes] = ..., keyType: _Optional[_Union[_record_pb2.RecordKeyType, str]] = ..., data: _Optional[bytes] = ..., defaultManageRecords: bool = ..., defaultManageUsers: bool = ..., defaultCanEdit: bool = ..., defaultCanReshare: bool = ..., cacheStatus: _Optional[_Union[CacheStatus, str]] = ..., owner: _Optional[str] = ..., ownerAccountUid: _Optional[bytes] = ..., name: _Optional[bytes] = ...) -> None: ... + def __init__(self, sharedFolderUid: _Optional[bytes] = ..., revision: _Optional[int] = ..., sharedFolderKey: _Optional[bytes] = ..., keyType: _Optional[_Union[_record_pb2.RecordKeyType, str]] = ..., data: _Optional[bytes] = ..., defaultManageRecords: _Optional[bool] = ..., defaultManageUsers: _Optional[bool] = ..., defaultCanEdit: _Optional[bool] = ..., defaultCanReshare: _Optional[bool] = ..., cacheStatus: _Optional[_Union[CacheStatus, str]] = ..., owner: _Optional[str] = ..., ownerAccountUid: _Optional[bytes] = ..., name: _Optional[bytes] = ...) -> None: ... class UserFolderSharedFolder(_message.Message): __slots__ = ("folderUid", "sharedFolderUid", "revision") @@ -326,7 +326,7 @@ class Team(_message.Message): sharedFolderKeys: _containers.RepeatedCompositeFieldContainer[SharedFolderKey] teamEccPrivateKey: bytes teamEccPublicKey: bytes - def __init__(self, teamUid: _Optional[bytes] = ..., name: _Optional[str] = ..., teamKey: _Optional[bytes] = ..., teamKeyType: _Optional[_Union[_record_pb2.RecordKeyType, str]] = ..., teamPrivateKey: _Optional[bytes] = ..., restrictEdit: bool = ..., restrictShare: bool = ..., restrictView: bool = ..., removedSharedFolders: _Optional[_Iterable[bytes]] = ..., sharedFolderKeys: _Optional[_Iterable[_Union[SharedFolderKey, _Mapping]]] = ..., teamEccPrivateKey: _Optional[bytes] = ..., teamEccPublicKey: _Optional[bytes] = ...) -> None: ... + def __init__(self, teamUid: _Optional[bytes] = ..., name: _Optional[str] = ..., teamKey: _Optional[bytes] = ..., teamKeyType: _Optional[_Union[_record_pb2.RecordKeyType, str]] = ..., teamPrivateKey: _Optional[bytes] = ..., restrictEdit: _Optional[bool] = ..., restrictShare: _Optional[bool] = ..., restrictView: _Optional[bool] = ..., removedSharedFolders: _Optional[_Iterable[bytes]] = ..., sharedFolderKeys: _Optional[_Iterable[_Union[SharedFolderKey, _Mapping]]] = ..., teamEccPrivateKey: _Optional[bytes] = ..., teamEccPublicKey: _Optional[bytes] = ...) -> None: ... class Record(_message.Message): __slots__ = ("recordUid", "revision", "version", "shared", "clientModifiedTime", "data", "extra", "udata", "fileSize", "thumbnailSize") @@ -350,7 +350,7 @@ class Record(_message.Message): udata: str fileSize: int thumbnailSize: int - def __init__(self, recordUid: _Optional[bytes] = ..., revision: _Optional[int] = ..., version: _Optional[int] = ..., shared: bool = ..., clientModifiedTime: _Optional[int] = ..., data: _Optional[bytes] = ..., extra: _Optional[bytes] = ..., udata: _Optional[str] = ..., fileSize: _Optional[int] = ..., thumbnailSize: _Optional[int] = ...) -> None: ... + def __init__(self, recordUid: _Optional[bytes] = ..., revision: _Optional[int] = ..., version: _Optional[int] = ..., shared: _Optional[bool] = ..., clientModifiedTime: _Optional[int] = ..., data: _Optional[bytes] = ..., extra: _Optional[bytes] = ..., udata: _Optional[str] = ..., fileSize: _Optional[int] = ..., thumbnailSize: _Optional[int] = ...) -> None: ... class RecordLink(_message.Message): __slots__ = ("parentRecordUid", "childRecordUid", "recordKey", "revision") @@ -416,7 +416,7 @@ class RecordMetaData(_message.Message): expiration: int expirationNotificationType: _record_pb2.TimerNotificationType ownerUsername: str - def __init__(self, recordUid: _Optional[bytes] = ..., owner: bool = ..., recordKey: _Optional[bytes] = ..., recordKeyType: _Optional[_Union[_record_pb2.RecordKeyType, str]] = ..., canShare: bool = ..., canEdit: bool = ..., ownerAccountUid: _Optional[bytes] = ..., expiration: _Optional[int] = ..., expirationNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., ownerUsername: _Optional[str] = ...) -> None: ... + def __init__(self, recordUid: _Optional[bytes] = ..., owner: _Optional[bool] = ..., recordKey: _Optional[bytes] = ..., recordKeyType: _Optional[_Union[_record_pb2.RecordKeyType, str]] = ..., canShare: _Optional[bool] = ..., canEdit: _Optional[bool] = ..., ownerAccountUid: _Optional[bytes] = ..., expiration: _Optional[int] = ..., expirationNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., ownerUsername: _Optional[str] = ...) -> None: ... class SharingChange(_message.Message): __slots__ = ("recordUid", "shared") @@ -424,7 +424,7 @@ class SharingChange(_message.Message): SHARED_FIELD_NUMBER: _ClassVar[int] recordUid: bytes shared: bool - def __init__(self, recordUid: _Optional[bytes] = ..., shared: bool = ...) -> None: ... + def __init__(self, recordUid: _Optional[bytes] = ..., shared: _Optional[bool] = ...) -> None: ... class Profile(_message.Message): __slots__ = ("data", "profileName", "revision") @@ -490,7 +490,7 @@ class UserAuth(_message.Message): encryptedClientKey: bytes revision: int name: str - def __init__(self, uid: _Optional[bytes] = ..., loginType: _Optional[_Union[_APIRequest_pb2.LoginType, str]] = ..., deleted: bool = ..., iterations: _Optional[int] = ..., salt: _Optional[bytes] = ..., encryptedClientKey: _Optional[bytes] = ..., revision: _Optional[int] = ..., name: _Optional[str] = ...) -> None: ... + def __init__(self, uid: _Optional[bytes] = ..., loginType: _Optional[_Union[_APIRequest_pb2.LoginType, str]] = ..., deleted: _Optional[bool] = ..., iterations: _Optional[int] = ..., salt: _Optional[bytes] = ..., encryptedClientKey: _Optional[bytes] = ..., revision: _Optional[int] = ..., name: _Optional[str] = ...) -> None: ... class BreachWatchSecurityData(_message.Message): __slots__ = ("recordUid", "revision", "removed") @@ -500,7 +500,7 @@ class BreachWatchSecurityData(_message.Message): recordUid: bytes revision: int removed: bool - def __init__(self, recordUid: _Optional[bytes] = ..., revision: _Optional[int] = ..., removed: bool = ...) -> None: ... + def __init__(self, recordUid: _Optional[bytes] = ..., revision: _Optional[int] = ..., removed: _Optional[bool] = ...) -> None: ... class ReusedPasswords(_message.Message): __slots__ = ("count", "revision") @@ -534,7 +534,7 @@ class SharedFolderRecord(_message.Message): expirationNotificationType: _record_pb2.TimerNotificationType ownerUsername: str rotateOnExpiration: bool - def __init__(self, sharedFolderUid: _Optional[bytes] = ..., recordUid: _Optional[bytes] = ..., recordKey: _Optional[bytes] = ..., canShare: bool = ..., canEdit: bool = ..., ownerAccountUid: _Optional[bytes] = ..., expiration: _Optional[int] = ..., owner: bool = ..., expirationNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., ownerUsername: _Optional[str] = ..., rotateOnExpiration: bool = ...) -> None: ... + def __init__(self, sharedFolderUid: _Optional[bytes] = ..., recordUid: _Optional[bytes] = ..., recordKey: _Optional[bytes] = ..., canShare: _Optional[bool] = ..., canEdit: _Optional[bool] = ..., ownerAccountUid: _Optional[bytes] = ..., expiration: _Optional[int] = ..., owner: _Optional[bool] = ..., expirationNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., ownerUsername: _Optional[str] = ..., rotateOnExpiration: _Optional[bool] = ...) -> None: ... class SharedFolderUser(_message.Message): __slots__ = ("sharedFolderUid", "username", "manageRecords", "manageUsers", "accountUid", "expiration", "expirationNotificationType", "rotateOnExpiration") @@ -554,7 +554,7 @@ class SharedFolderUser(_message.Message): expiration: int expirationNotificationType: _record_pb2.TimerNotificationType rotateOnExpiration: bool - def __init__(self, sharedFolderUid: _Optional[bytes] = ..., username: _Optional[str] = ..., manageRecords: bool = ..., manageUsers: bool = ..., accountUid: _Optional[bytes] = ..., expiration: _Optional[int] = ..., expirationNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., rotateOnExpiration: bool = ...) -> None: ... + def __init__(self, sharedFolderUid: _Optional[bytes] = ..., username: _Optional[str] = ..., manageRecords: _Optional[bool] = ..., manageUsers: _Optional[bool] = ..., accountUid: _Optional[bytes] = ..., expiration: _Optional[int] = ..., expirationNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., rotateOnExpiration: _Optional[bool] = ...) -> None: ... class SharedFolderTeam(_message.Message): __slots__ = ("sharedFolderUid", "teamUid", "name", "manageRecords", "manageUsers", "expiration", "expirationNotificationType", "rotateOnExpiration") @@ -574,7 +574,7 @@ class SharedFolderTeam(_message.Message): expiration: int expirationNotificationType: _record_pb2.TimerNotificationType rotateOnExpiration: bool - def __init__(self, sharedFolderUid: _Optional[bytes] = ..., teamUid: _Optional[bytes] = ..., name: _Optional[str] = ..., manageRecords: bool = ..., manageUsers: bool = ..., expiration: _Optional[int] = ..., expirationNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., rotateOnExpiration: bool = ...) -> None: ... + def __init__(self, sharedFolderUid: _Optional[bytes] = ..., teamUid: _Optional[bytes] = ..., name: _Optional[str] = ..., manageRecords: _Optional[bool] = ..., manageUsers: _Optional[bool] = ..., expiration: _Optional[int] = ..., expirationNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., rotateOnExpiration: _Optional[bool] = ...) -> None: ... class KsmChange(_message.Message): __slots__ = ("appRecordUid", "detailId", "removed", "appClientType", "expiration") @@ -588,7 +588,7 @@ class KsmChange(_message.Message): removed: bool appClientType: _enterprise_pb2.AppClientType expiration: int - def __init__(self, appRecordUid: _Optional[bytes] = ..., detailId: _Optional[bytes] = ..., removed: bool = ..., appClientType: _Optional[_Union[_enterprise_pb2.AppClientType, str]] = ..., expiration: _Optional[int] = ...) -> None: ... + def __init__(self, appRecordUid: _Optional[bytes] = ..., detailId: _Optional[bytes] = ..., removed: _Optional[bool] = ..., appClientType: _Optional[_Union[_enterprise_pb2.AppClientType, str]] = ..., expiration: _Optional[int] = ...) -> None: ... class ShareInvitation(_message.Message): __slots__ = ("username",) @@ -638,7 +638,7 @@ class RecordRotation(_message.Message): resourceUid: bytes lastRotation: int lastRotationStatus: RecordRotationStatus - def __init__(self, recordUid: _Optional[bytes] = ..., revision: _Optional[int] = ..., configurationUid: _Optional[bytes] = ..., schedule: _Optional[str] = ..., pwdComplexity: _Optional[bytes] = ..., disabled: bool = ..., resourceUid: _Optional[bytes] = ..., lastRotation: _Optional[int] = ..., lastRotationStatus: _Optional[_Union[RecordRotationStatus, str]] = ...) -> None: ... + def __init__(self, recordUid: _Optional[bytes] = ..., revision: _Optional[int] = ..., configurationUid: _Optional[bytes] = ..., schedule: _Optional[str] = ..., pwdComplexity: _Optional[bytes] = ..., disabled: _Optional[bool] = ..., resourceUid: _Optional[bytes] = ..., lastRotation: _Optional[int] = ..., lastRotationStatus: _Optional[_Union[RecordRotationStatus, str]] = ...) -> None: ... class SecurityScoreData(_message.Message): __slots__ = ("recordUid", "data", "revision") diff --git a/keepercommander/proto/dag_pb2.pyi b/keepercommander/proto/dag_pb2.pyi index 8738ef405..6896c5d7b 100644 --- a/keepercommander/proto/dag_pb2.pyi +++ b/keepercommander/proto/dag_pb2.pyi @@ -78,7 +78,7 @@ class SyncData(_message.Message): data: _containers.RepeatedCompositeFieldContainer[Data] syncPoint: int hasMore: bool - def __init__(self, data: _Optional[_Iterable[_Union[Data, _Mapping]]] = ..., syncPoint: _Optional[int] = ..., hasMore: bool = ...) -> None: ... + def __init__(self, data: _Optional[_Iterable[_Union[Data, _Mapping]]] = ..., syncPoint: _Optional[int] = ..., hasMore: _Optional[bool] = ...) -> None: ... class DebugData(_message.Message): __slots__ = ("dataType", "path", "ref", "parentRef") diff --git a/keepercommander/proto/enterprise_pb2.py b/keepercommander/proto/enterprise_pb2.py index 63c28ba73..b0dc5120f 100644 --- a/keepercommander/proto/enterprise_pb2.py +++ b/keepercommander/proto/enterprise_pb2.py @@ -22,9 +22,10 @@ _sym_db = _symbol_database.Default() +from . import folder_pb2 as folder__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10\x65nterprise.proto\x12\nEnterprise\"\x84\x01\n\x18\x45nterpriseKeyPairRequest\x12\x1b\n\x13\x65nterprisePublicKey\x18\x01 \x01(\x0c\x12%\n\x1d\x65ncryptedEnterprisePrivateKey\x18\x02 \x01(\x0c\x12$\n\x07keyType\x18\x03 \x01(\x0e\x32\x13.Enterprise.KeyType\"\'\n\x14GetTeamMemberRequest\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\"}\n\x0e\x45nterpriseUser\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\r\n\x05\x65mail\x18\x02 \x01(\t\x12\x1a\n\x12\x65nterpriseUsername\x18\x03 \x01(\t\x12\x14\n\x0cisShareAdmin\x18\x04 \x01(\x08\x12\x10\n\x08username\x18\x05 \x01(\t\"K\n\x15GetTeamMemberResponse\x12\x32\n\x0e\x65nterpriseUser\x18\x01 \x03(\x0b\x32\x1a.Enterprise.EnterpriseUser\"-\n\x11\x45nterpriseUserIds\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x03(\x03\"B\n\x19\x45nterprisePersonalAccount\x12\r\n\x05\x65mail\x18\x01 \x01(\t\x12\x16\n\x0eOBSOLETE_FIELD\x18\x02 \x01(\x0c\"S\n\x17\x45ncryptedTeamKeyRequest\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x18\n\x10\x65ncryptedTeamKey\x18\x02 \x01(\x0c\x12\r\n\x05\x66orce\x18\x03 \x01(\x08\"+\n\x0fReEncryptedData\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"?\n\x12ReEncryptedRoleKey\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x18\n\x10\x65ncryptedRoleKey\x18\x02 \x01(\x0c\"P\n\x16ReEncryptedUserDataKey\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1c\n\x14userEncryptedDataKey\x18\x02 \x01(\x0c\"\xd8\x02\n\x1bNodeToManagedCompanyRequest\x12\x11\n\tcompanyId\x18\x01 \x01(\x05\x12*\n\x05nodes\x18\x02 \x03(\x0b\x32\x1b.Enterprise.ReEncryptedData\x12*\n\x05roles\x18\x03 \x03(\x0b\x32\x1b.Enterprise.ReEncryptedData\x12*\n\x05users\x18\x04 \x03(\x0b\x32\x1b.Enterprise.ReEncryptedData\x12\x30\n\x08roleKeys\x18\x05 \x03(\x0b\x32\x1e.Enterprise.ReEncryptedRoleKey\x12\x35\n\x08teamKeys\x18\x06 \x03(\x0b\x32#.Enterprise.EncryptedTeamKeyRequest\x12\x39\n\rusersDataKeys\x18\x07 \x03(\x0b\x32\".Enterprise.ReEncryptedUserDataKey\",\n\x08RoleTeam\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x0f\n\x07teamUid\x18\x02 \x01(\x0c\"4\n\tRoleTeams\x12\'\n\trole_team\x18\x01 \x03(\x0b\x32\x14.Enterprise.RoleTeam\"/\n\x0bTeamsByRole\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x0f\n\x07teamUid\x18\x02 \x03(\x0c\"<\n\x12ManagedNodesByRole\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x15\n\rmanagedNodeId\x18\x02 \x03(\x03\"R\n\x0fRoleUserAddKeys\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0f\n\x07treeKey\x18\x02 \x01(\t\x12\x14\n\x0croleAdminKey\x18\x03 \x01(\t\"T\n\x0bRoleUserAdd\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x34\n\x0froleUserAddKeys\x18\x02 \x03(\x0b\x32\x1b.Enterprise.RoleUserAddKeys\"D\n\x13RoleUsersAddRequest\x12-\n\x0croleUserAdds\x18\x01 \x03(\x0b\x32\x17.Enterprise.RoleUserAdd\"\x80\x01\n\x11RoleUserAddResult\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\x12\x30\n\x06status\x18\x03 \x01(\x0e\x32 .Enterprise.RoleUserModifyStatus\x12\x0f\n\x07message\x18\x04 \x01(\t\"F\n\x14RoleUsersAddResponse\x12.\n\x07results\x18\x01 \x03(\x0b\x32\x1d.Enterprise.RoleUserAddResult\"<\n\x0eRoleUserRemove\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x19\n\x11\x65nterpriseUserIds\x18\x02 \x03(\x03\"M\n\x16RoleUsersRemoveRequest\x12\x33\n\x0froleUserRemoves\x18\x01 \x03(\x0b\x32\x1a.Enterprise.RoleUserRemove\"\x83\x01\n\x14RoleUserRemoveResult\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\x12\x30\n\x06status\x18\x03 \x01(\x0e\x32 .Enterprise.RoleUserModifyStatus\x12\x0f\n\x07message\x18\x04 \x01(\t\"L\n\x17RoleUsersRemoveResponse\x12\x31\n\x07results\x18\x01 \x03(\x0b\x32 .Enterprise.RoleUserRemoveResult\"\xa0\x04\n\x16\x45nterpriseRegistration\x12\x18\n\x10\x65ncryptedTreeKey\x18\x01 \x01(\x0c\x12\x16\n\x0e\x65nterpriseName\x18\x02 \x01(\t\x12\x14\n\x0crootNodeData\x18\x03 \x01(\x0c\x12\x15\n\radminUserData\x18\x04 \x01(\x0c\x12\x11\n\tadminName\x18\x05 \x01(\t\x12\x10\n\x08roleData\x18\x06 \x01(\x0c\x12\x38\n\nrsaKeyPair\x18\x07 \x01(\x0b\x32$.Enterprise.EnterpriseKeyPairRequest\x12\x13\n\x0bnumberSeats\x18\x08 \x01(\x05\x12\x32\n\x0e\x65nterpriseType\x18\t \x01(\x0e\x32\x1a.Enterprise.EnterpriseType\x12\x15\n\rrolePublicKey\x18\n \x01(\x0c\x12*\n\"rolePrivateKeyEncryptedWithRoleKey\x18\x0b \x01(\x0c\x12#\n\x1broleKeyEncryptedWithTreeKey\x18\x0c \x01(\x0c\x12\x38\n\neccKeyPair\x18\r \x01(\x0b\x32$.Enterprise.EnterpriseKeyPairRequest\x12\x18\n\x10\x61llUsersRoleData\x18\x0e \x01(\x0c\x12)\n!roleKeyEncryptedWithUserPublicKey\x18\x0f \x01(\x0c\x12\x18\n\x10\x61pproverRoleData\x18\x10 \x01(\x0c\"H\n\x1a\x44omainPasswordRulesRequest\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x18\n\x10verificationCode\x18\x02 \x01(\t\"\\\n\x19\x44omainPasswordRulesFields\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0f\n\x07minimum\x18\x02 \x01(\x05\x12\x0f\n\x07maximum\x18\x03 \x01(\x05\x12\x0f\n\x07\x61llowed\x18\x04 \x01(\x08\"E\n\x10LoginToMcRequest\x12\x16\n\x0emcEnterpriseId\x18\x01 \x01(\x05\x12\x19\n\x11messageSessionUid\x18\x02 \x01(\x0c\"w\n\x11LoginToMcResponse\x12\x1d\n\x15\x65ncryptedSessionToken\x18\x01 \x01(\x0c\x12\x18\n\x10\x65ncryptedTreeKey\x18\x02 \x01(\t\x12\x11\n\tkeyTypeId\x18\x03 \x01(\x05\x12\x16\n\x0e\x66orbidKeyType2\x18\x04 \x01(\x08\"g\n\x1b\x44omainPasswordRulesResponse\x12H\n\x19\x64omainPasswordRulesFields\x18\x01 \x03(\x0b\x32%.Enterprise.DomainPasswordRulesFields\"\x88\x01\n\x18\x41pproveUserDeviceRequest\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1c\n\x14\x65ncryptedDeviceToken\x18\x02 \x01(\x0c\x12\x1e\n\x16\x65ncryptedDeviceDataKey\x18\x03 \x01(\x0c\x12\x14\n\x0c\x64\x65nyApproval\x18\x04 \x01(\x08\"t\n\x19\x41pproveUserDeviceResponse\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1c\n\x14\x65ncryptedDeviceToken\x18\x02 \x01(\x0c\x12\x0e\n\x06\x66\x61iled\x18\x03 \x01(\x08\x12\x0f\n\x07message\x18\x04 \x01(\t\"Y\n\x19\x41pproveUserDevicesRequest\x12<\n\x0e\x64\x65viceRequests\x18\x01 \x03(\x0b\x32$.Enterprise.ApproveUserDeviceRequest\"\\\n\x1a\x41pproveUserDevicesResponse\x12>\n\x0f\x64\x65viceResponses\x18\x01 \x03(\x0b\x32%.Enterprise.ApproveUserDeviceResponse\"\x87\x01\n\x15\x45nterpriseUserDataKey\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1c\n\x14userEncryptedDataKey\x18\x02 \x01(\x0c\x12\x11\n\tkeyTypeId\x18\x03 \x01(\x05\x12\x0f\n\x07roleKey\x18\x04 \x01(\x0c\x12\x12\n\nprivateKey\x18\x05 \x01(\x0c\"I\n\x16\x45nterpriseUserDataKeys\x12/\n\x04keys\x18\x01 \x03(\x0b\x32!.Enterprise.EnterpriseUserDataKey\"g\n\x1a\x45nterpriseUserDataKeyLight\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1c\n\x14userEncryptedDataKey\x18\x02 \x01(\x0c\x12\x11\n\tkeyTypeId\x18\x03 \x01(\x05\"d\n\x1c\x45nterpriseUserDataKeysByNode\x12\x0e\n\x06nodeId\x18\x01 \x01(\x03\x12\x34\n\x04keys\x18\x02 \x03(\x0b\x32&.Enterprise.EnterpriseUserDataKeyLight\"^\n$EnterpriseUserDataKeysByNodeResponse\x12\x36\n\x04keys\x18\x01 \x03(\x0b\x32(.Enterprise.EnterpriseUserDataKeysByNode\"2\n\x15\x45nterpriseDataRequest\x12\x19\n\x11\x63ontinuationToken\x18\x01 \x01(\x0c\"0\n\x13SpecialProvisioning\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"\x84\x02\n\x11GeneralDataEntity\x12\x16\n\x0e\x65nterpriseName\x18\x01 \x01(\t\x12\x1a\n\x12restrictVisibility\x18\x02 \x01(\x08\x12<\n\x13specialProvisioning\x18\x04 \x01(\x0b\x32\x1f.Enterprise.SpecialProvisioning\x12\x30\n\ruserPrivilege\x18\x07 \x01(\x0b\x32\x19.Enterprise.UserPrivilege\x12\x13\n\x0b\x64istributor\x18\x08 \x01(\x08\x12\x1d\n\x15\x66orbidAccountTransfer\x18\t \x01(\x08\x12\x17\n\x0fshowUserOnboard\x18\n \x01(\x08\"\xfd\x01\n\x04Node\x12\x0e\n\x06nodeId\x18\x01 \x01(\x03\x12\x10\n\x08parentId\x18\x02 \x01(\x03\x12\x10\n\x08\x62ridgeId\x18\x03 \x01(\x03\x12\x0e\n\x06scimId\x18\x04 \x01(\x03\x12\x11\n\tlicenseId\x18\x05 \x01(\x03\x12\x15\n\rencryptedData\x18\x06 \x01(\t\x12\x12\n\nduoEnabled\x18\x07 \x01(\x08\x12\x12\n\nrsaEnabled\x18\x08 \x01(\x08\x12 \n\x14ssoServiceProviderId\x18\t \x01(\x03\x42\x02\x18\x01\x12\x1a\n\x12restrictVisibility\x18\n \x01(\x08\x12!\n\x15ssoServiceProviderIds\x18\x0b \x03(\x03\x42\x02\x10\x01\"\x8e\x01\n\x04Role\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x15\n\rencryptedData\x18\x03 \x01(\t\x12\x0f\n\x07keyType\x18\x04 \x01(\t\x12\x14\n\x0cvisibleBelow\x18\x05 \x01(\x08\x12\x16\n\x0enewUserInherit\x18\x06 \x01(\x08\x12\x10\n\x08roleType\x18\x07 \x01(\t\"\xb8\x02\n\x04User\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x15\n\rencryptedData\x18\x03 \x01(\t\x12\x0f\n\x07keyType\x18\x04 \x01(\t\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x0e\n\x06status\x18\x06 \x01(\t\x12\x0c\n\x04lock\x18\x07 \x01(\x05\x12\x0e\n\x06userId\x18\x08 \x01(\x05\x12\x1e\n\x16\x61\x63\x63ountShareExpiration\x18\t \x01(\x03\x12\x10\n\x08\x66ullName\x18\n \x01(\t\x12\x10\n\x08jobTitle\x18\x0b \x01(\t\x12\x12\n\ntfaEnabled\x18\x0c \x01(\x08\x12\x46\n\x18transferAcceptanceStatus\x18\r \x01(\x0e\x32$.Enterprise.TransferAcceptanceStatus\"7\n\tUserAlias\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x10\n\x08username\x18\x02 \x01(\t\"\xac\x01\n\x18\x43omplianceReportMetaData\x12\x11\n\treportUid\x18\x01 \x01(\x0c\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x12\n\nreportName\x18\x03 \x01(\t\x12\x15\n\rdateGenerated\x18\x04 \x01(\x03\x12\x11\n\trunByName\x18\x05 \x01(\t\x12\x16\n\x0enumberOfOwners\x18\x07 \x01(\x05\x12\x17\n\x0fnumberOfRecords\x18\x08 \x01(\x05\"S\n\x0bManagedNode\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x15\n\rmanagedNodeId\x18\x02 \x01(\x03\x12\x1d\n\x15\x63\x61scadeNodeManagement\x18\x03 \x01(\x08\"T\n\x0fUserManagedNode\x12\x0e\n\x06nodeId\x18\x01 \x01(\x03\x12\x1d\n\x15\x63\x61scadeNodeManagement\x18\x02 \x01(\x08\x12\x12\n\nprivileges\x18\x03 \x03(\t\"w\n\rUserPrivilege\x12\x35\n\x10userManagedNodes\x18\x01 \x03(\x0b\x32\x1b.Enterprise.UserManagedNode\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\x12\x15\n\rencryptedData\x18\x03 \x01(\t\"4\n\x08RoleUser\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\"M\n\rRolePrivilege\x12\x15\n\rmanagedNodeId\x18\x01 \x01(\x03\x12\x0e\n\x06roleId\x18\x02 \x01(\x03\x12\x15\n\rprivilegeType\x18\x03 \x01(\t\"T\n\x17PrivilegesByManagedNode\x12\x15\n\rmanagedNodeId\x18\x01 \x01(\x03\x12\x0e\n\x06roleId\x18\x02 \x01(\x03\x12\x12\n\nprivileges\x18\x03 \x03(\t\"I\n\x0fRoleEnforcement\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x17\n\x0f\x65nforcementType\x18\x02 \x01(\t\x12\r\n\x05value\x18\x03 \x01(\t\"\xa9\x01\n\x04Team\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06nodeId\x18\x03 \x01(\x03\x12\x14\n\x0crestrictEdit\x18\x04 \x01(\x08\x12\x15\n\rrestrictShare\x18\x05 \x01(\x08\x12\x14\n\x0crestrictView\x18\x06 \x01(\x08\x12\x15\n\rencryptedData\x18\x07 \x01(\t\x12\x18\n\x10\x65ncryptedTeamKey\x18\x08 \x01(\t\"G\n\x08TeamUser\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\x12\x10\n\x08userType\x18\x03 \x01(\t\"K\n\x1aGetDistributorInfoResponse\x12-\n\x0c\x64istributors\x18\x01 \x03(\x0b\x32\x17.Enterprise.Distributor\"B\n\x0b\x44istributor\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\x08mspInfos\x18\x02 \x03(\x0b\x32\x13.Enterprise.MspInfo\"\x9d\x02\n\x07MspInfo\x12\x14\n\x0c\x65nterpriseId\x18\x01 \x01(\x05\x12\x16\n\x0e\x65nterpriseName\x18\x02 \x01(\t\x12\x19\n\x11\x61llocatedLicenses\x18\x03 \x01(\x05\x12\x19\n\x11\x61llowedMcProducts\x18\x04 \x03(\t\x12\x15\n\rallowedAddOns\x18\x05 \x03(\t\x12\x17\n\x0fmaxFilePlanType\x18\x06 \x01(\t\x12\x34\n\x10managedCompanies\x18\x07 \x03(\x0b\x32\x1a.Enterprise.ManagedCompany\x12\x1e\n\x16\x61llowUnlimitedLicenses\x18\x08 \x01(\x08\x12(\n\x06\x61\x64\x64Ons\x18\t \x03(\x0b\x32\x18.Enterprise.LicenseAddOn\"\xa8\x02\n\x0eManagedCompany\x12\x16\n\x0emcEnterpriseId\x18\x01 \x01(\x05\x12\x18\n\x10mcEnterpriseName\x18\x02 \x01(\t\x12\x11\n\tmspNodeId\x18\x03 \x01(\x03\x12\x15\n\rnumberOfSeats\x18\x04 \x01(\x05\x12\x15\n\rnumberOfUsers\x18\x05 \x01(\x05\x12\x11\n\tproductId\x18\x06 \x01(\t\x12\x11\n\tisExpired\x18\x07 \x01(\x08\x12\x0f\n\x07treeKey\x18\x08 \x01(\t\x12\x15\n\rtree_key_role\x18\t \x01(\x03\x12\x14\n\x0c\x66ilePlanType\x18\n \x01(\t\x12(\n\x06\x61\x64\x64Ons\x18\x0b \x03(\x0b\x32\x18.Enterprise.LicenseAddOn\x12\x15\n\rtreeKeyTypeId\x18\x0c \x01(\x05\"R\n\x07MSPPool\x12\x11\n\tproductId\x18\x01 \x01(\t\x12\r\n\x05seats\x18\x02 \x01(\x05\x12\x16\n\x0e\x61vailableSeats\x18\x03 \x01(\x05\x12\r\n\x05stash\x18\x04 \x01(\x05\":\n\nMSPContact\x12\x14\n\x0c\x65nterpriseId\x18\x01 \x01(\x05\x12\x16\n\x0e\x65nterpriseName\x18\x02 \x01(\t\"\x84\x02\n\x0cLicenseAddOn\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x65nabled\x18\x02 \x01(\x08\x12\x0f\n\x07isTrial\x18\x03 \x01(\x08\x12\x12\n\nexpiration\x18\x04 \x01(\x03\x12\x0f\n\x07\x63reated\x18\x05 \x01(\x03\x12\r\n\x05seats\x18\x06 \x01(\x05\x12\x16\n\x0e\x61\x63tivationTime\x18\x07 \x01(\x03\x12\x19\n\x11includedInProduct\x18\x08 \x01(\x08\x12\x14\n\x0c\x61piCallCount\x18\t \x01(\x05\x12\x17\n\x0ftierDescription\x18\n \x01(\t\x12\x16\n\x0eseatsAllocated\x18\x0b \x01(\x05\x12\x16\n\x0enhiTierAddOnId\x18\x0c \x01(\x05\"s\n\tMCDefault\x12\x11\n\tmcProduct\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x64\x64Ons\x18\x02 \x03(\t\x12\x14\n\x0c\x66ilePlanType\x18\x03 \x01(\t\x12\x13\n\x0bmaxLicenses\x18\x04 \x01(\x05\x12\x18\n\x10\x66ixedMaxLicenses\x18\x05 \x01(\x08\"\xd2\x01\n\nMSPPermits\x12\x12\n\nrestricted\x18\x01 \x01(\x08\x12\x1a\n\x12maxAllowedLicenses\x18\x02 \x01(\x05\x12\x19\n\x11\x61llowedMcProducts\x18\x03 \x03(\t\x12\x15\n\rallowedAddOns\x18\x04 \x03(\t\x12\x17\n\x0fmaxFilePlanType\x18\x05 \x01(\t\x12\x1e\n\x16\x61llowUnlimitedLicenses\x18\x06 \x01(\x08\x12)\n\nmcDefaults\x18\x07 \x03(\x0b\x32\x15.Enterprise.MCDefault\"\xa0\x04\n\x07License\x12\x0c\n\x04paid\x18\x01 \x01(\x08\x12\x15\n\rnumberOfSeats\x18\x02 \x01(\x05\x12\x12\n\nexpiration\x18\x03 \x01(\x03\x12\x14\n\x0clicenseKeyId\x18\x04 \x01(\x05\x12\x15\n\rproductTypeId\x18\x05 \x01(\x05\x12\x0c\n\x04name\x18\x06 \x01(\t\x12\x1b\n\x13\x65nterpriseLicenseId\x18\x07 \x01(\x03\x12\x16\n\x0eseatsAllocated\x18\x08 \x01(\x05\x12\x14\n\x0cseatsPending\x18\t \x01(\x05\x12\x0c\n\x04tier\x18\n \x01(\x05\x12\x16\n\x0e\x66ilePlanTypeId\x18\x0b \x01(\x05\x12\x10\n\x08maxBytes\x18\x0c \x01(\x03\x12\x19\n\x11storageExpiration\x18\r \x01(\x03\x12\x15\n\rlicenseStatus\x18\x0e \x01(\t\x12$\n\x07mspPool\x18\x0f \x03(\x0b\x32\x13.Enterprise.MSPPool\x12)\n\tmanagedBy\x18\x10 \x01(\x0b\x32\x16.Enterprise.MSPContact\x12(\n\x06\x61\x64\x64Ons\x18\x11 \x03(\x0b\x32\x18.Enterprise.LicenseAddOn\x12\x17\n\x0fnextBillingDate\x18\x12 \x01(\x03\x12\x17\n\x0fhasMSPLegacyLog\x18\x13 \x01(\x08\x12*\n\nmspPermits\x18\x14 \x01(\x0b\x32\x16.Enterprise.MSPPermits\x12\x13\n\x0b\x64istributor\x18\x15 \x01(\x08\"n\n\x06\x42ridge\x12\x10\n\x08\x62ridgeId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x18\n\x10wanIpEnforcement\x18\x03 \x01(\t\x12\x18\n\x10lanIpEnforcement\x18\x04 \x01(\t\x12\x0e\n\x06status\x18\x05 \x01(\t\"t\n\x04Scim\x12\x0e\n\x06scimId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x0e\n\x06status\x18\x03 \x01(\t\x12\x12\n\nlastSynced\x18\x04 \x01(\x03\x12\x12\n\nrolePrefix\x18\x05 \x01(\t\x12\x14\n\x0cuniqueGroups\x18\x06 \x01(\x08\"L\n\x0e\x45mailProvision\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x0e\n\x06\x64omain\x18\x03 \x01(\t\x12\x0e\n\x06method\x18\x04 \x01(\t\"R\n\nQueuedTeam\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06nodeId\x18\x03 \x01(\x03\x12\x15\n\rencryptedData\x18\x04 \x01(\t\"0\n\x0eQueuedTeamUser\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\r\n\x05users\x18\x02 \x03(\x03\"\xa4\x01\n\x0eTeamsAddResult\x12\x34\n\x11successfulTeamAdd\x18\x01 \x03(\x0b\x32\x19.Enterprise.TeamAddResult\x12\x36\n\x13unsuccessfulTeamAdd\x18\x02 \x03(\x0b\x32\x19.Enterprise.TeamAddResult\x12\x0e\n\x06result\x18\x03 \x01(\t\x12\x14\n\x0c\x65rrorMessage\x18\x04 \x01(\t\"U\n\rTeamAddResult\x12\x1e\n\x04team\x18\x01 \x01(\x0b\x32\x10.Enterprise.Team\x12\x0e\n\x06result\x18\x02 \x01(\t\x12\x14\n\x0c\x65rrorMessage\x18\x03 \x01(\t\"\x91\x01\n\nSsoService\x12\x1c\n\x14ssoServiceProviderId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0e\n\x06sp_url\x18\x04 \x01(\t\x12\x16\n\x0einviteNewUsers\x18\x05 \x01(\x08\x12\x0e\n\x06\x61\x63tive\x18\x06 \x01(\x08\x12\x0f\n\x07isCloud\x18\x07 \x01(\x08\"1\n\x10ReportFilterUser\x12\x0e\n\x06userId\x18\x01 \x01(\x05\x12\r\n\x05\x65mail\x18\x02 \x01(\t\"\x97\x02\n\x1d\x44\x65viceRequestForAdminApproval\x12\x10\n\x08\x64\x65viceId\x18\x01 \x01(\x03\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\x12\x1c\n\x14\x65ncryptedDeviceToken\x18\x03 \x01(\x0c\x12\x17\n\x0f\x64\x65vicePublicKey\x18\x04 \x01(\x0c\x12\x12\n\ndeviceName\x18\x05 \x01(\t\x12\x15\n\rclientVersion\x18\x06 \x01(\t\x12\x12\n\ndeviceType\x18\x07 \x01(\t\x12\x0c\n\x04\x64\x61te\x18\x08 \x01(\x03\x12\x11\n\tipAddress\x18\t \x01(\t\x12\x10\n\x08location\x18\n \x01(\t\x12\r\n\x05\x65mail\x18\x0b \x01(\t\x12\x12\n\naccountUid\x18\x0c \x01(\x0c\"`\n\x0e\x45nterpriseData\x12\x30\n\x06\x65ntity\x18\x01 \x01(\x0e\x32 .Enterprise.EnterpriseDataEntity\x12\x0e\n\x06\x64\x65lete\x18\x02 \x01(\x08\x12\x0c\n\x04\x64\x61ta\x18\x03 \x03(\x0c\"\xd0\x01\n\x16\x45nterpriseDataResponse\x12\x19\n\x11\x63ontinuationToken\x18\x01 \x01(\x0c\x12\x0f\n\x07hasMore\x18\x02 \x01(\x08\x12,\n\x0b\x63\x61\x63heStatus\x18\x03 \x01(\x0e\x32\x17.Enterprise.CacheStatus\x12(\n\x04\x64\x61ta\x18\x04 \x03(\x0b\x32\x1a.Enterprise.EnterpriseData\x12\x32\n\x0bgeneralData\x18\x05 \x01(\x0b\x32\x1d.Enterprise.GeneralDataEntity\"*\n\rBackupRequest\x12\x19\n\x11\x63ontinuationToken\x18\x01 \x01(\x0c\"\x98\x01\n\x0c\x42\x61\x63kupRecord\x12\x0e\n\x06userId\x18\x01 \x01(\x05\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x0b\n\x03key\x18\x03 \x01(\x0c\x12*\n\x07keyType\x18\x04 \x01(\x0e\x32\x19.Enterprise.BackupKeyType\x12\x0f\n\x07version\x18\x05 \x01(\x05\x12\x0c\n\x04\x64\x61ta\x18\x06 \x01(\x0c\x12\r\n\x05\x65xtra\x18\x07 \x01(\x0c\".\n\tBackupKey\x12\x0e\n\x06userId\x18\x01 \x01(\x05\x12\x11\n\tbackupKey\x18\x02 \x01(\x0c\"\x8d\x02\n\nBackupUser\x12\x0e\n\x06userId\x18\x01 \x01(\x05\x12\x10\n\x08userName\x18\x02 \x01(\t\x12\x0f\n\x07\x64\x61taKey\x18\x03 \x01(\x0c\x12\x36\n\x0b\x64\x61taKeyType\x18\x04 \x01(\x0e\x32!.Enterprise.BackupUserDataKeyType\x12\x12\n\nprivateKey\x18\x05 \x01(\x0c\x12\x0f\n\x07treeKey\x18\x06 \x01(\x0c\x12.\n\x0btreeKeyType\x18\x07 \x01(\x0e\x32\x19.Enterprise.BackupKeyType\x12)\n\nbackupKeys\x18\x08 \x03(\x0b\x32\x15.Enterprise.BackupKey\x12\x14\n\x0cprivateECKey\x18\t \x01(\x0c\"\x9e\x01\n\x0e\x42\x61\x63kupResponse\x12\x1f\n\x17\x65nterpriseEccPrivateKey\x18\x01 \x01(\x0c\x12%\n\x05users\x18\x02 \x03(\x0b\x32\x16.Enterprise.BackupUser\x12)\n\x07records\x18\x03 \x03(\x0b\x32\x18.Enterprise.BackupRecord\x12\x19\n\x11\x63ontinuationToken\x18\x04 \x01(\x0c\"e\n\nBackupFile\x12\x0c\n\x04user\x18\x01 \x01(\t\x12\x11\n\tbackupUid\x18\x02 \x01(\x0c\x12\x10\n\x08\x66ileName\x18\x03 \x01(\t\x12\x0f\n\x07\x63reated\x18\x04 \x01(\x03\x12\x13\n\x0b\x64ownloadUrl\x18\x05 \x01(\t\"8\n\x0f\x42\x61\x63kupsResponse\x12%\n\x05\x66iles\x18\x01 \x03(\x0b\x32\x16.Enterprise.BackupFile\".\n\x1cGetEnterpriseDataKeysRequest\x12\x0e\n\x06roleId\x18\x01 \x03(\x03\"\xff\x01\n\x1dGetEnterpriseDataKeysResponse\x12:\n\x12reEncryptedRoleKey\x18\x01 \x03(\x0b\x32\x1e.Enterprise.ReEncryptedRoleKey\x12$\n\x07roleKey\x18\x02 \x03(\x0b\x32\x13.Enterprise.RoleKey\x12\"\n\x06mspKey\x18\x03 \x01(\x0b\x32\x12.Enterprise.MspKey\x12\x32\n\x0e\x65nterpriseKeys\x18\x04 \x01(\x0b\x32\x1a.Enterprise.EnterpriseKeys\x12$\n\x07treeKey\x18\x05 \x01(\x0b\x32\x13.Enterprise.TreeKey\"^\n\x07RoleKey\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x14\n\x0c\x65ncryptedKey\x18\x02 \x01(\t\x12-\n\x07keyType\x18\x03 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\"d\n\x06MspKey\x12\x1b\n\x13\x65ncryptedMspTreeKey\x18\x01 \x01(\t\x12=\n\x17\x65ncryptedMspTreeKeyType\x18\x02 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\"|\n\x0e\x45nterpriseKeys\x12\x14\n\x0crsaPublicKey\x18\x01 \x01(\x0c\x12\x1e\n\x16rsaEncryptedPrivateKey\x18\x02 \x01(\x0c\x12\x14\n\x0c\x65\x63\x63PublicKey\x18\x03 \x01(\x0c\x12\x1e\n\x16\x65\x63\x63\x45ncryptedPrivateKey\x18\x04 \x01(\x0c\"H\n\x07TreeKey\x12\x0f\n\x07treeKey\x18\x01 \x01(\t\x12,\n\tkeyTypeId\x18\x02 \x01(\x0e\x32\x19.Enterprise.BackupKeyType\"E\n\x14SharedRecordResponse\x12-\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x1d.Enterprise.SharedRecordEvent\"p\n\x11SharedRecordEvent\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x10\n\x08userName\x18\x02 \x01(\t\x12\x0f\n\x07\x63\x61nEdit\x18\x03 \x01(\x08\x12\x12\n\ncanReshare\x18\x04 \x01(\x08\x12\x11\n\tshareFrom\x18\x05 \x01(\x05\".\n\x1cSetRestrictVisibilityRequest\x12\x0e\n\x06nodeId\x18\x01 \x01(\x03\"\xd0\x01\n\x0eUserAddRequest\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x15\n\rencryptedData\x18\x03 \x01(\x0c\x12-\n\x07keyType\x18\x04 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\x12\x10\n\x08\x66ullName\x18\x05 \x01(\t\x12\x10\n\x08jobTitle\x18\x06 \x01(\t\x12\r\n\x05\x65mail\x18\x07 \x01(\t\x12\x1b\n\x13suppressEmailInvite\x18\x08 \x01(\x08\":\n\x11UserUpdateRequest\x12%\n\x05users\x18\x01 \x03(\x0b\x32\x16.Enterprise.UserUpdate\"\xaf\x01\n\nUserUpdate\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x15\n\rencryptedData\x18\x03 \x01(\x0c\x12-\n\x07keyType\x18\x04 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\x12\x10\n\x08\x66ullName\x18\x05 \x01(\t\x12\x10\n\x08jobTitle\x18\x06 \x01(\t\x12\r\n\x05\x65mail\x18\x07 \x01(\t\"A\n\x12UserUpdateResponse\x12+\n\x05users\x18\x01 \x03(\x0b\x32\x1c.Enterprise.UserUpdateResult\"Z\n\x10UserUpdateResult\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12,\n\x06status\x18\x02 \x01(\x0e\x32\x1c.Enterprise.UserUpdateStatus\"J\n\x1d\x43omplianceRecordOwnersRequest\x12\x0f\n\x07nodeIds\x18\x01 \x03(\x03\x12\x18\n\x10includeNonShared\x18\x02 \x01(\x08\"O\n\x1e\x43omplianceRecordOwnersResponse\x12-\n\x0crecordOwners\x18\x01 \x03(\x0b\x32\x17.Enterprise.RecordOwner\"7\n\x0bRecordOwner\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0e\n\x06shared\x18\x02 \x01(\x08\"\xa6\x01\n PreliminaryComplianceDataRequest\x12\x19\n\x11\x65nterpriseUserIds\x18\x01 \x03(\x03\x12\x18\n\x10includeNonShared\x18\x02 \x01(\x08\x12\x19\n\x11\x63ontinuationToken\x18\x03 \x01(\x0c\x12\x32\n*includeTotalMatchingRecordsInFirstResponse\x18\x04 \x01(\x08\"\x9f\x01\n!PreliminaryComplianceDataResponse\x12\x30\n\rauditUserData\x18\x01 \x03(\x0b\x32\x19.Enterprise.AuditUserData\x12\x19\n\x11\x63ontinuationToken\x18\x02 \x01(\x0c\x12\x0f\n\x07hasMore\x18\x03 \x01(\x08\x12\x1c\n\x14totalMatchingRecords\x18\x04 \x01(\x05\"K\n\x0f\x41uditUserRecord\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x15\n\rencryptedData\x18\x02 \x01(\x0c\x12\x0e\n\x06shared\x18\x03 \x01(\x08\"\x8d\x01\n\rAuditUserData\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x35\n\x10\x61uditUserRecords\x18\x02 \x03(\x0b\x32\x1b.Enterprise.AuditUserRecord\x12+\n\x06status\x18\x03 \x01(\x0e\x32\x1b.Enterprise.AuditUserStatus\"\x7f\n\x17\x43omplianceReportFilters\x12\x14\n\x0crecordTitles\x18\x01 \x03(\t\x12\x12\n\nrecordUids\x18\x02 \x03(\x0c\x12\x11\n\tjobTitles\x18\x03 \x03(\x03\x12\x0c\n\x04urls\x18\x04 \x03(\t\x12\x19\n\x11\x65nterpriseUserIds\x18\x05 \x03(\x03\"\x7f\n\x17\x43omplianceReportRequest\x12<\n\x13\x63omplianceReportRun\x18\x01 \x01(\x0b\x32\x1f.Enterprise.ComplianceReportRun\x12\x12\n\nreportName\x18\x02 \x01(\t\x12\x12\n\nsaveReport\x18\x03 \x01(\x08\"\x85\x01\n\x13\x43omplianceReportRun\x12N\n\x17reportCriteriaAndFilter\x18\x01 \x01(\x0b\x32-.Enterprise.ComplianceReportCriteriaAndFilter\x12\r\n\x05users\x18\x02 \x03(\x03\x12\x0f\n\x07records\x18\x03 \x03(\x0c\"\xfc\x01\n!ComplianceReportCriteriaAndFilter\x12\x0e\n\x06nodeId\x18\x01 \x01(\x03\x12\x13\n\x0b\x63riteriaUid\x18\x02 \x01(\x0c\x12\x14\n\x0c\x63riteriaName\x18\x03 \x01(\t\x12\x36\n\x08\x63riteria\x18\x04 \x01(\x0b\x32$.Enterprise.ComplianceReportCriteria\x12\x33\n\x07\x66ilters\x18\x05 \x03(\x0b\x32\".Enterprise.ComplianceReportFilter\x12\x14\n\x0clastModified\x18\x06 \x01(\x03\x12\x19\n\x11nodeEncryptedData\x18\x07 \x01(\x0c\"b\n\x18\x43omplianceReportCriteria\x12\x11\n\tjobTitles\x18\x01 \x03(\t\x12\x19\n\x11\x65nterpriseUserIds\x18\x02 \x03(\x03\x12\x18\n\x10includeNonShared\x18\x03 \x01(\x08\"x\n\x16\x43omplianceReportFilter\x12\x14\n\x0crecordTitles\x18\x01 \x03(\t\x12\x12\n\nrecordUids\x18\x02 \x03(\x0c\x12\x11\n\tjobTitles\x18\x03 \x03(\t\x12\x0c\n\x04urls\x18\x04 \x03(\t\x12\x13\n\x0brecordTypes\x18\x05 \x03(\t\"\xa1\x05\n\x18\x43omplianceReportResponse\x12\x15\n\rdateGenerated\x18\x01 \x01(\x03\x12\x15\n\rrunByUserName\x18\x02 \x01(\t\x12\x12\n\nreportName\x18\x03 \x01(\t\x12\x11\n\treportUid\x18\x04 \x01(\x0c\x12<\n\x13\x63omplianceReportRun\x18\x05 \x01(\x0b\x32\x1f.Enterprise.ComplianceReportRun\x12-\n\x0cuserProfiles\x18\x06 \x03(\x0b\x32\x17.Enterprise.UserProfile\x12)\n\nauditTeams\x18\x07 \x03(\x0b\x32\x15.Enterprise.AuditTeam\x12-\n\x0c\x61uditRecords\x18\x08 \x03(\x0b\x32\x17.Enterprise.AuditRecord\x12+\n\x0buserRecords\x18\t \x03(\x0b\x32\x16.Enterprise.UserRecord\x12;\n\x13sharedFolderRecords\x18\n \x03(\x0b\x32\x1e.Enterprise.SharedFolderRecord\x12\x37\n\x11sharedFolderUsers\x18\x0b \x03(\x0b\x32\x1c.Enterprise.SharedFolderUser\x12\x37\n\x11sharedFolderTeams\x18\x0c \x03(\x0b\x32\x1c.Enterprise.SharedFolderTeam\x12\x31\n\x0e\x61uditTeamUsers\x18\r \x03(\x0b\x32\x19.Enterprise.AuditTeamUser\x12)\n\nauditRoles\x18\x0e \x03(\x0b\x32\x15.Enterprise.AuditRole\x12/\n\rlinkedRecords\x18\x0f \x03(\x0b\x32\x18.Enterprise.LinkedRecord\"\x81\x01\n\x0b\x41uditRecord\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x11\n\tauditData\x18\x02 \x01(\x0c\x12\x16\n\x0ehasAttachments\x18\x03 \x01(\x08\x12\x0f\n\x07inTrash\x18\x04 \x01(\x08\x12\x10\n\x08treeLeft\x18\x05 \x01(\x05\x12\x11\n\ttreeRight\x18\x06 \x01(\x05\"\x80\x02\n\tAuditRole\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x15\n\rencryptedData\x18\x02 \x01(\x0c\x12&\n\x1erestrictShareOutsideEnterprise\x18\x03 \x01(\x08\x12\x18\n\x10restrictShareAll\x18\x04 \x01(\x08\x12\"\n\x1arestrictShareOfAttachments\x18\x05 \x01(\x08\x12)\n!restrictMaskPasswordsWhileEditing\x18\x06 \x01(\x08\x12;\n\x13roleNodeManagements\x18\x07 \x03(\x0b\x32\x1e.Enterprise.RoleNodeManagement\"^\n\x12RoleNodeManagement\x12\x10\n\x08treeLeft\x18\x01 \x01(\x05\x12\x11\n\ttreeRight\x18\x02 \x01(\x05\x12\x0f\n\x07\x63\x61scade\x18\x03 \x01(\x08\x12\x12\n\nprivileges\x18\x04 \x01(\x05\"k\n\x0bUserProfile\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x10\n\x08\x66ullName\x18\x02 \x01(\t\x12\x10\n\x08jobTitle\x18\x03 \x01(\t\x12\r\n\x05\x65mail\x18\x04 \x01(\t\x12\x0f\n\x07roleIds\x18\x05 \x03(\x03\"=\n\x10RecordPermission\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x16\n\x0epermissionBits\x18\x02 \x01(\x05\"_\n\nUserRecord\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x37\n\x11recordPermissions\x18\x02 \x03(\x0b\x32\x1c.Enterprise.RecordPermission\"[\n\tAuditTeam\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x10\n\x08teamName\x18\x02 \x01(\t\x12\x14\n\x0crestrictEdit\x18\x03 \x01(\x08\x12\x15\n\rrestrictShare\x18\x04 \x01(\x08\";\n\rAuditTeamUser\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x19\n\x11\x65nterpriseUserIds\x18\x02 \x03(\x03\"\x9f\x01\n\x12SharedFolderRecord\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x37\n\x11recordPermissions\x18\x02 \x03(\x0b\x32\x1c.Enterprise.RecordPermission\x12\x37\n\x11shareAdminRecords\x18\x03 \x03(\x0b\x32\x1c.Enterprise.ShareAdminRecord\"M\n\x10ShareAdminRecord\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1f\n\x17recordPermissionIndexes\x18\x02 \x03(\x05\"F\n\x10SharedFolderUser\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x19\n\x11\x65nterpriseUserIds\x18\x02 \x03(\x03\"=\n\x10SharedFolderTeam\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x10\n\x08teamUids\x18\x02 \x03(\x0c\"/\n\x1aGetComplianceReportRequest\x12\x11\n\treportUid\x18\x01 \x01(\x0c\"2\n\x1bGetComplianceReportResponse\x12\x13\n\x0b\x64ownloadUrl\x18\x01 \x01(\t\"6\n\x1f\x43omplianceReportCriteriaRequest\x12\x13\n\x0b\x63riteriaUid\x18\x01 \x01(\x0c\";\n$SaveComplianceReportCriteriaResponse\x12\x13\n\x0b\x63riteriaUid\x18\x01 \x01(\x0c\"4\n\x0cLinkedRecord\x12\x10\n\x08ownerUid\x18\x01 \x01(\x0c\x12\x12\n\nrecordUids\x18\x02 \x03(\x0c\"W\n\x17GetSharingAdminsRequest\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x10\n\x08username\x18\x03 \x01(\t\"\xe0\x01\n\x0eUserProfileExt\x12\r\n\x05\x65mail\x18\x01 \x01(\t\x12\x10\n\x08\x66ullName\x18\x02 \x01(\t\x12\x10\n\x08jobTitle\x18\x03 \x01(\t\x12\x14\n\x0cisMSPMCAdmin\x18\x04 \x01(\x08\x12\x18\n\x10isInSharedFolder\x18\x05 \x01(\x08\x12&\n\x1eisShareAdminForRequestedObject\x18\x06 \x01(\x08\x12(\n isShareAdminForSharedFolderOwner\x18\x07 \x01(\x08\x12\x19\n\x11hasAccessToObject\x18\x08 \x01(\x08\"O\n\x18GetSharingAdminsResponse\x12\x33\n\x0fuserProfileExts\x18\x01 \x03(\x0b\x32\x1a.Enterprise.UserProfileExt\"_\n\x1eTeamsEnterpriseUsersAddRequest\x12=\n\x05teams\x18\x01 \x03(\x0b\x32..Enterprise.TeamsEnterpriseUsersAddTeamRequest\"t\n\"TeamsEnterpriseUsersAddTeamRequest\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12=\n\x05users\x18\x02 \x03(\x0b\x32..Enterprise.TeamsEnterpriseUsersAddUserRequest\"\xab\x01\n\"TeamsEnterpriseUsersAddUserRequest\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12*\n\x08userType\x18\x02 \x01(\x0e\x32\x18.Enterprise.TeamUserType\x12\x13\n\x07teamKey\x18\x03 \x01(\tB\x02\x18\x01\x12*\n\x0ctypedTeamKey\x18\x04 \x01(\x0b\x32\x14.Enterprise.TypedKey\"F\n\x08TypedKey\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12-\n\x07keyType\x18\x02 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\"s\n\x1fTeamsEnterpriseUsersAddResponse\x12>\n\x05teams\x18\x01 \x03(\x0b\x32/.Enterprise.TeamsEnterpriseUsersAddTeamResponse\x12\x10\n\x08revision\x18\x02 \x01(\x03\"\xc4\x01\n#TeamsEnterpriseUsersAddTeamResponse\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12>\n\x05users\x18\x02 \x03(\x0b\x32/.Enterprise.TeamsEnterpriseUsersAddUserResponse\x12\x0f\n\x07success\x18\x03 \x01(\x08\x12\x0f\n\x07message\x18\x04 \x01(\t\x12\x12\n\nresultCode\x18\x05 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x06 \x01(\t\"\x9f\x01\n#TeamsEnterpriseUsersAddUserResponse\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x10\n\x08revision\x18\x02 \x01(\x03\x12\x0f\n\x07success\x18\x03 \x01(\x08\x12\x0f\n\x07message\x18\x04 \x01(\t\x12\x12\n\nresultCode\x18\x05 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x06 \x01(\t\"E\n\x18TeamEnterpriseUserRemove\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\"j\n TeamEnterpriseUserRemovesRequest\x12\x46\n\x18teamEnterpriseUserRemove\x18\x01 \x03(\x0b\x32$.Enterprise.TeamEnterpriseUserRemove\"{\n!TeamEnterpriseUserRemovesResponse\x12V\n teamEnterpriseUserRemoveResponse\x18\x01 \x03(\x0b\x32,.Enterprise.TeamEnterpriseUserRemoveResponse\"\xb8\x01\n TeamEnterpriseUserRemoveResponse\x12\x46\n\x18teamEnterpriseUserRemove\x18\x01 \x01(\x0b\x32$.Enterprise.TeamEnterpriseUserRemove\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\nresultCode\x18\x03 \x01(\t\x12\x0f\n\x07message\x18\x04 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x05 \x01(\t\"M\n\x0b\x44omainAlias\x12\x0e\n\x06\x64omain\x18\x01 \x01(\t\x12\r\n\x05\x61lias\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\x05\x12\x0f\n\x07message\x18\x04 \x01(\t\"B\n\x12\x44omainAliasRequest\x12,\n\x0b\x64omainAlias\x18\x01 \x03(\x0b\x32\x17.Enterprise.DomainAlias\"C\n\x13\x44omainAliasResponse\x12,\n\x0b\x64omainAlias\x18\x01 \x03(\x0b\x32\x17.Enterprise.DomainAlias\"m\n\x1f\x45nterpriseUsersProvisionRequest\x12\x33\n\x05users\x18\x01 \x03(\x0b\x32$.Enterprise.EnterpriseUsersProvision\x12\x15\n\rclientVersion\x18\x02 \x01(\t\"\xb6\x03\n\x18\x45nterpriseUsersProvision\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x0e\n\x06nodeId\x18\x03 \x01(\x03\x12\x15\n\rencryptedData\x18\x04 \x01(\t\x12-\n\x07keyType\x18\x05 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\x12\x10\n\x08\x66ullName\x18\x06 \x01(\t\x12\x10\n\x08jobTitle\x18\x07 \x01(\t\x12\x1e\n\x16\x65nterpriseUsersDataKey\x18\x08 \x01(\x0c\x12\x14\n\x0c\x61uthVerifier\x18\t \x01(\x0c\x12\x18\n\x10\x65ncryptionParams\x18\n \x01(\x0c\x12\x14\n\x0crsaPublicKey\x18\x0b \x01(\x0c\x12\x1e\n\x16rsaEncryptedPrivateKey\x18\x0c \x01(\x0c\x12\x14\n\x0c\x65\x63\x63PublicKey\x18\r \x01(\x0c\x12\x1e\n\x16\x65\x63\x63\x45ncryptedPrivateKey\x18\x0e \x01(\x0c\x12\x1c\n\x14\x65ncryptedDeviceToken\x18\x0f \x01(\x0c\x12\x1a\n\x12\x65ncryptedClientKey\x18\x10 \x01(\x0c\"_\n EnterpriseUsersProvisionResponse\x12;\n\x07results\x18\x01 \x03(\x0b\x32*.Enterprise.EnterpriseUsersProvisionResult\"q\n\x1e\x45nterpriseUsersProvisionResult\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0f\n\x07message\x18\x03 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x04 \x01(\t\"a\n\x19\x45nterpriseUsersAddRequest\x12-\n\x05users\x18\x01 \x03(\x0b\x32\x1e.Enterprise.EnterpriseUsersAdd\x12\x15\n\rclientVersion\x18\x02 \x01(\t\"\x8c\x02\n\x12\x45nterpriseUsersAdd\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x0e\n\x06nodeId\x18\x03 \x01(\x03\x12\x15\n\rencryptedData\x18\x04 \x01(\t\x12-\n\x07keyType\x18\x05 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\x12\x10\n\x08\x66ullName\x18\x06 \x01(\t\x12\x10\n\x08jobTitle\x18\x07 \x01(\t\x12\x1b\n\x13suppressEmailInvite\x18\x08 \x01(\x08\x12\x15\n\rinviteeLocale\x18\t \x01(\t\x12\x0c\n\x04move\x18\n \x01(\x08\x12\x0e\n\x06roleId\x18\x0b \x01(\x03\"\x9b\x01\n\x1a\x45nterpriseUsersAddResponse\x12\x35\n\x07results\x18\x01 \x03(\x0b\x32$.Enterprise.EnterpriseUsersAddResult\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x0c\n\x04\x63ode\x18\x03 \x01(\t\x12\x0f\n\x07message\x18\x04 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x05 \x01(\t\"\x96\x01\n\x18\x45nterpriseUsersAddResult\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x18\n\x10verificationCode\x18\x03 \x01(\t\x12\x0c\n\x04\x63ode\x18\x04 \x01(\t\x12\x0f\n\x07message\x18\x05 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x06 \x01(\t\"\xb9\x01\n\x17UpdateMSPPermitsRequest\x12\x17\n\x0fmspEnterpriseId\x18\x01 \x01(\x05\x12\x1a\n\x12maxAllowedLicenses\x18\x02 \x01(\x05\x12\x19\n\x11\x61llowedMcProducts\x18\x03 \x03(\t\x12\x15\n\rallowedAddOns\x18\x04 \x03(\t\x12\x17\n\x0fmaxFilePlanType\x18\x05 \x01(\t\x12\x1e\n\x16\x61llowUnlimitedLicenses\x18\x06 \x01(\x08\"9\n\x1c\x44\x65leteEnterpriseUsersRequest\x12\x19\n\x11\x65nterpriseUserIds\x18\x01 \x03(\x03\"o\n\x1a\x44\x65leteEnterpriseUserStatus\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x37\n\x06status\x18\x02 \x01(\x0e\x32\'.Enterprise.DeleteEnterpriseUsersResult\"]\n\x1d\x44\x65leteEnterpriseUsersResponse\x12<\n\x0c\x64\x65leteStatus\x18\x01 \x03(\x0b\x32&.Enterprise.DeleteEnterpriseUserStatus\"w\n\x18\x43learSecurityDataRequest\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x03(\x03\x12\x10\n\x08\x61llUsers\x18\x02 \x01(\x08\x12/\n\x04type\x18\x03 \x01(\x0e\x32!.Enterprise.ClearSecurityDataType\"%\n\x13ListDomainsResponse\x12\x0e\n\x06\x64omain\x18\x01 \x03(\t\"d\n\x14ReserveDomainRequest\x12<\n\x13reserveDomainAction\x18\x01 \x01(\x0e\x32\x1f.Enterprise.ReserveDomainAction\x12\x0e\n\x06\x64omain\x18\x02 \x01(\t\"&\n\x15ReserveDomainResponse\x12\r\n\x05token\x18\x01 \x01(\t\".\n\x0bRolesByTeam\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x0e\n\x06roleId\x18\x02 \x03(\x03\"\x8d\x01\n\x10LockUsersRequest\x12\x1d\n\x15lockEnterpriseUserIds\x18\x01 \x03(\x03\x12 \n\x18\x64isableEnterpriseUserIds\x18\x02 \x03(\x03\x12\x1f\n\x17unlockEnterpriseUserIds\x18\x03 \x03(\x03\x12\x17\n\x0f\x64\x65leteIfPending\x18\x04 \x01(\x08\"C\n\x11LockUsersResponse\x12.\n\x08response\x18\x01 \x03(\x0b\x32\x1c.Enterprise.LockUserResponse\"n\n\x10LockUserResponse\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12*\n\x06status\x18\x02 \x01(\x0e\x32\x1a.Enterprise.UserLockStatus\x12\x14\n\x0c\x65rrorMessage\x18\x03 \x01(\t*\x1b\n\x07KeyType\x12\x07\n\x03RSA\x10\x00\x12\x07\n\x03\x45\x43\x43\x10\x01*\x9a\x02\n\x14RoleUserModifyStatus\x12\x0f\n\x0bROLE_EXISTS\x10\x00\x12\x14\n\x10MISSING_TREE_KEY\x10\x01\x12\x14\n\x10MISSING_ROLE_KEY\x10\x02\x12\x1e\n\x1aINVALID_ENTERPRISE_USER_ID\x10\x03\x12\x1b\n\x17PENDING_ENTERPRISE_USER\x10\x04\x12\x13\n\x0fINVALID_NODE_ID\x10\x05\x12!\n\x1dMAY_NOT_REMOVE_SELF_FROM_ROLE\x10\x06\x12\x1c\n\x18MUST_HAVE_ONE_USER_ADMIN\x10\x07\x12\x13\n\x0fINVALID_ROLE_ID\x10\x08\x12\x1d\n\x19PAM_LICENSE_SEAT_EXCEEDED\x10\t*=\n\x0e\x45nterpriseType\x12\x17\n\x13\x45NTERPRISE_STANDARD\x10\x00\x12\x12\n\x0e\x45NTERPRISE_MSP\x10\x01*s\n\x18TransferAcceptanceStatus\x12\r\n\tUNDEFINED\x10\x00\x12\x10\n\x0cNOT_REQUIRED\x10\x01\x12\x10\n\x0cNOT_ACCEPTED\x10\x02\x12\x16\n\x12PARTIALLY_ACCEPTED\x10\x03\x12\x0c\n\x08\x41\x43\x43\x45PTED\x10\x04*\xe1\x03\n\x14\x45nterpriseDataEntity\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05NODES\x10\x01\x12\t\n\x05ROLES\x10\x02\x12\t\n\x05USERS\x10\x03\x12\t\n\x05TEAMS\x10\x04\x12\x0e\n\nTEAM_USERS\x10\x05\x12\x0e\n\nROLE_USERS\x10\x06\x12\x13\n\x0fROLE_PRIVILEGES\x10\x07\x12\x15\n\x11ROLE_ENFORCEMENTS\x10\x08\x12\x0e\n\nROLE_TEAMS\x10\t\x12\x0c\n\x08LICENSES\x10\n\x12\x11\n\rMANAGED_NODES\x10\x0b\x12\x15\n\x11MANAGED_COMPANIES\x10\x0c\x12\x0b\n\x07\x42RIDGES\x10\r\x12\t\n\x05SCIMS\x10\x0e\x12\x13\n\x0f\x45MAIL_PROVISION\x10\x0f\x12\x10\n\x0cQUEUED_TEAMS\x10\x10\x12\x15\n\x11QUEUED_TEAM_USERS\x10\x11\x12\x10\n\x0cSSO_SERVICES\x10\x12\x12\x17\n\x13REPORT_FILTER_USERS\x10\x13\x12&\n\"DEVICES_REQUEST_FOR_ADMIN_APPROVAL\x10\x14\x12\x10\n\x0cUSER_ALIASES\x10\x15\x12)\n%COMPLIANCE_REPORT_CRITERIA_AND_FILTER\x10\x16\x12\x16\n\x12\x43OMPLIANCE_REPORTS\x10\x17*\"\n\x0b\x43\x61\x63heStatus\x12\x08\n\x04KEEP\x10\x00\x12\t\n\x05\x43LEAR\x10\x01*\x93\x01\n\rBackupKeyType\x12\n\n\x06NO_KEY\x10\x00\x12\x19\n\x15\x45NCRYPTED_BY_DATA_KEY\x10\x01\x12\x1b\n\x17\x45NCRYPTED_BY_PUBLIC_KEY\x10\x02\x12\x1d\n\x19\x45NCRYPTED_BY_DATA_KEY_GCM\x10\x03\x12\x1f\n\x1b\x45NCRYPTED_BY_PUBLIC_KEY_ECC\x10\x04*:\n\x15\x42\x61\x63kupUserDataKeyType\x12\x07\n\x03OWN\x10\x00\x12\x18\n\x14SHARED_TO_ENTERPRISE\x10\x01*\xa5\x01\n\x10\x45ncryptedKeyType\x12\r\n\tKT_NO_KEY\x10\x00\x12\x1c\n\x18KT_ENCRYPTED_BY_DATA_KEY\x10\x01\x12\x1e\n\x1aKT_ENCRYPTED_BY_PUBLIC_KEY\x10\x02\x12 \n\x1cKT_ENCRYPTED_BY_DATA_KEY_GCM\x10\x03\x12\"\n\x1eKT_ENCRYPTED_BY_PUBLIC_KEY_ECC\x10\x04*\xb7\x02\n\x12\x45nterpriseFlagType\x12\x0b\n\x07INVALID\x10\x00\x12\x1a\n\x16\x41LLOW_PERSONAL_LICENSE\x10\x01\x12\x18\n\x14SPECIAL_PROVISIONING\x10\x02\x12\x10\n\x0cRECORD_TYPES\x10\x03\x12\x13\n\x0fSECRETS_MANAGER\x10\x04\x12\x15\n\x11\x45NTERPRISE_LOCKED\x10\x05\x12\x15\n\x11\x46ORBID_KEY_TYPE_2\x10\x06\x12\x15\n\x11\x43ONSOLE_ONBOARDED\x10\x07\x12\x1b\n\x17\x46ORBID_ACCOUNT_TRANSFER\x10\x08\x12\x15\n\x11NPS_POPUP_OPT_OUT\x10\t\x12\x15\n\x11SHOW_USER_ONBOARD\x10\n\x12\x15\n\x11\x46ORBID_KEY_TYPE_1\x10\x0b\x12\x10\n\x0cKEEPER_DRIVE\x10\x0c*E\n\x10UserUpdateStatus\x12\x12\n\x0eUSER_UPDATE_OK\x10\x00\x12\x1d\n\x19USER_UPDATE_ACCESS_DENIED\x10\x01*I\n\x0f\x41uditUserStatus\x12\x06\n\x02OK\x10\x00\x12\x11\n\rACCESS_DENIED\x10\x01\x12\x1b\n\x17NO_LONGER_IN_ENTERPRISE\x10\x02*3\n\x0cTeamUserType\x12\x08\n\x04USER\x10\x00\x12\t\n\x05\x41\x44MIN\x10\x01\x12\x0e\n\nADMIN_ONLY\x10\x02*x\n\rAppClientType\x12\x0c\n\x08NOT_USED\x10\x00\x12\x0b\n\x07GENERAL\x10\x01\x12%\n!DISCOVERY_AND_ROTATION_CONTROLLER\x10\x02\x12\x12\n\x0eKCM_CONTROLLER\x10\x03\x12\x11\n\rSELF_DESTRUCT\x10\x04*\x8f\x01\n\x1b\x44\x65leteEnterpriseUsersResult\x12\x0b\n\x07SUCCESS\x10\x00\x12\x1a\n\x16NOT_AN_ENTERPRISE_USER\x10\x01\x12\x16\n\x12\x43\x41NNOT_DELETE_SELF\x10\x02\x12$\n BRIDGE_CANNOT_DELETE_ACTIVE_USER\x10\x03\x12\t\n\x05\x45RROR\x10\x04*\x87\x01\n\x15\x43learSecurityDataType\x12\x1e\n\x1aRECALCULATE_SUMMARY_REPORT\x10\x00\x12\'\n#FORCE_CLIENT_CHECK_FOR_MISSING_DATA\x10\x01\x12%\n!FORCE_CLIENT_RESEND_SECURITY_DATA\x10\x02*J\n\x13ReserveDomainAction\x12\x10\n\x0c\x44OMAIN_TOKEN\x10\x00\x12\x0e\n\nDOMAIN_ADD\x10\x01\x12\x11\n\rDOMAIN_DELETE\x10\x02*s\n\x0eUserLockStatus\x12\x17\n\x13UNKNOWN_LOCK_STATUS\x10\x00\x12\n\n\x06LOCKED\x10\x01\x12\x0c\n\x08\x44ISABLED\x10\x02\x12\x0c\n\x08UNLOCKED\x10\x03\x12\x0b\n\x07\x44\x45LETED\x10\x04\x12\x13\n\x0f\x43\x41NT_BE_PENDING\x10\x05*\x80\x01\n\x1d\x45xternalCloudSecretsStoreType\x12\x16\n\x12UNKNOWN_STORE_TYPE\x10\x00\x12\x17\n\x13\x41WS_SECRETS_MANAGER\x10\x01\x12\x13\n\x0f\x41ZURE_KEY_VAULT\x10\x02\x12\x19\n\x15GOOGLE_SECRET_MANAGER\x10\x03\x42&\n\x18\x63om.keepersecurity.protoB\nEnterpriseb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10\x65nterprise.proto\x12\nEnterprise\x1a\x0c\x66older.proto\"\x84\x01\n\x18\x45nterpriseKeyPairRequest\x12\x1b\n\x13\x65nterprisePublicKey\x18\x01 \x01(\x0c\x12%\n\x1d\x65ncryptedEnterprisePrivateKey\x18\x02 \x01(\x0c\x12$\n\x07keyType\x18\x03 \x01(\x0e\x32\x13.Enterprise.KeyType\"\'\n\x14GetTeamMemberRequest\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\"}\n\x0e\x45nterpriseUser\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\r\n\x05\x65mail\x18\x02 \x01(\t\x12\x1a\n\x12\x65nterpriseUsername\x18\x03 \x01(\t\x12\x14\n\x0cisShareAdmin\x18\x04 \x01(\x08\x12\x10\n\x08username\x18\x05 \x01(\t\"K\n\x15GetTeamMemberResponse\x12\x32\n\x0e\x65nterpriseUser\x18\x01 \x03(\x0b\x32\x1a.Enterprise.EnterpriseUser\"-\n\x11\x45nterpriseUserIds\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x03(\x03\"B\n\x19\x45nterprisePersonalAccount\x12\r\n\x05\x65mail\x18\x01 \x01(\t\x12\x16\n\x0eOBSOLETE_FIELD\x18\x02 \x01(\x0c\"S\n\x17\x45ncryptedTeamKeyRequest\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x18\n\x10\x65ncryptedTeamKey\x18\x02 \x01(\x0c\x12\r\n\x05\x66orce\x18\x03 \x01(\x08\"+\n\x0fReEncryptedData\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"?\n\x12ReEncryptedRoleKey\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x18\n\x10\x65ncryptedRoleKey\x18\x02 \x01(\x0c\"P\n\x16ReEncryptedUserDataKey\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1c\n\x14userEncryptedDataKey\x18\x02 \x01(\x0c\"\xd8\x02\n\x1bNodeToManagedCompanyRequest\x12\x11\n\tcompanyId\x18\x01 \x01(\x05\x12*\n\x05nodes\x18\x02 \x03(\x0b\x32\x1b.Enterprise.ReEncryptedData\x12*\n\x05roles\x18\x03 \x03(\x0b\x32\x1b.Enterprise.ReEncryptedData\x12*\n\x05users\x18\x04 \x03(\x0b\x32\x1b.Enterprise.ReEncryptedData\x12\x30\n\x08roleKeys\x18\x05 \x03(\x0b\x32\x1e.Enterprise.ReEncryptedRoleKey\x12\x35\n\x08teamKeys\x18\x06 \x03(\x0b\x32#.Enterprise.EncryptedTeamKeyRequest\x12\x39\n\rusersDataKeys\x18\x07 \x03(\x0b\x32\".Enterprise.ReEncryptedUserDataKey\",\n\x08RoleTeam\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x0f\n\x07teamUid\x18\x02 \x01(\x0c\"4\n\tRoleTeams\x12\'\n\trole_team\x18\x01 \x03(\x0b\x32\x14.Enterprise.RoleTeam\"/\n\x0bTeamsByRole\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x0f\n\x07teamUid\x18\x02 \x03(\x0c\"<\n\x12ManagedNodesByRole\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x15\n\rmanagedNodeId\x18\x02 \x03(\x03\"\x82\x01\n\x0fRoleUserAddKeys\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x13\n\x07treeKey\x18\x02 \x01(\tB\x02\x18\x01\x12\x14\n\x0croleAdminKey\x18\x03 \x01(\t\x12*\n\x0ctypedTreeKey\x18\x04 \x01(\x0b\x32\x14.Enterprise.TypedKey\"T\n\x0bRoleUserAdd\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x34\n\x0froleUserAddKeys\x18\x02 \x03(\x0b\x32\x1b.Enterprise.RoleUserAddKeys\"D\n\x13RoleUsersAddRequest\x12-\n\x0croleUserAdds\x18\x01 \x03(\x0b\x32\x17.Enterprise.RoleUserAdd\"\x80\x01\n\x11RoleUserAddResult\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\x12\x30\n\x06status\x18\x03 \x01(\x0e\x32 .Enterprise.RoleUserModifyStatus\x12\x0f\n\x07message\x18\x04 \x01(\t\"F\n\x14RoleUsersAddResponse\x12.\n\x07results\x18\x01 \x03(\x0b\x32\x1d.Enterprise.RoleUserAddResult\"<\n\x0eRoleUserRemove\x12\x0f\n\x07role_id\x18\x01 \x01(\x03\x12\x19\n\x11\x65nterpriseUserIds\x18\x02 \x03(\x03\"M\n\x16RoleUsersRemoveRequest\x12\x33\n\x0froleUserRemoves\x18\x01 \x03(\x0b\x32\x1a.Enterprise.RoleUserRemove\"\x83\x01\n\x14RoleUserRemoveResult\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\x12\x30\n\x06status\x18\x03 \x01(\x0e\x32 .Enterprise.RoleUserModifyStatus\x12\x0f\n\x07message\x18\x04 \x01(\t\"L\n\x17RoleUsersRemoveResponse\x12\x31\n\x07results\x18\x01 \x03(\x0b\x32 .Enterprise.RoleUserRemoveResult\"\xa0\x04\n\x16\x45nterpriseRegistration\x12\x18\n\x10\x65ncryptedTreeKey\x18\x01 \x01(\x0c\x12\x16\n\x0e\x65nterpriseName\x18\x02 \x01(\t\x12\x14\n\x0crootNodeData\x18\x03 \x01(\x0c\x12\x15\n\radminUserData\x18\x04 \x01(\x0c\x12\x11\n\tadminName\x18\x05 \x01(\t\x12\x10\n\x08roleData\x18\x06 \x01(\x0c\x12\x38\n\nrsaKeyPair\x18\x07 \x01(\x0b\x32$.Enterprise.EnterpriseKeyPairRequest\x12\x13\n\x0bnumberSeats\x18\x08 \x01(\x05\x12\x32\n\x0e\x65nterpriseType\x18\t \x01(\x0e\x32\x1a.Enterprise.EnterpriseType\x12\x15\n\rrolePublicKey\x18\n \x01(\x0c\x12*\n\"rolePrivateKeyEncryptedWithRoleKey\x18\x0b \x01(\x0c\x12#\n\x1broleKeyEncryptedWithTreeKey\x18\x0c \x01(\x0c\x12\x38\n\neccKeyPair\x18\r \x01(\x0b\x32$.Enterprise.EnterpriseKeyPairRequest\x12\x18\n\x10\x61llUsersRoleData\x18\x0e \x01(\x0c\x12)\n!roleKeyEncryptedWithUserPublicKey\x18\x0f \x01(\x0c\x12\x18\n\x10\x61pproverRoleData\x18\x10 \x01(\x0c\"H\n\x1a\x44omainPasswordRulesRequest\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x18\n\x10verificationCode\x18\x02 \x01(\t\"\\\n\x19\x44omainPasswordRulesFields\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0f\n\x07minimum\x18\x02 \x01(\x05\x12\x0f\n\x07maximum\x18\x03 \x01(\x05\x12\x0f\n\x07\x61llowed\x18\x04 \x01(\x08\"E\n\x10LoginToMcRequest\x12\x16\n\x0emcEnterpriseId\x18\x01 \x01(\x05\x12\x19\n\x11messageSessionUid\x18\x02 \x01(\x0c\"w\n\x11LoginToMcResponse\x12\x1d\n\x15\x65ncryptedSessionToken\x18\x01 \x01(\x0c\x12\x18\n\x10\x65ncryptedTreeKey\x18\x02 \x01(\t\x12\x11\n\tkeyTypeId\x18\x03 \x01(\x05\x12\x16\n\x0e\x66orbidKeyType2\x18\x04 \x01(\x08\"g\n\x1b\x44omainPasswordRulesResponse\x12H\n\x19\x64omainPasswordRulesFields\x18\x01 \x03(\x0b\x32%.Enterprise.DomainPasswordRulesFields\"\x88\x01\n\x18\x41pproveUserDeviceRequest\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1c\n\x14\x65ncryptedDeviceToken\x18\x02 \x01(\x0c\x12\x1e\n\x16\x65ncryptedDeviceDataKey\x18\x03 \x01(\x0c\x12\x14\n\x0c\x64\x65nyApproval\x18\x04 \x01(\x08\"t\n\x19\x41pproveUserDeviceResponse\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1c\n\x14\x65ncryptedDeviceToken\x18\x02 \x01(\x0c\x12\x0e\n\x06\x66\x61iled\x18\x03 \x01(\x08\x12\x0f\n\x07message\x18\x04 \x01(\t\"Y\n\x19\x41pproveUserDevicesRequest\x12<\n\x0e\x64\x65viceRequests\x18\x01 \x03(\x0b\x32$.Enterprise.ApproveUserDeviceRequest\"\\\n\x1a\x41pproveUserDevicesResponse\x12>\n\x0f\x64\x65viceResponses\x18\x01 \x03(\x0b\x32%.Enterprise.ApproveUserDeviceResponse\"\x87\x01\n\x15\x45nterpriseUserDataKey\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1c\n\x14userEncryptedDataKey\x18\x02 \x01(\x0c\x12\x11\n\tkeyTypeId\x18\x03 \x01(\x05\x12\x0f\n\x07roleKey\x18\x04 \x01(\x0c\x12\x12\n\nprivateKey\x18\x05 \x01(\x0c\"I\n\x16\x45nterpriseUserDataKeys\x12/\n\x04keys\x18\x01 \x03(\x0b\x32!.Enterprise.EnterpriseUserDataKey\"g\n\x1a\x45nterpriseUserDataKeyLight\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1c\n\x14userEncryptedDataKey\x18\x02 \x01(\x0c\x12\x11\n\tkeyTypeId\x18\x03 \x01(\x05\"d\n\x1c\x45nterpriseUserDataKeysByNode\x12\x0e\n\x06nodeId\x18\x01 \x01(\x03\x12\x34\n\x04keys\x18\x02 \x03(\x0b\x32&.Enterprise.EnterpriseUserDataKeyLight\"^\n$EnterpriseUserDataKeysByNodeResponse\x12\x36\n\x04keys\x18\x01 \x03(\x0b\x32(.Enterprise.EnterpriseUserDataKeysByNode\"2\n\x15\x45nterpriseDataRequest\x12\x19\n\x11\x63ontinuationToken\x18\x01 \x01(\x0c\"0\n\x13SpecialProvisioning\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"\x84\x02\n\x11GeneralDataEntity\x12\x16\n\x0e\x65nterpriseName\x18\x01 \x01(\t\x12\x1a\n\x12restrictVisibility\x18\x02 \x01(\x08\x12<\n\x13specialProvisioning\x18\x04 \x01(\x0b\x32\x1f.Enterprise.SpecialProvisioning\x12\x30\n\ruserPrivilege\x18\x07 \x01(\x0b\x32\x19.Enterprise.UserPrivilege\x12\x13\n\x0b\x64istributor\x18\x08 \x01(\x08\x12\x1d\n\x15\x66orbidAccountTransfer\x18\t \x01(\x08\x12\x17\n\x0fshowUserOnboard\x18\n \x01(\x08\"\xfd\x01\n\x04Node\x12\x0e\n\x06nodeId\x18\x01 \x01(\x03\x12\x10\n\x08parentId\x18\x02 \x01(\x03\x12\x10\n\x08\x62ridgeId\x18\x03 \x01(\x03\x12\x0e\n\x06scimId\x18\x04 \x01(\x03\x12\x11\n\tlicenseId\x18\x05 \x01(\x03\x12\x15\n\rencryptedData\x18\x06 \x01(\t\x12\x12\n\nduoEnabled\x18\x07 \x01(\x08\x12\x12\n\nrsaEnabled\x18\x08 \x01(\x08\x12 \n\x14ssoServiceProviderId\x18\t \x01(\x03\x42\x02\x18\x01\x12\x1a\n\x12restrictVisibility\x18\n \x01(\x08\x12!\n\x15ssoServiceProviderIds\x18\x0b \x03(\x03\x42\x02\x10\x01\"\x8e\x01\n\x04Role\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x15\n\rencryptedData\x18\x03 \x01(\t\x12\x0f\n\x07keyType\x18\x04 \x01(\t\x12\x14\n\x0cvisibleBelow\x18\x05 \x01(\x08\x12\x16\n\x0enewUserInherit\x18\x06 \x01(\x08\x12\x10\n\x08roleType\x18\x07 \x01(\t\"\xb8\x02\n\x04User\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x15\n\rencryptedData\x18\x03 \x01(\t\x12\x0f\n\x07keyType\x18\x04 \x01(\t\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x0e\n\x06status\x18\x06 \x01(\t\x12\x0c\n\x04lock\x18\x07 \x01(\x05\x12\x0e\n\x06userId\x18\x08 \x01(\x05\x12\x1e\n\x16\x61\x63\x63ountShareExpiration\x18\t \x01(\x03\x12\x10\n\x08\x66ullName\x18\n \x01(\t\x12\x10\n\x08jobTitle\x18\x0b \x01(\t\x12\x12\n\ntfaEnabled\x18\x0c \x01(\x08\x12\x46\n\x18transferAcceptanceStatus\x18\r \x01(\x0e\x32$.Enterprise.TransferAcceptanceStatus\"7\n\tUserAlias\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x10\n\x08username\x18\x02 \x01(\t\"\xac\x01\n\x18\x43omplianceReportMetaData\x12\x11\n\treportUid\x18\x01 \x01(\x0c\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x12\n\nreportName\x18\x03 \x01(\t\x12\x15\n\rdateGenerated\x18\x04 \x01(\x03\x12\x11\n\trunByName\x18\x05 \x01(\t\x12\x16\n\x0enumberOfOwners\x18\x07 \x01(\x05\x12\x17\n\x0fnumberOfRecords\x18\x08 \x01(\x05\"S\n\x0bManagedNode\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x15\n\rmanagedNodeId\x18\x02 \x01(\x03\x12\x1d\n\x15\x63\x61scadeNodeManagement\x18\x03 \x01(\x08\"T\n\x0fUserManagedNode\x12\x0e\n\x06nodeId\x18\x01 \x01(\x03\x12\x1d\n\x15\x63\x61scadeNodeManagement\x18\x02 \x01(\x08\x12\x12\n\nprivileges\x18\x03 \x03(\t\"w\n\rUserPrivilege\x12\x35\n\x10userManagedNodes\x18\x01 \x03(\x0b\x32\x1b.Enterprise.UserManagedNode\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\x12\x15\n\rencryptedData\x18\x03 \x01(\t\"4\n\x08RoleUser\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\"M\n\rRolePrivilege\x12\x15\n\rmanagedNodeId\x18\x01 \x01(\x03\x12\x0e\n\x06roleId\x18\x02 \x01(\x03\x12\x15\n\rprivilegeType\x18\x03 \x01(\t\"T\n\x17PrivilegesByManagedNode\x12\x15\n\rmanagedNodeId\x18\x01 \x01(\x03\x12\x0e\n\x06roleId\x18\x02 \x01(\x03\x12\x12\n\nprivileges\x18\x03 \x03(\t\"I\n\x0fRoleEnforcement\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x17\n\x0f\x65nforcementType\x18\x02 \x01(\t\x12\r\n\x05value\x18\x03 \x01(\t\"\xa9\x01\n\x04Team\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06nodeId\x18\x03 \x01(\x03\x12\x14\n\x0crestrictEdit\x18\x04 \x01(\x08\x12\x15\n\rrestrictShare\x18\x05 \x01(\x08\x12\x14\n\x0crestrictView\x18\x06 \x01(\x08\x12\x15\n\rencryptedData\x18\x07 \x01(\t\x12\x18\n\x10\x65ncryptedTeamKey\x18\x08 \x01(\t\"G\n\x08TeamUser\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\x12\x10\n\x08userType\x18\x03 \x01(\t\"K\n\x1aGetDistributorInfoResponse\x12-\n\x0c\x64istributors\x18\x01 \x03(\x0b\x32\x17.Enterprise.Distributor\"B\n\x0b\x44istributor\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\x08mspInfos\x18\x02 \x03(\x0b\x32\x13.Enterprise.MspInfo\"\x9d\x02\n\x07MspInfo\x12\x14\n\x0c\x65nterpriseId\x18\x01 \x01(\x05\x12\x16\n\x0e\x65nterpriseName\x18\x02 \x01(\t\x12\x19\n\x11\x61llocatedLicenses\x18\x03 \x01(\x05\x12\x19\n\x11\x61llowedMcProducts\x18\x04 \x03(\t\x12\x15\n\rallowedAddOns\x18\x05 \x03(\t\x12\x17\n\x0fmaxFilePlanType\x18\x06 \x01(\t\x12\x34\n\x10managedCompanies\x18\x07 \x03(\x0b\x32\x1a.Enterprise.ManagedCompany\x12\x1e\n\x16\x61llowUnlimitedLicenses\x18\x08 \x01(\x08\x12(\n\x06\x61\x64\x64Ons\x18\t \x03(\x0b\x32\x18.Enterprise.LicenseAddOn\"\xa8\x02\n\x0eManagedCompany\x12\x16\n\x0emcEnterpriseId\x18\x01 \x01(\x05\x12\x18\n\x10mcEnterpriseName\x18\x02 \x01(\t\x12\x11\n\tmspNodeId\x18\x03 \x01(\x03\x12\x15\n\rnumberOfSeats\x18\x04 \x01(\x05\x12\x15\n\rnumberOfUsers\x18\x05 \x01(\x05\x12\x11\n\tproductId\x18\x06 \x01(\t\x12\x11\n\tisExpired\x18\x07 \x01(\x08\x12\x0f\n\x07treeKey\x18\x08 \x01(\t\x12\x15\n\rtree_key_role\x18\t \x01(\x03\x12\x14\n\x0c\x66ilePlanType\x18\n \x01(\t\x12(\n\x06\x61\x64\x64Ons\x18\x0b \x03(\x0b\x32\x18.Enterprise.LicenseAddOn\x12\x15\n\rtreeKeyTypeId\x18\x0c \x01(\x05\"R\n\x07MSPPool\x12\x11\n\tproductId\x18\x01 \x01(\t\x12\r\n\x05seats\x18\x02 \x01(\x05\x12\x16\n\x0e\x61vailableSeats\x18\x03 \x01(\x05\x12\r\n\x05stash\x18\x04 \x01(\x05\":\n\nMSPContact\x12\x14\n\x0c\x65nterpriseId\x18\x01 \x01(\x05\x12\x16\n\x0e\x65nterpriseName\x18\x02 \x01(\t\"\x84\x02\n\x0cLicenseAddOn\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x65nabled\x18\x02 \x01(\x08\x12\x0f\n\x07isTrial\x18\x03 \x01(\x08\x12\x12\n\nexpiration\x18\x04 \x01(\x03\x12\x0f\n\x07\x63reated\x18\x05 \x01(\x03\x12\r\n\x05seats\x18\x06 \x01(\x05\x12\x16\n\x0e\x61\x63tivationTime\x18\x07 \x01(\x03\x12\x19\n\x11includedInProduct\x18\x08 \x01(\x08\x12\x14\n\x0c\x61piCallCount\x18\t \x01(\x05\x12\x17\n\x0ftierDescription\x18\n \x01(\t\x12\x16\n\x0eseatsAllocated\x18\x0b \x01(\x05\x12\x16\n\x0enhiTierAddOnId\x18\x0c \x01(\x05\"s\n\tMCDefault\x12\x11\n\tmcProduct\x18\x01 \x01(\t\x12\x0e\n\x06\x61\x64\x64Ons\x18\x02 \x03(\t\x12\x14\n\x0c\x66ilePlanType\x18\x03 \x01(\t\x12\x13\n\x0bmaxLicenses\x18\x04 \x01(\x05\x12\x18\n\x10\x66ixedMaxLicenses\x18\x05 \x01(\x08\"\xd2\x01\n\nMSPPermits\x12\x12\n\nrestricted\x18\x01 \x01(\x08\x12\x1a\n\x12maxAllowedLicenses\x18\x02 \x01(\x05\x12\x19\n\x11\x61llowedMcProducts\x18\x03 \x03(\t\x12\x15\n\rallowedAddOns\x18\x04 \x03(\t\x12\x17\n\x0fmaxFilePlanType\x18\x05 \x01(\t\x12\x1e\n\x16\x61llowUnlimitedLicenses\x18\x06 \x01(\x08\x12)\n\nmcDefaults\x18\x07 \x03(\x0b\x32\x15.Enterprise.MCDefault\"\xa0\x04\n\x07License\x12\x0c\n\x04paid\x18\x01 \x01(\x08\x12\x15\n\rnumberOfSeats\x18\x02 \x01(\x05\x12\x12\n\nexpiration\x18\x03 \x01(\x03\x12\x14\n\x0clicenseKeyId\x18\x04 \x01(\x05\x12\x15\n\rproductTypeId\x18\x05 \x01(\x05\x12\x0c\n\x04name\x18\x06 \x01(\t\x12\x1b\n\x13\x65nterpriseLicenseId\x18\x07 \x01(\x03\x12\x16\n\x0eseatsAllocated\x18\x08 \x01(\x05\x12\x14\n\x0cseatsPending\x18\t \x01(\x05\x12\x0c\n\x04tier\x18\n \x01(\x05\x12\x16\n\x0e\x66ilePlanTypeId\x18\x0b \x01(\x05\x12\x10\n\x08maxBytes\x18\x0c \x01(\x03\x12\x19\n\x11storageExpiration\x18\r \x01(\x03\x12\x15\n\rlicenseStatus\x18\x0e \x01(\t\x12$\n\x07mspPool\x18\x0f \x03(\x0b\x32\x13.Enterprise.MSPPool\x12)\n\tmanagedBy\x18\x10 \x01(\x0b\x32\x16.Enterprise.MSPContact\x12(\n\x06\x61\x64\x64Ons\x18\x11 \x03(\x0b\x32\x18.Enterprise.LicenseAddOn\x12\x17\n\x0fnextBillingDate\x18\x12 \x01(\x03\x12\x17\n\x0fhasMSPLegacyLog\x18\x13 \x01(\x08\x12*\n\nmspPermits\x18\x14 \x01(\x0b\x32\x16.Enterprise.MSPPermits\x12\x13\n\x0b\x64istributor\x18\x15 \x01(\x08\"n\n\x06\x42ridge\x12\x10\n\x08\x62ridgeId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x18\n\x10wanIpEnforcement\x18\x03 \x01(\t\x12\x18\n\x10lanIpEnforcement\x18\x04 \x01(\t\x12\x0e\n\x06status\x18\x05 \x01(\t\"t\n\x04Scim\x12\x0e\n\x06scimId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x0e\n\x06status\x18\x03 \x01(\t\x12\x12\n\nlastSynced\x18\x04 \x01(\x03\x12\x12\n\nrolePrefix\x18\x05 \x01(\t\x12\x14\n\x0cuniqueGroups\x18\x06 \x01(\x08\"L\n\x0e\x45mailProvision\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x0e\n\x06\x64omain\x18\x03 \x01(\t\x12\x0e\n\x06method\x18\x04 \x01(\t\"R\n\nQueuedTeam\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06nodeId\x18\x03 \x01(\x03\x12\x15\n\rencryptedData\x18\x04 \x01(\t\"0\n\x0eQueuedTeamUser\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\r\n\x05users\x18\x02 \x03(\x03\"\xa4\x01\n\x0eTeamsAddResult\x12\x34\n\x11successfulTeamAdd\x18\x01 \x03(\x0b\x32\x19.Enterprise.TeamAddResult\x12\x36\n\x13unsuccessfulTeamAdd\x18\x02 \x03(\x0b\x32\x19.Enterprise.TeamAddResult\x12\x0e\n\x06result\x18\x03 \x01(\t\x12\x14\n\x0c\x65rrorMessage\x18\x04 \x01(\t\"U\n\rTeamAddResult\x12\x1e\n\x04team\x18\x01 \x01(\x0b\x32\x10.Enterprise.Team\x12\x0e\n\x06result\x18\x02 \x01(\t\x12\x14\n\x0c\x65rrorMessage\x18\x03 \x01(\t\"\x91\x01\n\nSsoService\x12\x1c\n\x14ssoServiceProviderId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0e\n\x06sp_url\x18\x04 \x01(\t\x12\x16\n\x0einviteNewUsers\x18\x05 \x01(\x08\x12\x0e\n\x06\x61\x63tive\x18\x06 \x01(\x08\x12\x0f\n\x07isCloud\x18\x07 \x01(\x08\"1\n\x10ReportFilterUser\x12\x0e\n\x06userId\x18\x01 \x01(\x05\x12\r\n\x05\x65mail\x18\x02 \x01(\t\"\x97\x02\n\x1d\x44\x65viceRequestForAdminApproval\x12\x10\n\x08\x64\x65viceId\x18\x01 \x01(\x03\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\x12\x1c\n\x14\x65ncryptedDeviceToken\x18\x03 \x01(\x0c\x12\x17\n\x0f\x64\x65vicePublicKey\x18\x04 \x01(\x0c\x12\x12\n\ndeviceName\x18\x05 \x01(\t\x12\x15\n\rclientVersion\x18\x06 \x01(\t\x12\x12\n\ndeviceType\x18\x07 \x01(\t\x12\x0c\n\x04\x64\x61te\x18\x08 \x01(\x03\x12\x11\n\tipAddress\x18\t \x01(\t\x12\x10\n\x08location\x18\n \x01(\t\x12\r\n\x05\x65mail\x18\x0b \x01(\t\x12\x12\n\naccountUid\x18\x0c \x01(\x0c\"`\n\x0e\x45nterpriseData\x12\x30\n\x06\x65ntity\x18\x01 \x01(\x0e\x32 .Enterprise.EnterpriseDataEntity\x12\x0e\n\x06\x64\x65lete\x18\x02 \x01(\x08\x12\x0c\n\x04\x64\x61ta\x18\x03 \x03(\x0c\"\xd0\x01\n\x16\x45nterpriseDataResponse\x12\x19\n\x11\x63ontinuationToken\x18\x01 \x01(\x0c\x12\x0f\n\x07hasMore\x18\x02 \x01(\x08\x12,\n\x0b\x63\x61\x63heStatus\x18\x03 \x01(\x0e\x32\x17.Enterprise.CacheStatus\x12(\n\x04\x64\x61ta\x18\x04 \x03(\x0b\x32\x1a.Enterprise.EnterpriseData\x12\x32\n\x0bgeneralData\x18\x05 \x01(\x0b\x32\x1d.Enterprise.GeneralDataEntity\"*\n\rBackupRequest\x12\x19\n\x11\x63ontinuationToken\x18\x01 \x01(\x0c\"\x98\x01\n\x0c\x42\x61\x63kupRecord\x12\x0e\n\x06userId\x18\x01 \x01(\x05\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x0b\n\x03key\x18\x03 \x01(\x0c\x12*\n\x07keyType\x18\x04 \x01(\x0e\x32\x19.Enterprise.BackupKeyType\x12\x0f\n\x07version\x18\x05 \x01(\x05\x12\x0c\n\x04\x64\x61ta\x18\x06 \x01(\x0c\x12\r\n\x05\x65xtra\x18\x07 \x01(\x0c\".\n\tBackupKey\x12\x0e\n\x06userId\x18\x01 \x01(\x05\x12\x11\n\tbackupKey\x18\x02 \x01(\x0c\"\x8d\x02\n\nBackupUser\x12\x0e\n\x06userId\x18\x01 \x01(\x05\x12\x10\n\x08userName\x18\x02 \x01(\t\x12\x0f\n\x07\x64\x61taKey\x18\x03 \x01(\x0c\x12\x36\n\x0b\x64\x61taKeyType\x18\x04 \x01(\x0e\x32!.Enterprise.BackupUserDataKeyType\x12\x12\n\nprivateKey\x18\x05 \x01(\x0c\x12\x0f\n\x07treeKey\x18\x06 \x01(\x0c\x12.\n\x0btreeKeyType\x18\x07 \x01(\x0e\x32\x19.Enterprise.BackupKeyType\x12)\n\nbackupKeys\x18\x08 \x03(\x0b\x32\x15.Enterprise.BackupKey\x12\x14\n\x0cprivateECKey\x18\t \x01(\x0c\"\x9e\x01\n\x0e\x42\x61\x63kupResponse\x12\x1f\n\x17\x65nterpriseEccPrivateKey\x18\x01 \x01(\x0c\x12%\n\x05users\x18\x02 \x03(\x0b\x32\x16.Enterprise.BackupUser\x12)\n\x07records\x18\x03 \x03(\x0b\x32\x18.Enterprise.BackupRecord\x12\x19\n\x11\x63ontinuationToken\x18\x04 \x01(\x0c\"e\n\nBackupFile\x12\x0c\n\x04user\x18\x01 \x01(\t\x12\x11\n\tbackupUid\x18\x02 \x01(\x0c\x12\x10\n\x08\x66ileName\x18\x03 \x01(\t\x12\x0f\n\x07\x63reated\x18\x04 \x01(\x03\x12\x13\n\x0b\x64ownloadUrl\x18\x05 \x01(\t\"8\n\x0f\x42\x61\x63kupsResponse\x12%\n\x05\x66iles\x18\x01 \x03(\x0b\x32\x16.Enterprise.BackupFile\".\n\x1cGetEnterpriseDataKeysRequest\x12\x0e\n\x06roleId\x18\x01 \x03(\x03\"\xff\x01\n\x1dGetEnterpriseDataKeysResponse\x12:\n\x12reEncryptedRoleKey\x18\x01 \x03(\x0b\x32\x1e.Enterprise.ReEncryptedRoleKey\x12$\n\x07roleKey\x18\x02 \x03(\x0b\x32\x13.Enterprise.RoleKey\x12\"\n\x06mspKey\x18\x03 \x01(\x0b\x32\x12.Enterprise.MspKey\x12\x32\n\x0e\x65nterpriseKeys\x18\x04 \x01(\x0b\x32\x1a.Enterprise.EnterpriseKeys\x12$\n\x07treeKey\x18\x05 \x01(\x0b\x32\x13.Enterprise.TreeKey\"^\n\x07RoleKey\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x14\n\x0c\x65ncryptedKey\x18\x02 \x01(\t\x12-\n\x07keyType\x18\x03 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\"d\n\x06MspKey\x12\x1b\n\x13\x65ncryptedMspTreeKey\x18\x01 \x01(\t\x12=\n\x17\x65ncryptedMspTreeKeyType\x18\x02 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\"|\n\x0e\x45nterpriseKeys\x12\x14\n\x0crsaPublicKey\x18\x01 \x01(\x0c\x12\x1e\n\x16rsaEncryptedPrivateKey\x18\x02 \x01(\x0c\x12\x14\n\x0c\x65\x63\x63PublicKey\x18\x03 \x01(\x0c\x12\x1e\n\x16\x65\x63\x63\x45ncryptedPrivateKey\x18\x04 \x01(\x0c\"H\n\x07TreeKey\x12\x0f\n\x07treeKey\x18\x01 \x01(\t\x12,\n\tkeyTypeId\x18\x02 \x01(\x0e\x32\x19.Enterprise.BackupKeyType\"E\n\x14SharedRecordResponse\x12-\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x1d.Enterprise.SharedRecordEvent\"p\n\x11SharedRecordEvent\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x10\n\x08userName\x18\x02 \x01(\t\x12\x0f\n\x07\x63\x61nEdit\x18\x03 \x01(\x08\x12\x12\n\ncanReshare\x18\x04 \x01(\x08\x12\x11\n\tshareFrom\x18\x05 \x01(\x05\".\n\x1cSetRestrictVisibilityRequest\x12\x0e\n\x06nodeId\x18\x01 \x01(\x03\"\xd0\x01\n\x0eUserAddRequest\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x15\n\rencryptedData\x18\x03 \x01(\x0c\x12-\n\x07keyType\x18\x04 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\x12\x10\n\x08\x66ullName\x18\x05 \x01(\t\x12\x10\n\x08jobTitle\x18\x06 \x01(\t\x12\r\n\x05\x65mail\x18\x07 \x01(\t\x12\x1b\n\x13suppressEmailInvite\x18\x08 \x01(\x08\":\n\x11UserUpdateRequest\x12%\n\x05users\x18\x01 \x03(\x0b\x32\x16.Enterprise.UserUpdate\"\xe7\x01\n\nUserUpdate\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0e\n\x06nodeId\x18\x02 \x01(\x03\x12\x19\n\rencryptedData\x18\x03 \x01(\x0c\x42\x02\x18\x01\x12-\n\x07keyType\x18\x04 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\x12\x10\n\x08\x66ullName\x18\x05 \x01(\t\x12\x10\n\x08jobTitle\x18\x06 \x01(\t\x12\r\n\x05\x65mail\x18\x07 \x01(\t\x12\x15\n\rinviteeLocale\x18\x08 \x01(\t\x12\x1b\n\x13\x65ncryptedDataString\x18\t \x01(\t\"A\n\x12UserUpdateResponse\x12+\n\x05users\x18\x01 \x03(\x0b\x32\x1c.Enterprise.UserUpdateResult\"\x88\x01\n\x10UserUpdateResult\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12,\n\x06status\x18\x02 \x01(\x0e\x32\x1c.Enterprise.UserUpdateStatus\x12\x14\n\x0c\x65rrorMessage\x18\x03 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x04 \x01(\t\"J\n\x1d\x43omplianceRecordOwnersRequest\x12\x0f\n\x07nodeIds\x18\x01 \x03(\x03\x12\x18\n\x10includeNonShared\x18\x02 \x01(\x08\"O\n\x1e\x43omplianceRecordOwnersResponse\x12-\n\x0crecordOwners\x18\x01 \x03(\x0b\x32\x17.Enterprise.RecordOwner\"7\n\x0bRecordOwner\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0e\n\x06shared\x18\x02 \x01(\x08\"\xa6\x01\n PreliminaryComplianceDataRequest\x12\x19\n\x11\x65nterpriseUserIds\x18\x01 \x03(\x03\x12\x18\n\x10includeNonShared\x18\x02 \x01(\x08\x12\x19\n\x11\x63ontinuationToken\x18\x03 \x01(\x0c\x12\x32\n*includeTotalMatchingRecordsInFirstResponse\x18\x04 \x01(\x08\"\x9f\x01\n!PreliminaryComplianceDataResponse\x12\x30\n\rauditUserData\x18\x01 \x03(\x0b\x32\x19.Enterprise.AuditUserData\x12\x19\n\x11\x63ontinuationToken\x18\x02 \x01(\x0c\x12\x0f\n\x07hasMore\x18\x03 \x01(\x08\x12\x1c\n\x14totalMatchingRecords\x18\x04 \x01(\x05\"b\n\x0f\x41uditUserRecord\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x15\n\rencryptedData\x18\x02 \x01(\x0c\x12\x0e\n\x06shared\x18\x03 \x01(\x08\x12\x15\n\risDriveRecord\x18\x04 \x01(\x08\"\x8d\x01\n\rAuditUserData\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x35\n\x10\x61uditUserRecords\x18\x02 \x03(\x0b\x32\x1b.Enterprise.AuditUserRecord\x12+\n\x06status\x18\x03 \x01(\x0e\x32\x1b.Enterprise.AuditUserStatus\"\x7f\n\x17\x43omplianceReportFilters\x12\x14\n\x0crecordTitles\x18\x01 \x03(\t\x12\x12\n\nrecordUids\x18\x02 \x03(\x0c\x12\x11\n\tjobTitles\x18\x03 \x03(\x03\x12\x0c\n\x04urls\x18\x04 \x03(\t\x12\x19\n\x11\x65nterpriseUserIds\x18\x05 \x03(\x03\"\x7f\n\x17\x43omplianceReportRequest\x12<\n\x13\x63omplianceReportRun\x18\x01 \x01(\x0b\x32\x1f.Enterprise.ComplianceReportRun\x12\x12\n\nreportName\x18\x02 \x01(\t\x12\x12\n\nsaveReport\x18\x03 \x01(\x08\"\x85\x01\n\x13\x43omplianceReportRun\x12N\n\x17reportCriteriaAndFilter\x18\x01 \x01(\x0b\x32-.Enterprise.ComplianceReportCriteriaAndFilter\x12\r\n\x05users\x18\x02 \x03(\x03\x12\x0f\n\x07records\x18\x03 \x03(\x0c\"\xfc\x01\n!ComplianceReportCriteriaAndFilter\x12\x0e\n\x06nodeId\x18\x01 \x01(\x03\x12\x13\n\x0b\x63riteriaUid\x18\x02 \x01(\x0c\x12\x14\n\x0c\x63riteriaName\x18\x03 \x01(\t\x12\x36\n\x08\x63riteria\x18\x04 \x01(\x0b\x32$.Enterprise.ComplianceReportCriteria\x12\x33\n\x07\x66ilters\x18\x05 \x03(\x0b\x32\".Enterprise.ComplianceReportFilter\x12\x14\n\x0clastModified\x18\x06 \x01(\x03\x12\x19\n\x11nodeEncryptedData\x18\x07 \x01(\x0c\"b\n\x18\x43omplianceReportCriteria\x12\x11\n\tjobTitles\x18\x01 \x03(\t\x12\x19\n\x11\x65nterpriseUserIds\x18\x02 \x03(\x03\x12\x18\n\x10includeNonShared\x18\x03 \x01(\x08\"x\n\x16\x43omplianceReportFilter\x12\x14\n\x0crecordTitles\x18\x01 \x03(\t\x12\x12\n\nrecordUids\x18\x02 \x03(\x0c\x12\x11\n\tjobTitles\x18\x03 \x03(\t\x12\x0c\n\x04urls\x18\x04 \x03(\t\x12\x13\n\x0brecordTypes\x18\x05 \x03(\t\"\xa1\x05\n\x18\x43omplianceReportResponse\x12\x15\n\rdateGenerated\x18\x01 \x01(\x03\x12\x15\n\rrunByUserName\x18\x02 \x01(\t\x12\x12\n\nreportName\x18\x03 \x01(\t\x12\x11\n\treportUid\x18\x04 \x01(\x0c\x12<\n\x13\x63omplianceReportRun\x18\x05 \x01(\x0b\x32\x1f.Enterprise.ComplianceReportRun\x12-\n\x0cuserProfiles\x18\x06 \x03(\x0b\x32\x17.Enterprise.UserProfile\x12)\n\nauditTeams\x18\x07 \x03(\x0b\x32\x15.Enterprise.AuditTeam\x12-\n\x0c\x61uditRecords\x18\x08 \x03(\x0b\x32\x17.Enterprise.AuditRecord\x12+\n\x0buserRecords\x18\t \x03(\x0b\x32\x16.Enterprise.UserRecord\x12;\n\x13sharedFolderRecords\x18\n \x03(\x0b\x32\x1e.Enterprise.SharedFolderRecord\x12\x37\n\x11sharedFolderUsers\x18\x0b \x03(\x0b\x32\x1c.Enterprise.SharedFolderUser\x12\x37\n\x11sharedFolderTeams\x18\x0c \x03(\x0b\x32\x1c.Enterprise.SharedFolderTeam\x12\x31\n\x0e\x61uditTeamUsers\x18\r \x03(\x0b\x32\x19.Enterprise.AuditTeamUser\x12)\n\nauditRoles\x18\x0e \x03(\x0b\x32\x15.Enterprise.AuditRole\x12/\n\rlinkedRecords\x18\x0f \x03(\x0b\x32\x18.Enterprise.LinkedRecord\"\x98\x01\n\x0b\x41uditRecord\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x11\n\tauditData\x18\x02 \x01(\x0c\x12\x16\n\x0ehasAttachments\x18\x03 \x01(\x08\x12\x0f\n\x07inTrash\x18\x04 \x01(\x08\x12\x10\n\x08treeLeft\x18\x05 \x01(\x05\x12\x11\n\ttreeRight\x18\x06 \x01(\x05\x12\x15\n\risDriveRecord\x18\x07 \x01(\x08\"\x80\x02\n\tAuditRole\x12\x0e\n\x06roleId\x18\x01 \x01(\x03\x12\x15\n\rencryptedData\x18\x02 \x01(\x0c\x12&\n\x1erestrictShareOutsideEnterprise\x18\x03 \x01(\x08\x12\x18\n\x10restrictShareAll\x18\x04 \x01(\x08\x12\"\n\x1arestrictShareOfAttachments\x18\x05 \x01(\x08\x12)\n!restrictMaskPasswordsWhileEditing\x18\x06 \x01(\x08\x12;\n\x13roleNodeManagements\x18\x07 \x03(\x0b\x32\x1e.Enterprise.RoleNodeManagement\"^\n\x12RoleNodeManagement\x12\x10\n\x08treeLeft\x18\x01 \x01(\x05\x12\x11\n\ttreeRight\x18\x02 \x01(\x05\x12\x0f\n\x07\x63\x61scade\x18\x03 \x01(\x08\x12\x12\n\nprivileges\x18\x04 \x01(\x05\"k\n\x0bUserProfile\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x10\n\x08\x66ullName\x18\x02 \x01(\t\x12\x10\n\x08jobTitle\x18\x03 \x01(\t\x12\r\n\x05\x65mail\x18\x04 \x01(\t\x12\x0f\n\x07roleIds\x18\x05 \x03(\x03\"{\n\x10RecordPermission\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x18\n\x0epermissionBits\x18\x02 \x01(\x05H\x00\x12,\n\x05\x64rive\x18\x03 \x01(\x0b\x32\x1b.Enterprise.DrivePermissionH\x00\x42\x0c\n\npermission\"\xc7\x01\n\x0f\x44rivePermission\x12\r\n\x05owner\x18\x01 \x01(\x08\x12\x0e\n\x06\x64\x65nied\x18\x02 \x01(\x08\x12\x0f\n\x07\x63\x61nEdit\x18\x03 \x01(\x08\x12\x10\n\x08\x63\x61nShare\x18\x04 \x01(\x08\x12\x14\n\x0cisShareAdmin\x18\x05 \x01(\x08\x12&\n\naccessType\x18\x06 \x01(\x0e\x32\x12.Folder.AccessType\x12\x34\n\x11\x66olderPermissions\x18\x07 \x01(\x0b\x32\x19.Folder.FolderPermissions\"_\n\nUserRecord\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x37\n\x11recordPermissions\x18\x02 \x03(\x0b\x32\x1c.Enterprise.RecordPermission\"[\n\tAuditTeam\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x10\n\x08teamName\x18\x02 \x01(\t\x12\x14\n\x0crestrictEdit\x18\x03 \x01(\x08\x12\x15\n\rrestrictShare\x18\x04 \x01(\x08\";\n\rAuditTeamUser\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x19\n\x11\x65nterpriseUserIds\x18\x02 \x03(\x03\"\x9f\x01\n\x12SharedFolderRecord\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x37\n\x11recordPermissions\x18\x02 \x03(\x0b\x32\x1c.Enterprise.RecordPermission\x12\x37\n\x11shareAdminRecords\x18\x03 \x03(\x0b\x32\x1c.Enterprise.ShareAdminRecord\"M\n\x10ShareAdminRecord\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x1f\n\x17recordPermissionIndexes\x18\x02 \x03(\x05\"F\n\x10SharedFolderUser\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x19\n\x11\x65nterpriseUserIds\x18\x02 \x03(\x03\"=\n\x10SharedFolderTeam\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x10\n\x08teamUids\x18\x02 \x03(\x0c\"/\n\x1aGetComplianceReportRequest\x12\x11\n\treportUid\x18\x01 \x01(\x0c\"2\n\x1bGetComplianceReportResponse\x12\x13\n\x0b\x64ownloadUrl\x18\x01 \x01(\t\"6\n\x1f\x43omplianceReportCriteriaRequest\x12\x13\n\x0b\x63riteriaUid\x18\x01 \x01(\x0c\";\n$SaveComplianceReportCriteriaResponse\x12\x13\n\x0b\x63riteriaUid\x18\x01 \x01(\x0c\"4\n\x0cLinkedRecord\x12\x10\n\x08ownerUid\x18\x01 \x01(\x0c\x12\x12\n\nrecordUids\x18\x02 \x03(\x0c\"W\n\x17GetSharingAdminsRequest\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x10\n\x08username\x18\x03 \x01(\t\"\xe0\x01\n\x0eUserProfileExt\x12\r\n\x05\x65mail\x18\x01 \x01(\t\x12\x10\n\x08\x66ullName\x18\x02 \x01(\t\x12\x10\n\x08jobTitle\x18\x03 \x01(\t\x12\x14\n\x0cisMSPMCAdmin\x18\x04 \x01(\x08\x12\x18\n\x10isInSharedFolder\x18\x05 \x01(\x08\x12&\n\x1eisShareAdminForRequestedObject\x18\x06 \x01(\x08\x12(\n isShareAdminForSharedFolderOwner\x18\x07 \x01(\x08\x12\x19\n\x11hasAccessToObject\x18\x08 \x01(\x08\"O\n\x18GetSharingAdminsResponse\x12\x33\n\x0fuserProfileExts\x18\x01 \x03(\x0b\x32\x1a.Enterprise.UserProfileExt\"_\n\x1eTeamsEnterpriseUsersAddRequest\x12=\n\x05teams\x18\x01 \x03(\x0b\x32..Enterprise.TeamsEnterpriseUsersAddTeamRequest\"t\n\"TeamsEnterpriseUsersAddTeamRequest\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12=\n\x05users\x18\x02 \x03(\x0b\x32..Enterprise.TeamsEnterpriseUsersAddUserRequest\"\xab\x01\n\"TeamsEnterpriseUsersAddUserRequest\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12*\n\x08userType\x18\x02 \x01(\x0e\x32\x18.Enterprise.TeamUserType\x12\x13\n\x07teamKey\x18\x03 \x01(\tB\x02\x18\x01\x12*\n\x0ctypedTeamKey\x18\x04 \x01(\x0b\x32\x14.Enterprise.TypedKey\"F\n\x08TypedKey\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12-\n\x07keyType\x18\x02 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\"s\n\x1fTeamsEnterpriseUsersAddResponse\x12>\n\x05teams\x18\x01 \x03(\x0b\x32/.Enterprise.TeamsEnterpriseUsersAddTeamResponse\x12\x10\n\x08revision\x18\x02 \x01(\x03\"\xc4\x01\n#TeamsEnterpriseUsersAddTeamResponse\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12>\n\x05users\x18\x02 \x03(\x0b\x32/.Enterprise.TeamsEnterpriseUsersAddUserResponse\x12\x0f\n\x07success\x18\x03 \x01(\x08\x12\x0f\n\x07message\x18\x04 \x01(\t\x12\x12\n\nresultCode\x18\x05 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x06 \x01(\t\"\x9f\x01\n#TeamsEnterpriseUsersAddUserResponse\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x10\n\x08revision\x18\x02 \x01(\x03\x12\x0f\n\x07success\x18\x03 \x01(\x08\x12\x0f\n\x07message\x18\x04 \x01(\t\x12\x12\n\nresultCode\x18\x05 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x06 \x01(\t\"E\n\x18TeamEnterpriseUserRemove\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x18\n\x10\x65nterpriseUserId\x18\x02 \x01(\x03\"j\n TeamEnterpriseUserRemovesRequest\x12\x46\n\x18teamEnterpriseUserRemove\x18\x01 \x03(\x0b\x32$.Enterprise.TeamEnterpriseUserRemove\"{\n!TeamEnterpriseUserRemovesResponse\x12V\n teamEnterpriseUserRemoveResponse\x18\x01 \x03(\x0b\x32,.Enterprise.TeamEnterpriseUserRemoveResponse\"\xb8\x01\n TeamEnterpriseUserRemoveResponse\x12\x46\n\x18teamEnterpriseUserRemove\x18\x01 \x01(\x0b\x32$.Enterprise.TeamEnterpriseUserRemove\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\nresultCode\x18\x03 \x01(\t\x12\x0f\n\x07message\x18\x04 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x05 \x01(\t\"M\n\x0b\x44omainAlias\x12\x0e\n\x06\x64omain\x18\x01 \x01(\t\x12\r\n\x05\x61lias\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\x05\x12\x0f\n\x07message\x18\x04 \x01(\t\"B\n\x12\x44omainAliasRequest\x12,\n\x0b\x64omainAlias\x18\x01 \x03(\x0b\x32\x17.Enterprise.DomainAlias\"C\n\x13\x44omainAliasResponse\x12,\n\x0b\x64omainAlias\x18\x01 \x03(\x0b\x32\x17.Enterprise.DomainAlias\"m\n\x1f\x45nterpriseUsersProvisionRequest\x12\x33\n\x05users\x18\x01 \x03(\x0b\x32$.Enterprise.EnterpriseUsersProvision\x12\x15\n\rclientVersion\x18\x02 \x01(\t\"\xb6\x03\n\x18\x45nterpriseUsersProvision\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x0e\n\x06nodeId\x18\x03 \x01(\x03\x12\x15\n\rencryptedData\x18\x04 \x01(\t\x12-\n\x07keyType\x18\x05 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\x12\x10\n\x08\x66ullName\x18\x06 \x01(\t\x12\x10\n\x08jobTitle\x18\x07 \x01(\t\x12\x1e\n\x16\x65nterpriseUsersDataKey\x18\x08 \x01(\x0c\x12\x14\n\x0c\x61uthVerifier\x18\t \x01(\x0c\x12\x18\n\x10\x65ncryptionParams\x18\n \x01(\x0c\x12\x14\n\x0crsaPublicKey\x18\x0b \x01(\x0c\x12\x1e\n\x16rsaEncryptedPrivateKey\x18\x0c \x01(\x0c\x12\x14\n\x0c\x65\x63\x63PublicKey\x18\r \x01(\x0c\x12\x1e\n\x16\x65\x63\x63\x45ncryptedPrivateKey\x18\x0e \x01(\x0c\x12\x1c\n\x14\x65ncryptedDeviceToken\x18\x0f \x01(\x0c\x12\x1a\n\x12\x65ncryptedClientKey\x18\x10 \x01(\x0c\"_\n EnterpriseUsersProvisionResponse\x12;\n\x07results\x18\x01 \x03(\x0b\x32*.Enterprise.EnterpriseUsersProvisionResult\"q\n\x1e\x45nterpriseUsersProvisionResult\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0c\n\x04\x63ode\x18\x02 \x01(\t\x12\x0f\n\x07message\x18\x03 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x04 \x01(\t\"a\n\x19\x45nterpriseUsersAddRequest\x12-\n\x05users\x18\x01 \x03(\x0b\x32\x1e.Enterprise.EnterpriseUsersAdd\x12\x15\n\rclientVersion\x18\x02 \x01(\t\"\x8c\x02\n\x12\x45nterpriseUsersAdd\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x0e\n\x06nodeId\x18\x03 \x01(\x03\x12\x15\n\rencryptedData\x18\x04 \x01(\t\x12-\n\x07keyType\x18\x05 \x01(\x0e\x32\x1c.Enterprise.EncryptedKeyType\x12\x10\n\x08\x66ullName\x18\x06 \x01(\t\x12\x10\n\x08jobTitle\x18\x07 \x01(\t\x12\x1b\n\x13suppressEmailInvite\x18\x08 \x01(\x08\x12\x15\n\rinviteeLocale\x18\t \x01(\t\x12\x0c\n\x04move\x18\n \x01(\x08\x12\x0e\n\x06roleId\x18\x0b \x01(\x03\"\x9b\x01\n\x1a\x45nterpriseUsersAddResponse\x12\x35\n\x07results\x18\x01 \x03(\x0b\x32$.Enterprise.EnterpriseUsersAddResult\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x0c\n\x04\x63ode\x18\x03 \x01(\t\x12\x0f\n\x07message\x18\x04 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x05 \x01(\t\"\x96\x01\n\x18\x45nterpriseUsersAddResult\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x18\n\x10verificationCode\x18\x03 \x01(\t\x12\x0c\n\x04\x63ode\x18\x04 \x01(\t\x12\x0f\n\x07message\x18\x05 \x01(\t\x12\x16\n\x0e\x61\x64\x64itionalInfo\x18\x06 \x01(\t\"\xb9\x01\n\x17UpdateMSPPermitsRequest\x12\x17\n\x0fmspEnterpriseId\x18\x01 \x01(\x05\x12\x1a\n\x12maxAllowedLicenses\x18\x02 \x01(\x05\x12\x19\n\x11\x61llowedMcProducts\x18\x03 \x03(\t\x12\x15\n\rallowedAddOns\x18\x04 \x03(\t\x12\x17\n\x0fmaxFilePlanType\x18\x05 \x01(\t\x12\x1e\n\x16\x61llowUnlimitedLicenses\x18\x06 \x01(\x08\"9\n\x1c\x44\x65leteEnterpriseUsersRequest\x12\x19\n\x11\x65nterpriseUserIds\x18\x01 \x03(\x03\"o\n\x1a\x44\x65leteEnterpriseUserStatus\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12\x37\n\x06status\x18\x02 \x01(\x0e\x32\'.Enterprise.DeleteEnterpriseUsersResult\"]\n\x1d\x44\x65leteEnterpriseUsersResponse\x12<\n\x0c\x64\x65leteStatus\x18\x01 \x03(\x0b\x32&.Enterprise.DeleteEnterpriseUserStatus\"w\n\x18\x43learSecurityDataRequest\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x03(\x03\x12\x10\n\x08\x61llUsers\x18\x02 \x01(\x08\x12/\n\x04type\x18\x03 \x01(\x0e\x32!.Enterprise.ClearSecurityDataType\"%\n\x13ListDomainsResponse\x12\x0e\n\x06\x64omain\x18\x01 \x03(\t\"d\n\x14ReserveDomainRequest\x12<\n\x13reserveDomainAction\x18\x01 \x01(\x0e\x32\x1f.Enterprise.ReserveDomainAction\x12\x0e\n\x06\x64omain\x18\x02 \x01(\t\"&\n\x15ReserveDomainResponse\x12\r\n\x05token\x18\x01 \x01(\t\".\n\x0bRolesByTeam\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x0e\n\x06roleId\x18\x02 \x03(\x03\"\x8d\x01\n\x10LockUsersRequest\x12\x1d\n\x15lockEnterpriseUserIds\x18\x01 \x03(\x03\x12 \n\x18\x64isableEnterpriseUserIds\x18\x02 \x03(\x03\x12\x1f\n\x17unlockEnterpriseUserIds\x18\x03 \x03(\x03\x12\x17\n\x0f\x64\x65leteIfPending\x18\x04 \x01(\x08\"C\n\x11LockUsersResponse\x12.\n\x08response\x18\x01 \x03(\x0b\x32\x1c.Enterprise.LockUserResponse\"n\n\x10LockUserResponse\x12\x18\n\x10\x65nterpriseUserId\x18\x01 \x01(\x03\x12*\n\x06status\x18\x02 \x01(\x0e\x32\x1a.Enterprise.UserLockStatus\x12\x14\n\x0c\x65rrorMessage\x18\x03 \x01(\t*\x1b\n\x07KeyType\x12\x07\n\x03RSA\x10\x00\x12\x07\n\x03\x45\x43\x43\x10\x01*\xaf\x02\n\x14RoleUserModifyStatus\x12\x0f\n\x0bROLE_EXISTS\x10\x00\x12\x14\n\x10MISSING_TREE_KEY\x10\x01\x12\x14\n\x10MISSING_ROLE_KEY\x10\x02\x12\x1e\n\x1aINVALID_ENTERPRISE_USER_ID\x10\x03\x12\x1b\n\x17PENDING_ENTERPRISE_USER\x10\x04\x12\x13\n\x0fINVALID_NODE_ID\x10\x05\x12!\n\x1dMAY_NOT_REMOVE_SELF_FROM_ROLE\x10\x06\x12\x1c\n\x18MUST_HAVE_ONE_USER_ADMIN\x10\x07\x12\x13\n\x0fINVALID_ROLE_ID\x10\x08\x12\x1d\n\x19PAM_LICENSE_SEAT_EXCEEDED\x10\t\x12\x13\n\x0fWOULD_LOCK_SELF\x10\n*=\n\x0e\x45nterpriseType\x12\x17\n\x13\x45NTERPRISE_STANDARD\x10\x00\x12\x12\n\x0e\x45NTERPRISE_MSP\x10\x01*s\n\x18TransferAcceptanceStatus\x12\r\n\tUNDEFINED\x10\x00\x12\x10\n\x0cNOT_REQUIRED\x10\x01\x12\x10\n\x0cNOT_ACCEPTED\x10\x02\x12\x16\n\x12PARTIALLY_ACCEPTED\x10\x03\x12\x0c\n\x08\x41\x43\x43\x45PTED\x10\x04*\xe1\x03\n\x14\x45nterpriseDataEntity\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05NODES\x10\x01\x12\t\n\x05ROLES\x10\x02\x12\t\n\x05USERS\x10\x03\x12\t\n\x05TEAMS\x10\x04\x12\x0e\n\nTEAM_USERS\x10\x05\x12\x0e\n\nROLE_USERS\x10\x06\x12\x13\n\x0fROLE_PRIVILEGES\x10\x07\x12\x15\n\x11ROLE_ENFORCEMENTS\x10\x08\x12\x0e\n\nROLE_TEAMS\x10\t\x12\x0c\n\x08LICENSES\x10\n\x12\x11\n\rMANAGED_NODES\x10\x0b\x12\x15\n\x11MANAGED_COMPANIES\x10\x0c\x12\x0b\n\x07\x42RIDGES\x10\r\x12\t\n\x05SCIMS\x10\x0e\x12\x13\n\x0f\x45MAIL_PROVISION\x10\x0f\x12\x10\n\x0cQUEUED_TEAMS\x10\x10\x12\x15\n\x11QUEUED_TEAM_USERS\x10\x11\x12\x10\n\x0cSSO_SERVICES\x10\x12\x12\x17\n\x13REPORT_FILTER_USERS\x10\x13\x12&\n\"DEVICES_REQUEST_FOR_ADMIN_APPROVAL\x10\x14\x12\x10\n\x0cUSER_ALIASES\x10\x15\x12)\n%COMPLIANCE_REPORT_CRITERIA_AND_FILTER\x10\x16\x12\x16\n\x12\x43OMPLIANCE_REPORTS\x10\x17*\"\n\x0b\x43\x61\x63heStatus\x12\x08\n\x04KEEP\x10\x00\x12\t\n\x05\x43LEAR\x10\x01*\x93\x01\n\rBackupKeyType\x12\n\n\x06NO_KEY\x10\x00\x12\x19\n\x15\x45NCRYPTED_BY_DATA_KEY\x10\x01\x12\x1b\n\x17\x45NCRYPTED_BY_PUBLIC_KEY\x10\x02\x12\x1d\n\x19\x45NCRYPTED_BY_DATA_KEY_GCM\x10\x03\x12\x1f\n\x1b\x45NCRYPTED_BY_PUBLIC_KEY_ECC\x10\x04*:\n\x15\x42\x61\x63kupUserDataKeyType\x12\x07\n\x03OWN\x10\x00\x12\x18\n\x14SHARED_TO_ENTERPRISE\x10\x01*\xa5\x01\n\x10\x45ncryptedKeyType\x12\r\n\tKT_NO_KEY\x10\x00\x12\x1c\n\x18KT_ENCRYPTED_BY_DATA_KEY\x10\x01\x12\x1e\n\x1aKT_ENCRYPTED_BY_PUBLIC_KEY\x10\x02\x12 \n\x1cKT_ENCRYPTED_BY_DATA_KEY_GCM\x10\x03\x12\"\n\x1eKT_ENCRYPTED_BY_PUBLIC_KEY_ECC\x10\x04*\xb7\x02\n\x12\x45nterpriseFlagType\x12\x0b\n\x07INVALID\x10\x00\x12\x1a\n\x16\x41LLOW_PERSONAL_LICENSE\x10\x01\x12\x18\n\x14SPECIAL_PROVISIONING\x10\x02\x12\x10\n\x0cRECORD_TYPES\x10\x03\x12\x13\n\x0fSECRETS_MANAGER\x10\x04\x12\x15\n\x11\x45NTERPRISE_LOCKED\x10\x05\x12\x15\n\x11\x46ORBID_KEY_TYPE_2\x10\x06\x12\x15\n\x11\x43ONSOLE_ONBOARDED\x10\x07\x12\x1b\n\x17\x46ORBID_ACCOUNT_TRANSFER\x10\x08\x12\x15\n\x11NPS_POPUP_OPT_OUT\x10\t\x12\x15\n\x11SHOW_USER_ONBOARD\x10\n\x12\x15\n\x11\x46ORBID_KEY_TYPE_1\x10\x0b\x12\x10\n\x0cKEEPER_DRIVE\x10\x0c*\xf3\x01\n\x10UserUpdateStatus\x12\x12\n\x0eUSER_UPDATE_OK\x10\x00\x12\x1d\n\x19USER_UPDATE_ACCESS_DENIED\x10\x01\x12&\n\"USER_UPDATE_EXCEEDED_LICENSE_SEATS\x10\x02\x12\x1b\n\x17USER_UPDATE_BAD_REQUEST\x10\x03\x12\x19\n\x15USER_UPDATE_DUPLICATE\x10\x04\x12\x1d\n\x19USER_UPDATE_INVALID_STATE\x10\x05\x12\x16\n\x12USER_UPDATE_FAILED\x10\x06\x12\x15\n\x11USER_UPDATE_ERROR\x10\x07*I\n\x0f\x41uditUserStatus\x12\x06\n\x02OK\x10\x00\x12\x11\n\rACCESS_DENIED\x10\x01\x12\x1b\n\x17NO_LONGER_IN_ENTERPRISE\x10\x02*3\n\x0cTeamUserType\x12\x08\n\x04USER\x10\x00\x12\t\n\x05\x41\x44MIN\x10\x01\x12\x0e\n\nADMIN_ONLY\x10\x02*x\n\rAppClientType\x12\x0c\n\x08NOT_USED\x10\x00\x12\x0b\n\x07GENERAL\x10\x01\x12%\n!DISCOVERY_AND_ROTATION_CONTROLLER\x10\x02\x12\x12\n\x0eKCM_CONTROLLER\x10\x03\x12\x11\n\rSELF_DESTRUCT\x10\x04*\x8f\x01\n\x1b\x44\x65leteEnterpriseUsersResult\x12\x0b\n\x07SUCCESS\x10\x00\x12\x1a\n\x16NOT_AN_ENTERPRISE_USER\x10\x01\x12\x16\n\x12\x43\x41NNOT_DELETE_SELF\x10\x02\x12$\n BRIDGE_CANNOT_DELETE_ACTIVE_USER\x10\x03\x12\t\n\x05\x45RROR\x10\x04*\x87\x01\n\x15\x43learSecurityDataType\x12\x1e\n\x1aRECALCULATE_SUMMARY_REPORT\x10\x00\x12\'\n#FORCE_CLIENT_CHECK_FOR_MISSING_DATA\x10\x01\x12%\n!FORCE_CLIENT_RESEND_SECURITY_DATA\x10\x02*J\n\x13ReserveDomainAction\x12\x10\n\x0c\x44OMAIN_TOKEN\x10\x00\x12\x0e\n\nDOMAIN_ADD\x10\x01\x12\x11\n\rDOMAIN_DELETE\x10\x02*s\n\x0eUserLockStatus\x12\x17\n\x13UNKNOWN_LOCK_STATUS\x10\x00\x12\n\n\x06LOCKED\x10\x01\x12\x0c\n\x08\x44ISABLED\x10\x02\x12\x0c\n\x08UNLOCKED\x10\x03\x12\x0b\n\x07\x44\x45LETED\x10\x04\x12\x13\n\x0f\x43\x41NT_BE_PENDING\x10\x05*\x80\x01\n\x1d\x45xternalCloudSecretsStoreType\x12\x16\n\x12UNKNOWN_STORE_TYPE\x10\x00\x12\x17\n\x13\x41WS_SECRETS_MANAGER\x10\x01\x12\x13\n\x0f\x41ZURE_KEY_VAULT\x10\x02\x12\x19\n\x15GOOGLE_SECRET_MANAGER\x10\x03\x42&\n\x18\x63om.keepersecurity.protoB\nEnterpriseb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -32,382 +33,388 @@ if not _descriptor._USE_C_DESCRIPTORS: _globals['DESCRIPTOR']._loaded_options = None _globals['DESCRIPTOR']._serialized_options = b'\n\030com.keepersecurity.protoB\nEnterprise' + _globals['_ROLEUSERADDKEYS'].fields_by_name['treeKey']._loaded_options = None + _globals['_ROLEUSERADDKEYS'].fields_by_name['treeKey']._serialized_options = b'\030\001' _globals['_NODE'].fields_by_name['ssoServiceProviderId']._loaded_options = None _globals['_NODE'].fields_by_name['ssoServiceProviderId']._serialized_options = b'\030\001' _globals['_NODE'].fields_by_name['ssoServiceProviderIds']._loaded_options = None _globals['_NODE'].fields_by_name['ssoServiceProviderIds']._serialized_options = b'\020\001' + _globals['_USERUPDATE'].fields_by_name['encryptedData']._loaded_options = None + _globals['_USERUPDATE'].fields_by_name['encryptedData']._serialized_options = b'\030\001' _globals['_TEAMSENTERPRISEUSERSADDUSERREQUEST'].fields_by_name['teamKey']._loaded_options = None _globals['_TEAMSENTERPRISEUSERSADDUSERREQUEST'].fields_by_name['teamKey']._serialized_options = b'\030\001' - _globals['_KEYTYPE']._serialized_start=20649 - _globals['_KEYTYPE']._serialized_end=20676 - _globals['_ROLEUSERMODIFYSTATUS']._serialized_start=20679 - _globals['_ROLEUSERMODIFYSTATUS']._serialized_end=20961 - _globals['_ENTERPRISETYPE']._serialized_start=20963 - _globals['_ENTERPRISETYPE']._serialized_end=21024 - _globals['_TRANSFERACCEPTANCESTATUS']._serialized_start=21026 - _globals['_TRANSFERACCEPTANCESTATUS']._serialized_end=21141 - _globals['_ENTERPRISEDATAENTITY']._serialized_start=21144 - _globals['_ENTERPRISEDATAENTITY']._serialized_end=21625 - _globals['_CACHESTATUS']._serialized_start=21627 - _globals['_CACHESTATUS']._serialized_end=21661 - _globals['_BACKUPKEYTYPE']._serialized_start=21664 - _globals['_BACKUPKEYTYPE']._serialized_end=21811 - _globals['_BACKUPUSERDATAKEYTYPE']._serialized_start=21813 - _globals['_BACKUPUSERDATAKEYTYPE']._serialized_end=21871 - _globals['_ENCRYPTEDKEYTYPE']._serialized_start=21874 - _globals['_ENCRYPTEDKEYTYPE']._serialized_end=22039 - _globals['_ENTERPRISEFLAGTYPE']._serialized_start=22042 - _globals['_ENTERPRISEFLAGTYPE']._serialized_end=22353 - _globals['_USERUPDATESTATUS']._serialized_start=22355 - _globals['_USERUPDATESTATUS']._serialized_end=22424 - _globals['_AUDITUSERSTATUS']._serialized_start=22426 - _globals['_AUDITUSERSTATUS']._serialized_end=22499 - _globals['_TEAMUSERTYPE']._serialized_start=22501 - _globals['_TEAMUSERTYPE']._serialized_end=22552 - _globals['_APPCLIENTTYPE']._serialized_start=22554 - _globals['_APPCLIENTTYPE']._serialized_end=22674 - _globals['_DELETEENTERPRISEUSERSRESULT']._serialized_start=22677 - _globals['_DELETEENTERPRISEUSERSRESULT']._serialized_end=22820 - _globals['_CLEARSECURITYDATATYPE']._serialized_start=22823 - _globals['_CLEARSECURITYDATATYPE']._serialized_end=22958 - _globals['_RESERVEDOMAINACTION']._serialized_start=22960 - _globals['_RESERVEDOMAINACTION']._serialized_end=23034 - _globals['_USERLOCKSTATUS']._serialized_start=23036 - _globals['_USERLOCKSTATUS']._serialized_end=23151 - _globals['_EXTERNALCLOUDSECRETSSTORETYPE']._serialized_start=23154 - _globals['_EXTERNALCLOUDSECRETSSTORETYPE']._serialized_end=23282 - _globals['_ENTERPRISEKEYPAIRREQUEST']._serialized_start=33 - _globals['_ENTERPRISEKEYPAIRREQUEST']._serialized_end=165 - _globals['_GETTEAMMEMBERREQUEST']._serialized_start=167 - _globals['_GETTEAMMEMBERREQUEST']._serialized_end=206 - _globals['_ENTERPRISEUSER']._serialized_start=208 - _globals['_ENTERPRISEUSER']._serialized_end=333 - _globals['_GETTEAMMEMBERRESPONSE']._serialized_start=335 - _globals['_GETTEAMMEMBERRESPONSE']._serialized_end=410 - _globals['_ENTERPRISEUSERIDS']._serialized_start=412 - _globals['_ENTERPRISEUSERIDS']._serialized_end=457 - _globals['_ENTERPRISEPERSONALACCOUNT']._serialized_start=459 - _globals['_ENTERPRISEPERSONALACCOUNT']._serialized_end=525 - _globals['_ENCRYPTEDTEAMKEYREQUEST']._serialized_start=527 - _globals['_ENCRYPTEDTEAMKEYREQUEST']._serialized_end=610 - _globals['_REENCRYPTEDDATA']._serialized_start=612 - _globals['_REENCRYPTEDDATA']._serialized_end=655 - _globals['_REENCRYPTEDROLEKEY']._serialized_start=657 - _globals['_REENCRYPTEDROLEKEY']._serialized_end=720 - _globals['_REENCRYPTEDUSERDATAKEY']._serialized_start=722 - _globals['_REENCRYPTEDUSERDATAKEY']._serialized_end=802 - _globals['_NODETOMANAGEDCOMPANYREQUEST']._serialized_start=805 - _globals['_NODETOMANAGEDCOMPANYREQUEST']._serialized_end=1149 - _globals['_ROLETEAM']._serialized_start=1151 - _globals['_ROLETEAM']._serialized_end=1195 - _globals['_ROLETEAMS']._serialized_start=1197 - _globals['_ROLETEAMS']._serialized_end=1249 - _globals['_TEAMSBYROLE']._serialized_start=1251 - _globals['_TEAMSBYROLE']._serialized_end=1298 - _globals['_MANAGEDNODESBYROLE']._serialized_start=1300 - _globals['_MANAGEDNODESBYROLE']._serialized_end=1360 - _globals['_ROLEUSERADDKEYS']._serialized_start=1362 - _globals['_ROLEUSERADDKEYS']._serialized_end=1444 - _globals['_ROLEUSERADD']._serialized_start=1446 - _globals['_ROLEUSERADD']._serialized_end=1530 - _globals['_ROLEUSERSADDREQUEST']._serialized_start=1532 - _globals['_ROLEUSERSADDREQUEST']._serialized_end=1600 - _globals['_ROLEUSERADDRESULT']._serialized_start=1603 - _globals['_ROLEUSERADDRESULT']._serialized_end=1731 - _globals['_ROLEUSERSADDRESPONSE']._serialized_start=1733 - _globals['_ROLEUSERSADDRESPONSE']._serialized_end=1803 - _globals['_ROLEUSERREMOVE']._serialized_start=1805 - _globals['_ROLEUSERREMOVE']._serialized_end=1865 - _globals['_ROLEUSERSREMOVEREQUEST']._serialized_start=1867 - _globals['_ROLEUSERSREMOVEREQUEST']._serialized_end=1944 - _globals['_ROLEUSERREMOVERESULT']._serialized_start=1947 - _globals['_ROLEUSERREMOVERESULT']._serialized_end=2078 - _globals['_ROLEUSERSREMOVERESPONSE']._serialized_start=2080 - _globals['_ROLEUSERSREMOVERESPONSE']._serialized_end=2156 - _globals['_ENTERPRISEREGISTRATION']._serialized_start=2159 - _globals['_ENTERPRISEREGISTRATION']._serialized_end=2703 - _globals['_DOMAINPASSWORDRULESREQUEST']._serialized_start=2705 - _globals['_DOMAINPASSWORDRULESREQUEST']._serialized_end=2777 - _globals['_DOMAINPASSWORDRULESFIELDS']._serialized_start=2779 - _globals['_DOMAINPASSWORDRULESFIELDS']._serialized_end=2871 - _globals['_LOGINTOMCREQUEST']._serialized_start=2873 - _globals['_LOGINTOMCREQUEST']._serialized_end=2942 - _globals['_LOGINTOMCRESPONSE']._serialized_start=2944 - _globals['_LOGINTOMCRESPONSE']._serialized_end=3063 - _globals['_DOMAINPASSWORDRULESRESPONSE']._serialized_start=3065 - _globals['_DOMAINPASSWORDRULESRESPONSE']._serialized_end=3168 - _globals['_APPROVEUSERDEVICEREQUEST']._serialized_start=3171 - _globals['_APPROVEUSERDEVICEREQUEST']._serialized_end=3307 - _globals['_APPROVEUSERDEVICERESPONSE']._serialized_start=3309 - _globals['_APPROVEUSERDEVICERESPONSE']._serialized_end=3425 - _globals['_APPROVEUSERDEVICESREQUEST']._serialized_start=3427 - _globals['_APPROVEUSERDEVICESREQUEST']._serialized_end=3516 - _globals['_APPROVEUSERDEVICESRESPONSE']._serialized_start=3518 - _globals['_APPROVEUSERDEVICESRESPONSE']._serialized_end=3610 - _globals['_ENTERPRISEUSERDATAKEY']._serialized_start=3613 - _globals['_ENTERPRISEUSERDATAKEY']._serialized_end=3748 - _globals['_ENTERPRISEUSERDATAKEYS']._serialized_start=3750 - _globals['_ENTERPRISEUSERDATAKEYS']._serialized_end=3823 - _globals['_ENTERPRISEUSERDATAKEYLIGHT']._serialized_start=3825 - _globals['_ENTERPRISEUSERDATAKEYLIGHT']._serialized_end=3928 - _globals['_ENTERPRISEUSERDATAKEYSBYNODE']._serialized_start=3930 - _globals['_ENTERPRISEUSERDATAKEYSBYNODE']._serialized_end=4030 - _globals['_ENTERPRISEUSERDATAKEYSBYNODERESPONSE']._serialized_start=4032 - _globals['_ENTERPRISEUSERDATAKEYSBYNODERESPONSE']._serialized_end=4126 - _globals['_ENTERPRISEDATAREQUEST']._serialized_start=4128 - _globals['_ENTERPRISEDATAREQUEST']._serialized_end=4178 - _globals['_SPECIALPROVISIONING']._serialized_start=4180 - _globals['_SPECIALPROVISIONING']._serialized_end=4228 - _globals['_GENERALDATAENTITY']._serialized_start=4231 - _globals['_GENERALDATAENTITY']._serialized_end=4491 - _globals['_NODE']._serialized_start=4494 - _globals['_NODE']._serialized_end=4747 - _globals['_ROLE']._serialized_start=4750 - _globals['_ROLE']._serialized_end=4892 - _globals['_USER']._serialized_start=4895 - _globals['_USER']._serialized_end=5207 - _globals['_USERALIAS']._serialized_start=5209 - _globals['_USERALIAS']._serialized_end=5264 - _globals['_COMPLIANCEREPORTMETADATA']._serialized_start=5267 - _globals['_COMPLIANCEREPORTMETADATA']._serialized_end=5439 - _globals['_MANAGEDNODE']._serialized_start=5441 - _globals['_MANAGEDNODE']._serialized_end=5524 - _globals['_USERMANAGEDNODE']._serialized_start=5526 - _globals['_USERMANAGEDNODE']._serialized_end=5610 - _globals['_USERPRIVILEGE']._serialized_start=5612 - _globals['_USERPRIVILEGE']._serialized_end=5731 - _globals['_ROLEUSER']._serialized_start=5733 - _globals['_ROLEUSER']._serialized_end=5785 - _globals['_ROLEPRIVILEGE']._serialized_start=5787 - _globals['_ROLEPRIVILEGE']._serialized_end=5864 - _globals['_PRIVILEGESBYMANAGEDNODE']._serialized_start=5866 - _globals['_PRIVILEGESBYMANAGEDNODE']._serialized_end=5950 - _globals['_ROLEENFORCEMENT']._serialized_start=5952 - _globals['_ROLEENFORCEMENT']._serialized_end=6025 - _globals['_TEAM']._serialized_start=6028 - _globals['_TEAM']._serialized_end=6197 - _globals['_TEAMUSER']._serialized_start=6199 - _globals['_TEAMUSER']._serialized_end=6270 - _globals['_GETDISTRIBUTORINFORESPONSE']._serialized_start=6272 - _globals['_GETDISTRIBUTORINFORESPONSE']._serialized_end=6347 - _globals['_DISTRIBUTOR']._serialized_start=6349 - _globals['_DISTRIBUTOR']._serialized_end=6415 - _globals['_MSPINFO']._serialized_start=6418 - _globals['_MSPINFO']._serialized_end=6703 - _globals['_MANAGEDCOMPANY']._serialized_start=6706 - _globals['_MANAGEDCOMPANY']._serialized_end=7002 - _globals['_MSPPOOL']._serialized_start=7004 - _globals['_MSPPOOL']._serialized_end=7086 - _globals['_MSPCONTACT']._serialized_start=7088 - _globals['_MSPCONTACT']._serialized_end=7146 - _globals['_LICENSEADDON']._serialized_start=7149 - _globals['_LICENSEADDON']._serialized_end=7409 - _globals['_MCDEFAULT']._serialized_start=7411 - _globals['_MCDEFAULT']._serialized_end=7526 - _globals['_MSPPERMITS']._serialized_start=7529 - _globals['_MSPPERMITS']._serialized_end=7739 - _globals['_LICENSE']._serialized_start=7742 - _globals['_LICENSE']._serialized_end=8286 - _globals['_BRIDGE']._serialized_start=8288 - _globals['_BRIDGE']._serialized_end=8398 - _globals['_SCIM']._serialized_start=8400 - _globals['_SCIM']._serialized_end=8516 - _globals['_EMAILPROVISION']._serialized_start=8518 - _globals['_EMAILPROVISION']._serialized_end=8594 - _globals['_QUEUEDTEAM']._serialized_start=8596 - _globals['_QUEUEDTEAM']._serialized_end=8678 - _globals['_QUEUEDTEAMUSER']._serialized_start=8680 - _globals['_QUEUEDTEAMUSER']._serialized_end=8728 - _globals['_TEAMSADDRESULT']._serialized_start=8731 - _globals['_TEAMSADDRESULT']._serialized_end=8895 - _globals['_TEAMADDRESULT']._serialized_start=8897 - _globals['_TEAMADDRESULT']._serialized_end=8982 - _globals['_SSOSERVICE']._serialized_start=8985 - _globals['_SSOSERVICE']._serialized_end=9130 - _globals['_REPORTFILTERUSER']._serialized_start=9132 - _globals['_REPORTFILTERUSER']._serialized_end=9181 - _globals['_DEVICEREQUESTFORADMINAPPROVAL']._serialized_start=9184 - _globals['_DEVICEREQUESTFORADMINAPPROVAL']._serialized_end=9463 - _globals['_ENTERPRISEDATA']._serialized_start=9465 - _globals['_ENTERPRISEDATA']._serialized_end=9561 - _globals['_ENTERPRISEDATARESPONSE']._serialized_start=9564 - _globals['_ENTERPRISEDATARESPONSE']._serialized_end=9772 - _globals['_BACKUPREQUEST']._serialized_start=9774 - _globals['_BACKUPREQUEST']._serialized_end=9816 - _globals['_BACKUPRECORD']._serialized_start=9819 - _globals['_BACKUPRECORD']._serialized_end=9971 - _globals['_BACKUPKEY']._serialized_start=9973 - _globals['_BACKUPKEY']._serialized_end=10019 - _globals['_BACKUPUSER']._serialized_start=10022 - _globals['_BACKUPUSER']._serialized_end=10291 - _globals['_BACKUPRESPONSE']._serialized_start=10294 - _globals['_BACKUPRESPONSE']._serialized_end=10452 - _globals['_BACKUPFILE']._serialized_start=10454 - _globals['_BACKUPFILE']._serialized_end=10555 - _globals['_BACKUPSRESPONSE']._serialized_start=10557 - _globals['_BACKUPSRESPONSE']._serialized_end=10613 - _globals['_GETENTERPRISEDATAKEYSREQUEST']._serialized_start=10615 - _globals['_GETENTERPRISEDATAKEYSREQUEST']._serialized_end=10661 - _globals['_GETENTERPRISEDATAKEYSRESPONSE']._serialized_start=10664 - _globals['_GETENTERPRISEDATAKEYSRESPONSE']._serialized_end=10919 - _globals['_ROLEKEY']._serialized_start=10921 - _globals['_ROLEKEY']._serialized_end=11015 - _globals['_MSPKEY']._serialized_start=11017 - _globals['_MSPKEY']._serialized_end=11117 - _globals['_ENTERPRISEKEYS']._serialized_start=11119 - _globals['_ENTERPRISEKEYS']._serialized_end=11243 - _globals['_TREEKEY']._serialized_start=11245 - _globals['_TREEKEY']._serialized_end=11317 - _globals['_SHAREDRECORDRESPONSE']._serialized_start=11319 - _globals['_SHAREDRECORDRESPONSE']._serialized_end=11388 - _globals['_SHAREDRECORDEVENT']._serialized_start=11390 - _globals['_SHAREDRECORDEVENT']._serialized_end=11502 - _globals['_SETRESTRICTVISIBILITYREQUEST']._serialized_start=11504 - _globals['_SETRESTRICTVISIBILITYREQUEST']._serialized_end=11550 - _globals['_USERADDREQUEST']._serialized_start=11553 - _globals['_USERADDREQUEST']._serialized_end=11761 - _globals['_USERUPDATEREQUEST']._serialized_start=11763 - _globals['_USERUPDATEREQUEST']._serialized_end=11821 - _globals['_USERUPDATE']._serialized_start=11824 - _globals['_USERUPDATE']._serialized_end=11999 - _globals['_USERUPDATERESPONSE']._serialized_start=12001 - _globals['_USERUPDATERESPONSE']._serialized_end=12066 - _globals['_USERUPDATERESULT']._serialized_start=12068 - _globals['_USERUPDATERESULT']._serialized_end=12158 - _globals['_COMPLIANCERECORDOWNERSREQUEST']._serialized_start=12160 - _globals['_COMPLIANCERECORDOWNERSREQUEST']._serialized_end=12234 - _globals['_COMPLIANCERECORDOWNERSRESPONSE']._serialized_start=12236 - _globals['_COMPLIANCERECORDOWNERSRESPONSE']._serialized_end=12315 - _globals['_RECORDOWNER']._serialized_start=12317 - _globals['_RECORDOWNER']._serialized_end=12372 - _globals['_PRELIMINARYCOMPLIANCEDATAREQUEST']._serialized_start=12375 - _globals['_PRELIMINARYCOMPLIANCEDATAREQUEST']._serialized_end=12541 - _globals['_PRELIMINARYCOMPLIANCEDATARESPONSE']._serialized_start=12544 - _globals['_PRELIMINARYCOMPLIANCEDATARESPONSE']._serialized_end=12703 - _globals['_AUDITUSERRECORD']._serialized_start=12705 - _globals['_AUDITUSERRECORD']._serialized_end=12780 - _globals['_AUDITUSERDATA']._serialized_start=12783 - _globals['_AUDITUSERDATA']._serialized_end=12924 - _globals['_COMPLIANCEREPORTFILTERS']._serialized_start=12926 - _globals['_COMPLIANCEREPORTFILTERS']._serialized_end=13053 - _globals['_COMPLIANCEREPORTREQUEST']._serialized_start=13055 - _globals['_COMPLIANCEREPORTREQUEST']._serialized_end=13182 - _globals['_COMPLIANCEREPORTRUN']._serialized_start=13185 - _globals['_COMPLIANCEREPORTRUN']._serialized_end=13318 - _globals['_COMPLIANCEREPORTCRITERIAANDFILTER']._serialized_start=13321 - _globals['_COMPLIANCEREPORTCRITERIAANDFILTER']._serialized_end=13573 - _globals['_COMPLIANCEREPORTCRITERIA']._serialized_start=13575 - _globals['_COMPLIANCEREPORTCRITERIA']._serialized_end=13673 - _globals['_COMPLIANCEREPORTFILTER']._serialized_start=13675 - _globals['_COMPLIANCEREPORTFILTER']._serialized_end=13795 - _globals['_COMPLIANCEREPORTRESPONSE']._serialized_start=13798 - _globals['_COMPLIANCEREPORTRESPONSE']._serialized_end=14471 - _globals['_AUDITRECORD']._serialized_start=14474 - _globals['_AUDITRECORD']._serialized_end=14603 - _globals['_AUDITROLE']._serialized_start=14606 - _globals['_AUDITROLE']._serialized_end=14862 - _globals['_ROLENODEMANAGEMENT']._serialized_start=14864 - _globals['_ROLENODEMANAGEMENT']._serialized_end=14958 - _globals['_USERPROFILE']._serialized_start=14960 - _globals['_USERPROFILE']._serialized_end=15067 - _globals['_RECORDPERMISSION']._serialized_start=15069 - _globals['_RECORDPERMISSION']._serialized_end=15130 - _globals['_USERRECORD']._serialized_start=15132 - _globals['_USERRECORD']._serialized_end=15227 - _globals['_AUDITTEAM']._serialized_start=15229 - _globals['_AUDITTEAM']._serialized_end=15320 - _globals['_AUDITTEAMUSER']._serialized_start=15322 - _globals['_AUDITTEAMUSER']._serialized_end=15381 - _globals['_SHAREDFOLDERRECORD']._serialized_start=15384 - _globals['_SHAREDFOLDERRECORD']._serialized_end=15543 - _globals['_SHAREADMINRECORD']._serialized_start=15545 - _globals['_SHAREADMINRECORD']._serialized_end=15622 - _globals['_SHAREDFOLDERUSER']._serialized_start=15624 - _globals['_SHAREDFOLDERUSER']._serialized_end=15694 - _globals['_SHAREDFOLDERTEAM']._serialized_start=15696 - _globals['_SHAREDFOLDERTEAM']._serialized_end=15757 - _globals['_GETCOMPLIANCEREPORTREQUEST']._serialized_start=15759 - _globals['_GETCOMPLIANCEREPORTREQUEST']._serialized_end=15806 - _globals['_GETCOMPLIANCEREPORTRESPONSE']._serialized_start=15808 - _globals['_GETCOMPLIANCEREPORTRESPONSE']._serialized_end=15858 - _globals['_COMPLIANCEREPORTCRITERIAREQUEST']._serialized_start=15860 - _globals['_COMPLIANCEREPORTCRITERIAREQUEST']._serialized_end=15914 - _globals['_SAVECOMPLIANCEREPORTCRITERIARESPONSE']._serialized_start=15916 - _globals['_SAVECOMPLIANCEREPORTCRITERIARESPONSE']._serialized_end=15975 - _globals['_LINKEDRECORD']._serialized_start=15977 - _globals['_LINKEDRECORD']._serialized_end=16029 - _globals['_GETSHARINGADMINSREQUEST']._serialized_start=16031 - _globals['_GETSHARINGADMINSREQUEST']._serialized_end=16118 - _globals['_USERPROFILEEXT']._serialized_start=16121 - _globals['_USERPROFILEEXT']._serialized_end=16345 - _globals['_GETSHARINGADMINSRESPONSE']._serialized_start=16347 - _globals['_GETSHARINGADMINSRESPONSE']._serialized_end=16426 - _globals['_TEAMSENTERPRISEUSERSADDREQUEST']._serialized_start=16428 - _globals['_TEAMSENTERPRISEUSERSADDREQUEST']._serialized_end=16523 - _globals['_TEAMSENTERPRISEUSERSADDTEAMREQUEST']._serialized_start=16525 - _globals['_TEAMSENTERPRISEUSERSADDTEAMREQUEST']._serialized_end=16641 - _globals['_TEAMSENTERPRISEUSERSADDUSERREQUEST']._serialized_start=16644 - _globals['_TEAMSENTERPRISEUSERSADDUSERREQUEST']._serialized_end=16815 - _globals['_TYPEDKEY']._serialized_start=16817 - _globals['_TYPEDKEY']._serialized_end=16887 - _globals['_TEAMSENTERPRISEUSERSADDRESPONSE']._serialized_start=16889 - _globals['_TEAMSENTERPRISEUSERSADDRESPONSE']._serialized_end=17004 - _globals['_TEAMSENTERPRISEUSERSADDTEAMRESPONSE']._serialized_start=17007 - _globals['_TEAMSENTERPRISEUSERSADDTEAMRESPONSE']._serialized_end=17203 - _globals['_TEAMSENTERPRISEUSERSADDUSERRESPONSE']._serialized_start=17206 - _globals['_TEAMSENTERPRISEUSERSADDUSERRESPONSE']._serialized_end=17365 - _globals['_TEAMENTERPRISEUSERREMOVE']._serialized_start=17367 - _globals['_TEAMENTERPRISEUSERREMOVE']._serialized_end=17436 - _globals['_TEAMENTERPRISEUSERREMOVESREQUEST']._serialized_start=17438 - _globals['_TEAMENTERPRISEUSERREMOVESREQUEST']._serialized_end=17544 - _globals['_TEAMENTERPRISEUSERREMOVESRESPONSE']._serialized_start=17546 - _globals['_TEAMENTERPRISEUSERREMOVESRESPONSE']._serialized_end=17669 - _globals['_TEAMENTERPRISEUSERREMOVERESPONSE']._serialized_start=17672 - _globals['_TEAMENTERPRISEUSERREMOVERESPONSE']._serialized_end=17856 - _globals['_DOMAINALIAS']._serialized_start=17858 - _globals['_DOMAINALIAS']._serialized_end=17935 - _globals['_DOMAINALIASREQUEST']._serialized_start=17937 - _globals['_DOMAINALIASREQUEST']._serialized_end=18003 - _globals['_DOMAINALIASRESPONSE']._serialized_start=18005 - _globals['_DOMAINALIASRESPONSE']._serialized_end=18072 - _globals['_ENTERPRISEUSERSPROVISIONREQUEST']._serialized_start=18074 - _globals['_ENTERPRISEUSERSPROVISIONREQUEST']._serialized_end=18183 - _globals['_ENTERPRISEUSERSPROVISION']._serialized_start=18186 - _globals['_ENTERPRISEUSERSPROVISION']._serialized_end=18624 - _globals['_ENTERPRISEUSERSPROVISIONRESPONSE']._serialized_start=18626 - _globals['_ENTERPRISEUSERSPROVISIONRESPONSE']._serialized_end=18721 - _globals['_ENTERPRISEUSERSPROVISIONRESULT']._serialized_start=18723 - _globals['_ENTERPRISEUSERSPROVISIONRESULT']._serialized_end=18836 - _globals['_ENTERPRISEUSERSADDREQUEST']._serialized_start=18838 - _globals['_ENTERPRISEUSERSADDREQUEST']._serialized_end=18935 - _globals['_ENTERPRISEUSERSADD']._serialized_start=18938 - _globals['_ENTERPRISEUSERSADD']._serialized_end=19206 - _globals['_ENTERPRISEUSERSADDRESPONSE']._serialized_start=19209 - _globals['_ENTERPRISEUSERSADDRESPONSE']._serialized_end=19364 - _globals['_ENTERPRISEUSERSADDRESULT']._serialized_start=19367 - _globals['_ENTERPRISEUSERSADDRESULT']._serialized_end=19517 - _globals['_UPDATEMSPPERMITSREQUEST']._serialized_start=19520 - _globals['_UPDATEMSPPERMITSREQUEST']._serialized_end=19705 - _globals['_DELETEENTERPRISEUSERSREQUEST']._serialized_start=19707 - _globals['_DELETEENTERPRISEUSERSREQUEST']._serialized_end=19764 - _globals['_DELETEENTERPRISEUSERSTATUS']._serialized_start=19766 - _globals['_DELETEENTERPRISEUSERSTATUS']._serialized_end=19877 - _globals['_DELETEENTERPRISEUSERSRESPONSE']._serialized_start=19879 - _globals['_DELETEENTERPRISEUSERSRESPONSE']._serialized_end=19972 - _globals['_CLEARSECURITYDATAREQUEST']._serialized_start=19974 - _globals['_CLEARSECURITYDATAREQUEST']._serialized_end=20093 - _globals['_LISTDOMAINSRESPONSE']._serialized_start=20095 - _globals['_LISTDOMAINSRESPONSE']._serialized_end=20132 - _globals['_RESERVEDOMAINREQUEST']._serialized_start=20134 - _globals['_RESERVEDOMAINREQUEST']._serialized_end=20234 - _globals['_RESERVEDOMAINRESPONSE']._serialized_start=20236 - _globals['_RESERVEDOMAINRESPONSE']._serialized_end=20274 - _globals['_ROLESBYTEAM']._serialized_start=20276 - _globals['_ROLESBYTEAM']._serialized_end=20322 - _globals['_LOCKUSERSREQUEST']._serialized_start=20325 - _globals['_LOCKUSERSREQUEST']._serialized_end=20466 - _globals['_LOCKUSERSRESPONSE']._serialized_start=20468 - _globals['_LOCKUSERSRESPONSE']._serialized_end=20535 - _globals['_LOCKUSERRESPONSE']._serialized_start=20537 - _globals['_LOCKUSERRESPONSE']._serialized_end=20647 + _globals['_KEYTYPE']._serialized_start=21125 + _globals['_KEYTYPE']._serialized_end=21152 + _globals['_ROLEUSERMODIFYSTATUS']._serialized_start=21155 + _globals['_ROLEUSERMODIFYSTATUS']._serialized_end=21458 + _globals['_ENTERPRISETYPE']._serialized_start=21460 + _globals['_ENTERPRISETYPE']._serialized_end=21521 + _globals['_TRANSFERACCEPTANCESTATUS']._serialized_start=21523 + _globals['_TRANSFERACCEPTANCESTATUS']._serialized_end=21638 + _globals['_ENTERPRISEDATAENTITY']._serialized_start=21641 + _globals['_ENTERPRISEDATAENTITY']._serialized_end=22122 + _globals['_CACHESTATUS']._serialized_start=22124 + _globals['_CACHESTATUS']._serialized_end=22158 + _globals['_BACKUPKEYTYPE']._serialized_start=22161 + _globals['_BACKUPKEYTYPE']._serialized_end=22308 + _globals['_BACKUPUSERDATAKEYTYPE']._serialized_start=22310 + _globals['_BACKUPUSERDATAKEYTYPE']._serialized_end=22368 + _globals['_ENCRYPTEDKEYTYPE']._serialized_start=22371 + _globals['_ENCRYPTEDKEYTYPE']._serialized_end=22536 + _globals['_ENTERPRISEFLAGTYPE']._serialized_start=22539 + _globals['_ENTERPRISEFLAGTYPE']._serialized_end=22850 + _globals['_USERUPDATESTATUS']._serialized_start=22853 + _globals['_USERUPDATESTATUS']._serialized_end=23096 + _globals['_AUDITUSERSTATUS']._serialized_start=23098 + _globals['_AUDITUSERSTATUS']._serialized_end=23171 + _globals['_TEAMUSERTYPE']._serialized_start=23173 + _globals['_TEAMUSERTYPE']._serialized_end=23224 + _globals['_APPCLIENTTYPE']._serialized_start=23226 + _globals['_APPCLIENTTYPE']._serialized_end=23346 + _globals['_DELETEENTERPRISEUSERSRESULT']._serialized_start=23349 + _globals['_DELETEENTERPRISEUSERSRESULT']._serialized_end=23492 + _globals['_CLEARSECURITYDATATYPE']._serialized_start=23495 + _globals['_CLEARSECURITYDATATYPE']._serialized_end=23630 + _globals['_RESERVEDOMAINACTION']._serialized_start=23632 + _globals['_RESERVEDOMAINACTION']._serialized_end=23706 + _globals['_USERLOCKSTATUS']._serialized_start=23708 + _globals['_USERLOCKSTATUS']._serialized_end=23823 + _globals['_EXTERNALCLOUDSECRETSSTORETYPE']._serialized_start=23826 + _globals['_EXTERNALCLOUDSECRETSSTORETYPE']._serialized_end=23954 + _globals['_ENTERPRISEKEYPAIRREQUEST']._serialized_start=47 + _globals['_ENTERPRISEKEYPAIRREQUEST']._serialized_end=179 + _globals['_GETTEAMMEMBERREQUEST']._serialized_start=181 + _globals['_GETTEAMMEMBERREQUEST']._serialized_end=220 + _globals['_ENTERPRISEUSER']._serialized_start=222 + _globals['_ENTERPRISEUSER']._serialized_end=347 + _globals['_GETTEAMMEMBERRESPONSE']._serialized_start=349 + _globals['_GETTEAMMEMBERRESPONSE']._serialized_end=424 + _globals['_ENTERPRISEUSERIDS']._serialized_start=426 + _globals['_ENTERPRISEUSERIDS']._serialized_end=471 + _globals['_ENTERPRISEPERSONALACCOUNT']._serialized_start=473 + _globals['_ENTERPRISEPERSONALACCOUNT']._serialized_end=539 + _globals['_ENCRYPTEDTEAMKEYREQUEST']._serialized_start=541 + _globals['_ENCRYPTEDTEAMKEYREQUEST']._serialized_end=624 + _globals['_REENCRYPTEDDATA']._serialized_start=626 + _globals['_REENCRYPTEDDATA']._serialized_end=669 + _globals['_REENCRYPTEDROLEKEY']._serialized_start=671 + _globals['_REENCRYPTEDROLEKEY']._serialized_end=734 + _globals['_REENCRYPTEDUSERDATAKEY']._serialized_start=736 + _globals['_REENCRYPTEDUSERDATAKEY']._serialized_end=816 + _globals['_NODETOMANAGEDCOMPANYREQUEST']._serialized_start=819 + _globals['_NODETOMANAGEDCOMPANYREQUEST']._serialized_end=1163 + _globals['_ROLETEAM']._serialized_start=1165 + _globals['_ROLETEAM']._serialized_end=1209 + _globals['_ROLETEAMS']._serialized_start=1211 + _globals['_ROLETEAMS']._serialized_end=1263 + _globals['_TEAMSBYROLE']._serialized_start=1265 + _globals['_TEAMSBYROLE']._serialized_end=1312 + _globals['_MANAGEDNODESBYROLE']._serialized_start=1314 + _globals['_MANAGEDNODESBYROLE']._serialized_end=1374 + _globals['_ROLEUSERADDKEYS']._serialized_start=1377 + _globals['_ROLEUSERADDKEYS']._serialized_end=1507 + _globals['_ROLEUSERADD']._serialized_start=1509 + _globals['_ROLEUSERADD']._serialized_end=1593 + _globals['_ROLEUSERSADDREQUEST']._serialized_start=1595 + _globals['_ROLEUSERSADDREQUEST']._serialized_end=1663 + _globals['_ROLEUSERADDRESULT']._serialized_start=1666 + _globals['_ROLEUSERADDRESULT']._serialized_end=1794 + _globals['_ROLEUSERSADDRESPONSE']._serialized_start=1796 + _globals['_ROLEUSERSADDRESPONSE']._serialized_end=1866 + _globals['_ROLEUSERREMOVE']._serialized_start=1868 + _globals['_ROLEUSERREMOVE']._serialized_end=1928 + _globals['_ROLEUSERSREMOVEREQUEST']._serialized_start=1930 + _globals['_ROLEUSERSREMOVEREQUEST']._serialized_end=2007 + _globals['_ROLEUSERREMOVERESULT']._serialized_start=2010 + _globals['_ROLEUSERREMOVERESULT']._serialized_end=2141 + _globals['_ROLEUSERSREMOVERESPONSE']._serialized_start=2143 + _globals['_ROLEUSERSREMOVERESPONSE']._serialized_end=2219 + _globals['_ENTERPRISEREGISTRATION']._serialized_start=2222 + _globals['_ENTERPRISEREGISTRATION']._serialized_end=2766 + _globals['_DOMAINPASSWORDRULESREQUEST']._serialized_start=2768 + _globals['_DOMAINPASSWORDRULESREQUEST']._serialized_end=2840 + _globals['_DOMAINPASSWORDRULESFIELDS']._serialized_start=2842 + _globals['_DOMAINPASSWORDRULESFIELDS']._serialized_end=2934 + _globals['_LOGINTOMCREQUEST']._serialized_start=2936 + _globals['_LOGINTOMCREQUEST']._serialized_end=3005 + _globals['_LOGINTOMCRESPONSE']._serialized_start=3007 + _globals['_LOGINTOMCRESPONSE']._serialized_end=3126 + _globals['_DOMAINPASSWORDRULESRESPONSE']._serialized_start=3128 + _globals['_DOMAINPASSWORDRULESRESPONSE']._serialized_end=3231 + _globals['_APPROVEUSERDEVICEREQUEST']._serialized_start=3234 + _globals['_APPROVEUSERDEVICEREQUEST']._serialized_end=3370 + _globals['_APPROVEUSERDEVICERESPONSE']._serialized_start=3372 + _globals['_APPROVEUSERDEVICERESPONSE']._serialized_end=3488 + _globals['_APPROVEUSERDEVICESREQUEST']._serialized_start=3490 + _globals['_APPROVEUSERDEVICESREQUEST']._serialized_end=3579 + _globals['_APPROVEUSERDEVICESRESPONSE']._serialized_start=3581 + _globals['_APPROVEUSERDEVICESRESPONSE']._serialized_end=3673 + _globals['_ENTERPRISEUSERDATAKEY']._serialized_start=3676 + _globals['_ENTERPRISEUSERDATAKEY']._serialized_end=3811 + _globals['_ENTERPRISEUSERDATAKEYS']._serialized_start=3813 + _globals['_ENTERPRISEUSERDATAKEYS']._serialized_end=3886 + _globals['_ENTERPRISEUSERDATAKEYLIGHT']._serialized_start=3888 + _globals['_ENTERPRISEUSERDATAKEYLIGHT']._serialized_end=3991 + _globals['_ENTERPRISEUSERDATAKEYSBYNODE']._serialized_start=3993 + _globals['_ENTERPRISEUSERDATAKEYSBYNODE']._serialized_end=4093 + _globals['_ENTERPRISEUSERDATAKEYSBYNODERESPONSE']._serialized_start=4095 + _globals['_ENTERPRISEUSERDATAKEYSBYNODERESPONSE']._serialized_end=4189 + _globals['_ENTERPRISEDATAREQUEST']._serialized_start=4191 + _globals['_ENTERPRISEDATAREQUEST']._serialized_end=4241 + _globals['_SPECIALPROVISIONING']._serialized_start=4243 + _globals['_SPECIALPROVISIONING']._serialized_end=4291 + _globals['_GENERALDATAENTITY']._serialized_start=4294 + _globals['_GENERALDATAENTITY']._serialized_end=4554 + _globals['_NODE']._serialized_start=4557 + _globals['_NODE']._serialized_end=4810 + _globals['_ROLE']._serialized_start=4813 + _globals['_ROLE']._serialized_end=4955 + _globals['_USER']._serialized_start=4958 + _globals['_USER']._serialized_end=5270 + _globals['_USERALIAS']._serialized_start=5272 + _globals['_USERALIAS']._serialized_end=5327 + _globals['_COMPLIANCEREPORTMETADATA']._serialized_start=5330 + _globals['_COMPLIANCEREPORTMETADATA']._serialized_end=5502 + _globals['_MANAGEDNODE']._serialized_start=5504 + _globals['_MANAGEDNODE']._serialized_end=5587 + _globals['_USERMANAGEDNODE']._serialized_start=5589 + _globals['_USERMANAGEDNODE']._serialized_end=5673 + _globals['_USERPRIVILEGE']._serialized_start=5675 + _globals['_USERPRIVILEGE']._serialized_end=5794 + _globals['_ROLEUSER']._serialized_start=5796 + _globals['_ROLEUSER']._serialized_end=5848 + _globals['_ROLEPRIVILEGE']._serialized_start=5850 + _globals['_ROLEPRIVILEGE']._serialized_end=5927 + _globals['_PRIVILEGESBYMANAGEDNODE']._serialized_start=5929 + _globals['_PRIVILEGESBYMANAGEDNODE']._serialized_end=6013 + _globals['_ROLEENFORCEMENT']._serialized_start=6015 + _globals['_ROLEENFORCEMENT']._serialized_end=6088 + _globals['_TEAM']._serialized_start=6091 + _globals['_TEAM']._serialized_end=6260 + _globals['_TEAMUSER']._serialized_start=6262 + _globals['_TEAMUSER']._serialized_end=6333 + _globals['_GETDISTRIBUTORINFORESPONSE']._serialized_start=6335 + _globals['_GETDISTRIBUTORINFORESPONSE']._serialized_end=6410 + _globals['_DISTRIBUTOR']._serialized_start=6412 + _globals['_DISTRIBUTOR']._serialized_end=6478 + _globals['_MSPINFO']._serialized_start=6481 + _globals['_MSPINFO']._serialized_end=6766 + _globals['_MANAGEDCOMPANY']._serialized_start=6769 + _globals['_MANAGEDCOMPANY']._serialized_end=7065 + _globals['_MSPPOOL']._serialized_start=7067 + _globals['_MSPPOOL']._serialized_end=7149 + _globals['_MSPCONTACT']._serialized_start=7151 + _globals['_MSPCONTACT']._serialized_end=7209 + _globals['_LICENSEADDON']._serialized_start=7212 + _globals['_LICENSEADDON']._serialized_end=7472 + _globals['_MCDEFAULT']._serialized_start=7474 + _globals['_MCDEFAULT']._serialized_end=7589 + _globals['_MSPPERMITS']._serialized_start=7592 + _globals['_MSPPERMITS']._serialized_end=7802 + _globals['_LICENSE']._serialized_start=7805 + _globals['_LICENSE']._serialized_end=8349 + _globals['_BRIDGE']._serialized_start=8351 + _globals['_BRIDGE']._serialized_end=8461 + _globals['_SCIM']._serialized_start=8463 + _globals['_SCIM']._serialized_end=8579 + _globals['_EMAILPROVISION']._serialized_start=8581 + _globals['_EMAILPROVISION']._serialized_end=8657 + _globals['_QUEUEDTEAM']._serialized_start=8659 + _globals['_QUEUEDTEAM']._serialized_end=8741 + _globals['_QUEUEDTEAMUSER']._serialized_start=8743 + _globals['_QUEUEDTEAMUSER']._serialized_end=8791 + _globals['_TEAMSADDRESULT']._serialized_start=8794 + _globals['_TEAMSADDRESULT']._serialized_end=8958 + _globals['_TEAMADDRESULT']._serialized_start=8960 + _globals['_TEAMADDRESULT']._serialized_end=9045 + _globals['_SSOSERVICE']._serialized_start=9048 + _globals['_SSOSERVICE']._serialized_end=9193 + _globals['_REPORTFILTERUSER']._serialized_start=9195 + _globals['_REPORTFILTERUSER']._serialized_end=9244 + _globals['_DEVICEREQUESTFORADMINAPPROVAL']._serialized_start=9247 + _globals['_DEVICEREQUESTFORADMINAPPROVAL']._serialized_end=9526 + _globals['_ENTERPRISEDATA']._serialized_start=9528 + _globals['_ENTERPRISEDATA']._serialized_end=9624 + _globals['_ENTERPRISEDATARESPONSE']._serialized_start=9627 + _globals['_ENTERPRISEDATARESPONSE']._serialized_end=9835 + _globals['_BACKUPREQUEST']._serialized_start=9837 + _globals['_BACKUPREQUEST']._serialized_end=9879 + _globals['_BACKUPRECORD']._serialized_start=9882 + _globals['_BACKUPRECORD']._serialized_end=10034 + _globals['_BACKUPKEY']._serialized_start=10036 + _globals['_BACKUPKEY']._serialized_end=10082 + _globals['_BACKUPUSER']._serialized_start=10085 + _globals['_BACKUPUSER']._serialized_end=10354 + _globals['_BACKUPRESPONSE']._serialized_start=10357 + _globals['_BACKUPRESPONSE']._serialized_end=10515 + _globals['_BACKUPFILE']._serialized_start=10517 + _globals['_BACKUPFILE']._serialized_end=10618 + _globals['_BACKUPSRESPONSE']._serialized_start=10620 + _globals['_BACKUPSRESPONSE']._serialized_end=10676 + _globals['_GETENTERPRISEDATAKEYSREQUEST']._serialized_start=10678 + _globals['_GETENTERPRISEDATAKEYSREQUEST']._serialized_end=10724 + _globals['_GETENTERPRISEDATAKEYSRESPONSE']._serialized_start=10727 + _globals['_GETENTERPRISEDATAKEYSRESPONSE']._serialized_end=10982 + _globals['_ROLEKEY']._serialized_start=10984 + _globals['_ROLEKEY']._serialized_end=11078 + _globals['_MSPKEY']._serialized_start=11080 + _globals['_MSPKEY']._serialized_end=11180 + _globals['_ENTERPRISEKEYS']._serialized_start=11182 + _globals['_ENTERPRISEKEYS']._serialized_end=11306 + _globals['_TREEKEY']._serialized_start=11308 + _globals['_TREEKEY']._serialized_end=11380 + _globals['_SHAREDRECORDRESPONSE']._serialized_start=11382 + _globals['_SHAREDRECORDRESPONSE']._serialized_end=11451 + _globals['_SHAREDRECORDEVENT']._serialized_start=11453 + _globals['_SHAREDRECORDEVENT']._serialized_end=11565 + _globals['_SETRESTRICTVISIBILITYREQUEST']._serialized_start=11567 + _globals['_SETRESTRICTVISIBILITYREQUEST']._serialized_end=11613 + _globals['_USERADDREQUEST']._serialized_start=11616 + _globals['_USERADDREQUEST']._serialized_end=11824 + _globals['_USERUPDATEREQUEST']._serialized_start=11826 + _globals['_USERUPDATEREQUEST']._serialized_end=11884 + _globals['_USERUPDATE']._serialized_start=11887 + _globals['_USERUPDATE']._serialized_end=12118 + _globals['_USERUPDATERESPONSE']._serialized_start=12120 + _globals['_USERUPDATERESPONSE']._serialized_end=12185 + _globals['_USERUPDATERESULT']._serialized_start=12188 + _globals['_USERUPDATERESULT']._serialized_end=12324 + _globals['_COMPLIANCERECORDOWNERSREQUEST']._serialized_start=12326 + _globals['_COMPLIANCERECORDOWNERSREQUEST']._serialized_end=12400 + _globals['_COMPLIANCERECORDOWNERSRESPONSE']._serialized_start=12402 + _globals['_COMPLIANCERECORDOWNERSRESPONSE']._serialized_end=12481 + _globals['_RECORDOWNER']._serialized_start=12483 + _globals['_RECORDOWNER']._serialized_end=12538 + _globals['_PRELIMINARYCOMPLIANCEDATAREQUEST']._serialized_start=12541 + _globals['_PRELIMINARYCOMPLIANCEDATAREQUEST']._serialized_end=12707 + _globals['_PRELIMINARYCOMPLIANCEDATARESPONSE']._serialized_start=12710 + _globals['_PRELIMINARYCOMPLIANCEDATARESPONSE']._serialized_end=12869 + _globals['_AUDITUSERRECORD']._serialized_start=12871 + _globals['_AUDITUSERRECORD']._serialized_end=12969 + _globals['_AUDITUSERDATA']._serialized_start=12972 + _globals['_AUDITUSERDATA']._serialized_end=13113 + _globals['_COMPLIANCEREPORTFILTERS']._serialized_start=13115 + _globals['_COMPLIANCEREPORTFILTERS']._serialized_end=13242 + _globals['_COMPLIANCEREPORTREQUEST']._serialized_start=13244 + _globals['_COMPLIANCEREPORTREQUEST']._serialized_end=13371 + _globals['_COMPLIANCEREPORTRUN']._serialized_start=13374 + _globals['_COMPLIANCEREPORTRUN']._serialized_end=13507 + _globals['_COMPLIANCEREPORTCRITERIAANDFILTER']._serialized_start=13510 + _globals['_COMPLIANCEREPORTCRITERIAANDFILTER']._serialized_end=13762 + _globals['_COMPLIANCEREPORTCRITERIA']._serialized_start=13764 + _globals['_COMPLIANCEREPORTCRITERIA']._serialized_end=13862 + _globals['_COMPLIANCEREPORTFILTER']._serialized_start=13864 + _globals['_COMPLIANCEREPORTFILTER']._serialized_end=13984 + _globals['_COMPLIANCEREPORTRESPONSE']._serialized_start=13987 + _globals['_COMPLIANCEREPORTRESPONSE']._serialized_end=14660 + _globals['_AUDITRECORD']._serialized_start=14663 + _globals['_AUDITRECORD']._serialized_end=14815 + _globals['_AUDITROLE']._serialized_start=14818 + _globals['_AUDITROLE']._serialized_end=15074 + _globals['_ROLENODEMANAGEMENT']._serialized_start=15076 + _globals['_ROLENODEMANAGEMENT']._serialized_end=15170 + _globals['_USERPROFILE']._serialized_start=15172 + _globals['_USERPROFILE']._serialized_end=15279 + _globals['_RECORDPERMISSION']._serialized_start=15281 + _globals['_RECORDPERMISSION']._serialized_end=15404 + _globals['_DRIVEPERMISSION']._serialized_start=15407 + _globals['_DRIVEPERMISSION']._serialized_end=15606 + _globals['_USERRECORD']._serialized_start=15608 + _globals['_USERRECORD']._serialized_end=15703 + _globals['_AUDITTEAM']._serialized_start=15705 + _globals['_AUDITTEAM']._serialized_end=15796 + _globals['_AUDITTEAMUSER']._serialized_start=15798 + _globals['_AUDITTEAMUSER']._serialized_end=15857 + _globals['_SHAREDFOLDERRECORD']._serialized_start=15860 + _globals['_SHAREDFOLDERRECORD']._serialized_end=16019 + _globals['_SHAREADMINRECORD']._serialized_start=16021 + _globals['_SHAREADMINRECORD']._serialized_end=16098 + _globals['_SHAREDFOLDERUSER']._serialized_start=16100 + _globals['_SHAREDFOLDERUSER']._serialized_end=16170 + _globals['_SHAREDFOLDERTEAM']._serialized_start=16172 + _globals['_SHAREDFOLDERTEAM']._serialized_end=16233 + _globals['_GETCOMPLIANCEREPORTREQUEST']._serialized_start=16235 + _globals['_GETCOMPLIANCEREPORTREQUEST']._serialized_end=16282 + _globals['_GETCOMPLIANCEREPORTRESPONSE']._serialized_start=16284 + _globals['_GETCOMPLIANCEREPORTRESPONSE']._serialized_end=16334 + _globals['_COMPLIANCEREPORTCRITERIAREQUEST']._serialized_start=16336 + _globals['_COMPLIANCEREPORTCRITERIAREQUEST']._serialized_end=16390 + _globals['_SAVECOMPLIANCEREPORTCRITERIARESPONSE']._serialized_start=16392 + _globals['_SAVECOMPLIANCEREPORTCRITERIARESPONSE']._serialized_end=16451 + _globals['_LINKEDRECORD']._serialized_start=16453 + _globals['_LINKEDRECORD']._serialized_end=16505 + _globals['_GETSHARINGADMINSREQUEST']._serialized_start=16507 + _globals['_GETSHARINGADMINSREQUEST']._serialized_end=16594 + _globals['_USERPROFILEEXT']._serialized_start=16597 + _globals['_USERPROFILEEXT']._serialized_end=16821 + _globals['_GETSHARINGADMINSRESPONSE']._serialized_start=16823 + _globals['_GETSHARINGADMINSRESPONSE']._serialized_end=16902 + _globals['_TEAMSENTERPRISEUSERSADDREQUEST']._serialized_start=16904 + _globals['_TEAMSENTERPRISEUSERSADDREQUEST']._serialized_end=16999 + _globals['_TEAMSENTERPRISEUSERSADDTEAMREQUEST']._serialized_start=17001 + _globals['_TEAMSENTERPRISEUSERSADDTEAMREQUEST']._serialized_end=17117 + _globals['_TEAMSENTERPRISEUSERSADDUSERREQUEST']._serialized_start=17120 + _globals['_TEAMSENTERPRISEUSERSADDUSERREQUEST']._serialized_end=17291 + _globals['_TYPEDKEY']._serialized_start=17293 + _globals['_TYPEDKEY']._serialized_end=17363 + _globals['_TEAMSENTERPRISEUSERSADDRESPONSE']._serialized_start=17365 + _globals['_TEAMSENTERPRISEUSERSADDRESPONSE']._serialized_end=17480 + _globals['_TEAMSENTERPRISEUSERSADDTEAMRESPONSE']._serialized_start=17483 + _globals['_TEAMSENTERPRISEUSERSADDTEAMRESPONSE']._serialized_end=17679 + _globals['_TEAMSENTERPRISEUSERSADDUSERRESPONSE']._serialized_start=17682 + _globals['_TEAMSENTERPRISEUSERSADDUSERRESPONSE']._serialized_end=17841 + _globals['_TEAMENTERPRISEUSERREMOVE']._serialized_start=17843 + _globals['_TEAMENTERPRISEUSERREMOVE']._serialized_end=17912 + _globals['_TEAMENTERPRISEUSERREMOVESREQUEST']._serialized_start=17914 + _globals['_TEAMENTERPRISEUSERREMOVESREQUEST']._serialized_end=18020 + _globals['_TEAMENTERPRISEUSERREMOVESRESPONSE']._serialized_start=18022 + _globals['_TEAMENTERPRISEUSERREMOVESRESPONSE']._serialized_end=18145 + _globals['_TEAMENTERPRISEUSERREMOVERESPONSE']._serialized_start=18148 + _globals['_TEAMENTERPRISEUSERREMOVERESPONSE']._serialized_end=18332 + _globals['_DOMAINALIAS']._serialized_start=18334 + _globals['_DOMAINALIAS']._serialized_end=18411 + _globals['_DOMAINALIASREQUEST']._serialized_start=18413 + _globals['_DOMAINALIASREQUEST']._serialized_end=18479 + _globals['_DOMAINALIASRESPONSE']._serialized_start=18481 + _globals['_DOMAINALIASRESPONSE']._serialized_end=18548 + _globals['_ENTERPRISEUSERSPROVISIONREQUEST']._serialized_start=18550 + _globals['_ENTERPRISEUSERSPROVISIONREQUEST']._serialized_end=18659 + _globals['_ENTERPRISEUSERSPROVISION']._serialized_start=18662 + _globals['_ENTERPRISEUSERSPROVISION']._serialized_end=19100 + _globals['_ENTERPRISEUSERSPROVISIONRESPONSE']._serialized_start=19102 + _globals['_ENTERPRISEUSERSPROVISIONRESPONSE']._serialized_end=19197 + _globals['_ENTERPRISEUSERSPROVISIONRESULT']._serialized_start=19199 + _globals['_ENTERPRISEUSERSPROVISIONRESULT']._serialized_end=19312 + _globals['_ENTERPRISEUSERSADDREQUEST']._serialized_start=19314 + _globals['_ENTERPRISEUSERSADDREQUEST']._serialized_end=19411 + _globals['_ENTERPRISEUSERSADD']._serialized_start=19414 + _globals['_ENTERPRISEUSERSADD']._serialized_end=19682 + _globals['_ENTERPRISEUSERSADDRESPONSE']._serialized_start=19685 + _globals['_ENTERPRISEUSERSADDRESPONSE']._serialized_end=19840 + _globals['_ENTERPRISEUSERSADDRESULT']._serialized_start=19843 + _globals['_ENTERPRISEUSERSADDRESULT']._serialized_end=19993 + _globals['_UPDATEMSPPERMITSREQUEST']._serialized_start=19996 + _globals['_UPDATEMSPPERMITSREQUEST']._serialized_end=20181 + _globals['_DELETEENTERPRISEUSERSREQUEST']._serialized_start=20183 + _globals['_DELETEENTERPRISEUSERSREQUEST']._serialized_end=20240 + _globals['_DELETEENTERPRISEUSERSTATUS']._serialized_start=20242 + _globals['_DELETEENTERPRISEUSERSTATUS']._serialized_end=20353 + _globals['_DELETEENTERPRISEUSERSRESPONSE']._serialized_start=20355 + _globals['_DELETEENTERPRISEUSERSRESPONSE']._serialized_end=20448 + _globals['_CLEARSECURITYDATAREQUEST']._serialized_start=20450 + _globals['_CLEARSECURITYDATAREQUEST']._serialized_end=20569 + _globals['_LISTDOMAINSRESPONSE']._serialized_start=20571 + _globals['_LISTDOMAINSRESPONSE']._serialized_end=20608 + _globals['_RESERVEDOMAINREQUEST']._serialized_start=20610 + _globals['_RESERVEDOMAINREQUEST']._serialized_end=20710 + _globals['_RESERVEDOMAINRESPONSE']._serialized_start=20712 + _globals['_RESERVEDOMAINRESPONSE']._serialized_end=20750 + _globals['_ROLESBYTEAM']._serialized_start=20752 + _globals['_ROLESBYTEAM']._serialized_end=20798 + _globals['_LOCKUSERSREQUEST']._serialized_start=20801 + _globals['_LOCKUSERSREQUEST']._serialized_end=20942 + _globals['_LOCKUSERSRESPONSE']._serialized_start=20944 + _globals['_LOCKUSERSRESPONSE']._serialized_end=21011 + _globals['_LOCKUSERRESPONSE']._serialized_start=21013 + _globals['_LOCKUSERRESPONSE']._serialized_end=21123 # @@protoc_insertion_point(module_scope) diff --git a/keepercommander/proto/enterprise_pb2.pyi b/keepercommander/proto/enterprise_pb2.pyi index 2d6931822..c527a7059 100644 --- a/keepercommander/proto/enterprise_pb2.pyi +++ b/keepercommander/proto/enterprise_pb2.pyi @@ -1,3 +1,4 @@ +from . import folder_pb2 as _folder_pb2 from google.protobuf.internal import containers as _containers from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper from google.protobuf import descriptor as _descriptor @@ -23,6 +24,7 @@ class RoleUserModifyStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): MUST_HAVE_ONE_USER_ADMIN: _ClassVar[RoleUserModifyStatus] INVALID_ROLE_ID: _ClassVar[RoleUserModifyStatus] PAM_LICENSE_SEAT_EXCEEDED: _ClassVar[RoleUserModifyStatus] + WOULD_LOCK_SELF: _ClassVar[RoleUserModifyStatus] class EnterpriseType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): __slots__ = () @@ -110,6 +112,12 @@ class UserUpdateStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): __slots__ = () USER_UPDATE_OK: _ClassVar[UserUpdateStatus] USER_UPDATE_ACCESS_DENIED: _ClassVar[UserUpdateStatus] + USER_UPDATE_EXCEEDED_LICENSE_SEATS: _ClassVar[UserUpdateStatus] + USER_UPDATE_BAD_REQUEST: _ClassVar[UserUpdateStatus] + USER_UPDATE_DUPLICATE: _ClassVar[UserUpdateStatus] + USER_UPDATE_INVALID_STATE: _ClassVar[UserUpdateStatus] + USER_UPDATE_FAILED: _ClassVar[UserUpdateStatus] + USER_UPDATE_ERROR: _ClassVar[UserUpdateStatus] class AuditUserStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): __slots__ = () @@ -178,6 +186,7 @@ MAY_NOT_REMOVE_SELF_FROM_ROLE: RoleUserModifyStatus MUST_HAVE_ONE_USER_ADMIN: RoleUserModifyStatus INVALID_ROLE_ID: RoleUserModifyStatus PAM_LICENSE_SEAT_EXCEEDED: RoleUserModifyStatus +WOULD_LOCK_SELF: RoleUserModifyStatus ENTERPRISE_STANDARD: EnterpriseType ENTERPRISE_MSP: EnterpriseType UNDEFINED: TransferAcceptanceStatus @@ -238,6 +247,12 @@ FORBID_KEY_TYPE_1: EnterpriseFlagType KEEPER_DRIVE: EnterpriseFlagType USER_UPDATE_OK: UserUpdateStatus USER_UPDATE_ACCESS_DENIED: UserUpdateStatus +USER_UPDATE_EXCEEDED_LICENSE_SEATS: UserUpdateStatus +USER_UPDATE_BAD_REQUEST: UserUpdateStatus +USER_UPDATE_DUPLICATE: UserUpdateStatus +USER_UPDATE_INVALID_STATE: UserUpdateStatus +USER_UPDATE_FAILED: UserUpdateStatus +USER_UPDATE_ERROR: UserUpdateStatus OK: AuditUserStatus ACCESS_DENIED: AuditUserStatus NO_LONGER_IN_ENTERPRISE: AuditUserStatus @@ -299,7 +314,7 @@ class EnterpriseUser(_message.Message): enterpriseUsername: str isShareAdmin: bool username: str - def __init__(self, enterpriseUserId: _Optional[int] = ..., email: _Optional[str] = ..., enterpriseUsername: _Optional[str] = ..., isShareAdmin: bool = ..., username: _Optional[str] = ...) -> None: ... + def __init__(self, enterpriseUserId: _Optional[int] = ..., email: _Optional[str] = ..., enterpriseUsername: _Optional[str] = ..., isShareAdmin: _Optional[bool] = ..., username: _Optional[str] = ...) -> None: ... class GetTeamMemberResponse(_message.Message): __slots__ = ("enterpriseUser",) @@ -329,7 +344,7 @@ class EncryptedTeamKeyRequest(_message.Message): teamUid: bytes encryptedTeamKey: bytes force: bool - def __init__(self, teamUid: _Optional[bytes] = ..., encryptedTeamKey: _Optional[bytes] = ..., force: bool = ...) -> None: ... + def __init__(self, teamUid: _Optional[bytes] = ..., encryptedTeamKey: _Optional[bytes] = ..., force: _Optional[bool] = ...) -> None: ... class ReEncryptedData(_message.Message): __slots__ = ("id", "data") @@ -404,14 +419,16 @@ class ManagedNodesByRole(_message.Message): def __init__(self, role_id: _Optional[int] = ..., managedNodeId: _Optional[_Iterable[int]] = ...) -> None: ... class RoleUserAddKeys(_message.Message): - __slots__ = ("enterpriseUserId", "treeKey", "roleAdminKey") + __slots__ = ("enterpriseUserId", "treeKey", "roleAdminKey", "typedTreeKey") ENTERPRISEUSERID_FIELD_NUMBER: _ClassVar[int] TREEKEY_FIELD_NUMBER: _ClassVar[int] ROLEADMINKEY_FIELD_NUMBER: _ClassVar[int] + TYPEDTREEKEY_FIELD_NUMBER: _ClassVar[int] enterpriseUserId: int treeKey: str roleAdminKey: str - def __init__(self, enterpriseUserId: _Optional[int] = ..., treeKey: _Optional[str] = ..., roleAdminKey: _Optional[str] = ...) -> None: ... + typedTreeKey: TypedKey + def __init__(self, enterpriseUserId: _Optional[int] = ..., treeKey: _Optional[str] = ..., roleAdminKey: _Optional[str] = ..., typedTreeKey: _Optional[_Union[TypedKey, _Mapping]] = ...) -> None: ... class RoleUserAdd(_message.Message): __slots__ = ("role_id", "roleUserAddKeys") @@ -531,7 +548,7 @@ class DomainPasswordRulesFields(_message.Message): minimum: int maximum: int allowed: bool - def __init__(self, type: _Optional[str] = ..., minimum: _Optional[int] = ..., maximum: _Optional[int] = ..., allowed: bool = ...) -> None: ... + def __init__(self, type: _Optional[str] = ..., minimum: _Optional[int] = ..., maximum: _Optional[int] = ..., allowed: _Optional[bool] = ...) -> None: ... class LoginToMcRequest(_message.Message): __slots__ = ("mcEnterpriseId", "messageSessionUid") @@ -551,7 +568,7 @@ class LoginToMcResponse(_message.Message): encryptedTreeKey: str keyTypeId: int forbidKeyType2: bool - def __init__(self, encryptedSessionToken: _Optional[bytes] = ..., encryptedTreeKey: _Optional[str] = ..., keyTypeId: _Optional[int] = ..., forbidKeyType2: bool = ...) -> None: ... + def __init__(self, encryptedSessionToken: _Optional[bytes] = ..., encryptedTreeKey: _Optional[str] = ..., keyTypeId: _Optional[int] = ..., forbidKeyType2: _Optional[bool] = ...) -> None: ... class DomainPasswordRulesResponse(_message.Message): __slots__ = ("domainPasswordRulesFields",) @@ -569,7 +586,7 @@ class ApproveUserDeviceRequest(_message.Message): encryptedDeviceToken: bytes encryptedDeviceDataKey: bytes denyApproval: bool - def __init__(self, enterpriseUserId: _Optional[int] = ..., encryptedDeviceToken: _Optional[bytes] = ..., encryptedDeviceDataKey: _Optional[bytes] = ..., denyApproval: bool = ...) -> None: ... + def __init__(self, enterpriseUserId: _Optional[int] = ..., encryptedDeviceToken: _Optional[bytes] = ..., encryptedDeviceDataKey: _Optional[bytes] = ..., denyApproval: _Optional[bool] = ...) -> None: ... class ApproveUserDeviceResponse(_message.Message): __slots__ = ("enterpriseUserId", "encryptedDeviceToken", "failed", "message") @@ -581,7 +598,7 @@ class ApproveUserDeviceResponse(_message.Message): encryptedDeviceToken: bytes failed: bool message: str - def __init__(self, enterpriseUserId: _Optional[int] = ..., encryptedDeviceToken: _Optional[bytes] = ..., failed: bool = ..., message: _Optional[str] = ...) -> None: ... + def __init__(self, enterpriseUserId: _Optional[int] = ..., encryptedDeviceToken: _Optional[bytes] = ..., failed: _Optional[bool] = ..., message: _Optional[str] = ...) -> None: ... class ApproveUserDevicesRequest(_message.Message): __slots__ = ("deviceRequests",) @@ -669,7 +686,7 @@ class GeneralDataEntity(_message.Message): distributor: bool forbidAccountTransfer: bool showUserOnboard: bool - def __init__(self, enterpriseName: _Optional[str] = ..., restrictVisibility: bool = ..., specialProvisioning: _Optional[_Union[SpecialProvisioning, _Mapping]] = ..., userPrivilege: _Optional[_Union[UserPrivilege, _Mapping]] = ..., distributor: bool = ..., forbidAccountTransfer: bool = ..., showUserOnboard: bool = ...) -> None: ... + def __init__(self, enterpriseName: _Optional[str] = ..., restrictVisibility: _Optional[bool] = ..., specialProvisioning: _Optional[_Union[SpecialProvisioning, _Mapping]] = ..., userPrivilege: _Optional[_Union[UserPrivilege, _Mapping]] = ..., distributor: _Optional[bool] = ..., forbidAccountTransfer: _Optional[bool] = ..., showUserOnboard: _Optional[bool] = ...) -> None: ... class Node(_message.Message): __slots__ = ("nodeId", "parentId", "bridgeId", "scimId", "licenseId", "encryptedData", "duoEnabled", "rsaEnabled", "ssoServiceProviderId", "restrictVisibility", "ssoServiceProviderIds") @@ -695,7 +712,7 @@ class Node(_message.Message): ssoServiceProviderId: int restrictVisibility: bool ssoServiceProviderIds: _containers.RepeatedScalarFieldContainer[int] - def __init__(self, nodeId: _Optional[int] = ..., parentId: _Optional[int] = ..., bridgeId: _Optional[int] = ..., scimId: _Optional[int] = ..., licenseId: _Optional[int] = ..., encryptedData: _Optional[str] = ..., duoEnabled: bool = ..., rsaEnabled: bool = ..., ssoServiceProviderId: _Optional[int] = ..., restrictVisibility: bool = ..., ssoServiceProviderIds: _Optional[_Iterable[int]] = ...) -> None: ... + def __init__(self, nodeId: _Optional[int] = ..., parentId: _Optional[int] = ..., bridgeId: _Optional[int] = ..., scimId: _Optional[int] = ..., licenseId: _Optional[int] = ..., encryptedData: _Optional[str] = ..., duoEnabled: _Optional[bool] = ..., rsaEnabled: _Optional[bool] = ..., ssoServiceProviderId: _Optional[int] = ..., restrictVisibility: _Optional[bool] = ..., ssoServiceProviderIds: _Optional[_Iterable[int]] = ...) -> None: ... class Role(_message.Message): __slots__ = ("roleId", "nodeId", "encryptedData", "keyType", "visibleBelow", "newUserInherit", "roleType") @@ -713,7 +730,7 @@ class Role(_message.Message): visibleBelow: bool newUserInherit: bool roleType: str - def __init__(self, roleId: _Optional[int] = ..., nodeId: _Optional[int] = ..., encryptedData: _Optional[str] = ..., keyType: _Optional[str] = ..., visibleBelow: bool = ..., newUserInherit: bool = ..., roleType: _Optional[str] = ...) -> None: ... + def __init__(self, roleId: _Optional[int] = ..., nodeId: _Optional[int] = ..., encryptedData: _Optional[str] = ..., keyType: _Optional[str] = ..., visibleBelow: _Optional[bool] = ..., newUserInherit: _Optional[bool] = ..., roleType: _Optional[str] = ...) -> None: ... class User(_message.Message): __slots__ = ("enterpriseUserId", "nodeId", "encryptedData", "keyType", "username", "status", "lock", "userId", "accountShareExpiration", "fullName", "jobTitle", "tfaEnabled", "transferAcceptanceStatus") @@ -743,7 +760,7 @@ class User(_message.Message): jobTitle: str tfaEnabled: bool transferAcceptanceStatus: TransferAcceptanceStatus - def __init__(self, enterpriseUserId: _Optional[int] = ..., nodeId: _Optional[int] = ..., encryptedData: _Optional[str] = ..., keyType: _Optional[str] = ..., username: _Optional[str] = ..., status: _Optional[str] = ..., lock: _Optional[int] = ..., userId: _Optional[int] = ..., accountShareExpiration: _Optional[int] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., tfaEnabled: bool = ..., transferAcceptanceStatus: _Optional[_Union[TransferAcceptanceStatus, str]] = ...) -> None: ... + def __init__(self, enterpriseUserId: _Optional[int] = ..., nodeId: _Optional[int] = ..., encryptedData: _Optional[str] = ..., keyType: _Optional[str] = ..., username: _Optional[str] = ..., status: _Optional[str] = ..., lock: _Optional[int] = ..., userId: _Optional[int] = ..., accountShareExpiration: _Optional[int] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., tfaEnabled: _Optional[bool] = ..., transferAcceptanceStatus: _Optional[_Union[TransferAcceptanceStatus, str]] = ...) -> None: ... class UserAlias(_message.Message): __slots__ = ("enterpriseUserId", "username") @@ -779,7 +796,7 @@ class ManagedNode(_message.Message): roleId: int managedNodeId: int cascadeNodeManagement: bool - def __init__(self, roleId: _Optional[int] = ..., managedNodeId: _Optional[int] = ..., cascadeNodeManagement: bool = ...) -> None: ... + def __init__(self, roleId: _Optional[int] = ..., managedNodeId: _Optional[int] = ..., cascadeNodeManagement: _Optional[bool] = ...) -> None: ... class UserManagedNode(_message.Message): __slots__ = ("nodeId", "cascadeNodeManagement", "privileges") @@ -789,7 +806,7 @@ class UserManagedNode(_message.Message): nodeId: int cascadeNodeManagement: bool privileges: _containers.RepeatedScalarFieldContainer[str] - def __init__(self, nodeId: _Optional[int] = ..., cascadeNodeManagement: bool = ..., privileges: _Optional[_Iterable[str]] = ...) -> None: ... + def __init__(self, nodeId: _Optional[int] = ..., cascadeNodeManagement: _Optional[bool] = ..., privileges: _Optional[_Iterable[str]] = ...) -> None: ... class UserPrivilege(_message.Message): __slots__ = ("userManagedNodes", "enterpriseUserId", "encryptedData") @@ -857,7 +874,7 @@ class Team(_message.Message): restrictView: bool encryptedData: str encryptedTeamKey: str - def __init__(self, teamUid: _Optional[bytes] = ..., name: _Optional[str] = ..., nodeId: _Optional[int] = ..., restrictEdit: bool = ..., restrictShare: bool = ..., restrictView: bool = ..., encryptedData: _Optional[str] = ..., encryptedTeamKey: _Optional[str] = ...) -> None: ... + def __init__(self, teamUid: _Optional[bytes] = ..., name: _Optional[str] = ..., nodeId: _Optional[int] = ..., restrictEdit: _Optional[bool] = ..., restrictShare: _Optional[bool] = ..., restrictView: _Optional[bool] = ..., encryptedData: _Optional[str] = ..., encryptedTeamKey: _Optional[str] = ...) -> None: ... class TeamUser(_message.Message): __slots__ = ("teamUid", "enterpriseUserId", "userType") @@ -903,7 +920,7 @@ class MspInfo(_message.Message): managedCompanies: _containers.RepeatedCompositeFieldContainer[ManagedCompany] allowUnlimitedLicenses: bool addOns: _containers.RepeatedCompositeFieldContainer[LicenseAddOn] - def __init__(self, enterpriseId: _Optional[int] = ..., enterpriseName: _Optional[str] = ..., allocatedLicenses: _Optional[int] = ..., allowedMcProducts: _Optional[_Iterable[str]] = ..., allowedAddOns: _Optional[_Iterable[str]] = ..., maxFilePlanType: _Optional[str] = ..., managedCompanies: _Optional[_Iterable[_Union[ManagedCompany, _Mapping]]] = ..., allowUnlimitedLicenses: bool = ..., addOns: _Optional[_Iterable[_Union[LicenseAddOn, _Mapping]]] = ...) -> None: ... + def __init__(self, enterpriseId: _Optional[int] = ..., enterpriseName: _Optional[str] = ..., allocatedLicenses: _Optional[int] = ..., allowedMcProducts: _Optional[_Iterable[str]] = ..., allowedAddOns: _Optional[_Iterable[str]] = ..., maxFilePlanType: _Optional[str] = ..., managedCompanies: _Optional[_Iterable[_Union[ManagedCompany, _Mapping]]] = ..., allowUnlimitedLicenses: _Optional[bool] = ..., addOns: _Optional[_Iterable[_Union[LicenseAddOn, _Mapping]]] = ...) -> None: ... class ManagedCompany(_message.Message): __slots__ = ("mcEnterpriseId", "mcEnterpriseName", "mspNodeId", "numberOfSeats", "numberOfUsers", "productId", "isExpired", "treeKey", "tree_key_role", "filePlanType", "addOns", "treeKeyTypeId") @@ -931,7 +948,7 @@ class ManagedCompany(_message.Message): filePlanType: str addOns: _containers.RepeatedCompositeFieldContainer[LicenseAddOn] treeKeyTypeId: int - def __init__(self, mcEnterpriseId: _Optional[int] = ..., mcEnterpriseName: _Optional[str] = ..., mspNodeId: _Optional[int] = ..., numberOfSeats: _Optional[int] = ..., numberOfUsers: _Optional[int] = ..., productId: _Optional[str] = ..., isExpired: bool = ..., treeKey: _Optional[str] = ..., tree_key_role: _Optional[int] = ..., filePlanType: _Optional[str] = ..., addOns: _Optional[_Iterable[_Union[LicenseAddOn, _Mapping]]] = ..., treeKeyTypeId: _Optional[int] = ...) -> None: ... + def __init__(self, mcEnterpriseId: _Optional[int] = ..., mcEnterpriseName: _Optional[str] = ..., mspNodeId: _Optional[int] = ..., numberOfSeats: _Optional[int] = ..., numberOfUsers: _Optional[int] = ..., productId: _Optional[str] = ..., isExpired: _Optional[bool] = ..., treeKey: _Optional[str] = ..., tree_key_role: _Optional[int] = ..., filePlanType: _Optional[str] = ..., addOns: _Optional[_Iterable[_Union[LicenseAddOn, _Mapping]]] = ..., treeKeyTypeId: _Optional[int] = ...) -> None: ... class MSPPool(_message.Message): __slots__ = ("productId", "seats", "availableSeats", "stash") @@ -979,7 +996,7 @@ class LicenseAddOn(_message.Message): tierDescription: str seatsAllocated: int nhiTierAddOnId: int - def __init__(self, name: _Optional[str] = ..., enabled: bool = ..., isTrial: bool = ..., expiration: _Optional[int] = ..., created: _Optional[int] = ..., seats: _Optional[int] = ..., activationTime: _Optional[int] = ..., includedInProduct: bool = ..., apiCallCount: _Optional[int] = ..., tierDescription: _Optional[str] = ..., seatsAllocated: _Optional[int] = ..., nhiTierAddOnId: _Optional[int] = ...) -> None: ... + def __init__(self, name: _Optional[str] = ..., enabled: _Optional[bool] = ..., isTrial: _Optional[bool] = ..., expiration: _Optional[int] = ..., created: _Optional[int] = ..., seats: _Optional[int] = ..., activationTime: _Optional[int] = ..., includedInProduct: _Optional[bool] = ..., apiCallCount: _Optional[int] = ..., tierDescription: _Optional[str] = ..., seatsAllocated: _Optional[int] = ..., nhiTierAddOnId: _Optional[int] = ...) -> None: ... class MCDefault(_message.Message): __slots__ = ("mcProduct", "addOns", "filePlanType", "maxLicenses", "fixedMaxLicenses") @@ -993,7 +1010,7 @@ class MCDefault(_message.Message): filePlanType: str maxLicenses: int fixedMaxLicenses: bool - def __init__(self, mcProduct: _Optional[str] = ..., addOns: _Optional[_Iterable[str]] = ..., filePlanType: _Optional[str] = ..., maxLicenses: _Optional[int] = ..., fixedMaxLicenses: bool = ...) -> None: ... + def __init__(self, mcProduct: _Optional[str] = ..., addOns: _Optional[_Iterable[str]] = ..., filePlanType: _Optional[str] = ..., maxLicenses: _Optional[int] = ..., fixedMaxLicenses: _Optional[bool] = ...) -> None: ... class MSPPermits(_message.Message): __slots__ = ("restricted", "maxAllowedLicenses", "allowedMcProducts", "allowedAddOns", "maxFilePlanType", "allowUnlimitedLicenses", "mcDefaults") @@ -1011,7 +1028,7 @@ class MSPPermits(_message.Message): maxFilePlanType: str allowUnlimitedLicenses: bool mcDefaults: _containers.RepeatedCompositeFieldContainer[MCDefault] - def __init__(self, restricted: bool = ..., maxAllowedLicenses: _Optional[int] = ..., allowedMcProducts: _Optional[_Iterable[str]] = ..., allowedAddOns: _Optional[_Iterable[str]] = ..., maxFilePlanType: _Optional[str] = ..., allowUnlimitedLicenses: bool = ..., mcDefaults: _Optional[_Iterable[_Union[MCDefault, _Mapping]]] = ...) -> None: ... + def __init__(self, restricted: _Optional[bool] = ..., maxAllowedLicenses: _Optional[int] = ..., allowedMcProducts: _Optional[_Iterable[str]] = ..., allowedAddOns: _Optional[_Iterable[str]] = ..., maxFilePlanType: _Optional[str] = ..., allowUnlimitedLicenses: _Optional[bool] = ..., mcDefaults: _Optional[_Iterable[_Union[MCDefault, _Mapping]]] = ...) -> None: ... class License(_message.Message): __slots__ = ("paid", "numberOfSeats", "expiration", "licenseKeyId", "productTypeId", "name", "enterpriseLicenseId", "seatsAllocated", "seatsPending", "tier", "filePlanTypeId", "maxBytes", "storageExpiration", "licenseStatus", "mspPool", "managedBy", "addOns", "nextBillingDate", "hasMSPLegacyLog", "mspPermits", "distributor") @@ -1057,7 +1074,7 @@ class License(_message.Message): hasMSPLegacyLog: bool mspPermits: MSPPermits distributor: bool - def __init__(self, paid: bool = ..., numberOfSeats: _Optional[int] = ..., expiration: _Optional[int] = ..., licenseKeyId: _Optional[int] = ..., productTypeId: _Optional[int] = ..., name: _Optional[str] = ..., enterpriseLicenseId: _Optional[int] = ..., seatsAllocated: _Optional[int] = ..., seatsPending: _Optional[int] = ..., tier: _Optional[int] = ..., filePlanTypeId: _Optional[int] = ..., maxBytes: _Optional[int] = ..., storageExpiration: _Optional[int] = ..., licenseStatus: _Optional[str] = ..., mspPool: _Optional[_Iterable[_Union[MSPPool, _Mapping]]] = ..., managedBy: _Optional[_Union[MSPContact, _Mapping]] = ..., addOns: _Optional[_Iterable[_Union[LicenseAddOn, _Mapping]]] = ..., nextBillingDate: _Optional[int] = ..., hasMSPLegacyLog: bool = ..., mspPermits: _Optional[_Union[MSPPermits, _Mapping]] = ..., distributor: bool = ...) -> None: ... + def __init__(self, paid: _Optional[bool] = ..., numberOfSeats: _Optional[int] = ..., expiration: _Optional[int] = ..., licenseKeyId: _Optional[int] = ..., productTypeId: _Optional[int] = ..., name: _Optional[str] = ..., enterpriseLicenseId: _Optional[int] = ..., seatsAllocated: _Optional[int] = ..., seatsPending: _Optional[int] = ..., tier: _Optional[int] = ..., filePlanTypeId: _Optional[int] = ..., maxBytes: _Optional[int] = ..., storageExpiration: _Optional[int] = ..., licenseStatus: _Optional[str] = ..., mspPool: _Optional[_Iterable[_Union[MSPPool, _Mapping]]] = ..., managedBy: _Optional[_Union[MSPContact, _Mapping]] = ..., addOns: _Optional[_Iterable[_Union[LicenseAddOn, _Mapping]]] = ..., nextBillingDate: _Optional[int] = ..., hasMSPLegacyLog: _Optional[bool] = ..., mspPermits: _Optional[_Union[MSPPermits, _Mapping]] = ..., distributor: _Optional[bool] = ...) -> None: ... class Bridge(_message.Message): __slots__ = ("bridgeId", "nodeId", "wanIpEnforcement", "lanIpEnforcement", "status") @@ -1087,7 +1104,7 @@ class Scim(_message.Message): lastSynced: int rolePrefix: str uniqueGroups: bool - def __init__(self, scimId: _Optional[int] = ..., nodeId: _Optional[int] = ..., status: _Optional[str] = ..., lastSynced: _Optional[int] = ..., rolePrefix: _Optional[str] = ..., uniqueGroups: bool = ...) -> None: ... + def __init__(self, scimId: _Optional[int] = ..., nodeId: _Optional[int] = ..., status: _Optional[str] = ..., lastSynced: _Optional[int] = ..., rolePrefix: _Optional[str] = ..., uniqueGroups: _Optional[bool] = ...) -> None: ... class EmailProvision(_message.Message): __slots__ = ("id", "nodeId", "domain", "method") @@ -1159,7 +1176,7 @@ class SsoService(_message.Message): inviteNewUsers: bool active: bool isCloud: bool - def __init__(self, ssoServiceProviderId: _Optional[int] = ..., nodeId: _Optional[int] = ..., name: _Optional[str] = ..., sp_url: _Optional[str] = ..., inviteNewUsers: bool = ..., active: bool = ..., isCloud: bool = ...) -> None: ... + def __init__(self, ssoServiceProviderId: _Optional[int] = ..., nodeId: _Optional[int] = ..., name: _Optional[str] = ..., sp_url: _Optional[str] = ..., inviteNewUsers: _Optional[bool] = ..., active: _Optional[bool] = ..., isCloud: _Optional[bool] = ...) -> None: ... class ReportFilterUser(_message.Message): __slots__ = ("userId", "email") @@ -1205,7 +1222,7 @@ class EnterpriseData(_message.Message): entity: EnterpriseDataEntity delete: bool data: _containers.RepeatedScalarFieldContainer[bytes] - def __init__(self, entity: _Optional[_Union[EnterpriseDataEntity, str]] = ..., delete: bool = ..., data: _Optional[_Iterable[bytes]] = ...) -> None: ... + def __init__(self, entity: _Optional[_Union[EnterpriseDataEntity, str]] = ..., delete: _Optional[bool] = ..., data: _Optional[_Iterable[bytes]] = ...) -> None: ... class EnterpriseDataResponse(_message.Message): __slots__ = ("continuationToken", "hasMore", "cacheStatus", "data", "generalData") @@ -1219,7 +1236,7 @@ class EnterpriseDataResponse(_message.Message): cacheStatus: CacheStatus data: _containers.RepeatedCompositeFieldContainer[EnterpriseData] generalData: GeneralDataEntity - def __init__(self, continuationToken: _Optional[bytes] = ..., hasMore: bool = ..., cacheStatus: _Optional[_Union[CacheStatus, str]] = ..., data: _Optional[_Iterable[_Union[EnterpriseData, _Mapping]]] = ..., generalData: _Optional[_Union[GeneralDataEntity, _Mapping]] = ...) -> None: ... + def __init__(self, continuationToken: _Optional[bytes] = ..., hasMore: _Optional[bool] = ..., cacheStatus: _Optional[_Union[CacheStatus, str]] = ..., data: _Optional[_Iterable[_Union[EnterpriseData, _Mapping]]] = ..., generalData: _Optional[_Union[GeneralDataEntity, _Mapping]] = ...) -> None: ... class BackupRequest(_message.Message): __slots__ = ("continuationToken",) @@ -1383,7 +1400,7 @@ class SharedRecordEvent(_message.Message): canEdit: bool canReshare: bool shareFrom: int - def __init__(self, recordUid: _Optional[bytes] = ..., userName: _Optional[str] = ..., canEdit: bool = ..., canReshare: bool = ..., shareFrom: _Optional[int] = ...) -> None: ... + def __init__(self, recordUid: _Optional[bytes] = ..., userName: _Optional[str] = ..., canEdit: _Optional[bool] = ..., canReshare: _Optional[bool] = ..., shareFrom: _Optional[int] = ...) -> None: ... class SetRestrictVisibilityRequest(_message.Message): __slots__ = ("nodeId",) @@ -1409,7 +1426,7 @@ class UserAddRequest(_message.Message): jobTitle: str email: str suppressEmailInvite: bool - def __init__(self, enterpriseUserId: _Optional[int] = ..., nodeId: _Optional[int] = ..., encryptedData: _Optional[bytes] = ..., keyType: _Optional[_Union[EncryptedKeyType, str]] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., email: _Optional[str] = ..., suppressEmailInvite: bool = ...) -> None: ... + def __init__(self, enterpriseUserId: _Optional[int] = ..., nodeId: _Optional[int] = ..., encryptedData: _Optional[bytes] = ..., keyType: _Optional[_Union[EncryptedKeyType, str]] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., email: _Optional[str] = ..., suppressEmailInvite: _Optional[bool] = ...) -> None: ... class UserUpdateRequest(_message.Message): __slots__ = ("users",) @@ -1418,7 +1435,7 @@ class UserUpdateRequest(_message.Message): def __init__(self, users: _Optional[_Iterable[_Union[UserUpdate, _Mapping]]] = ...) -> None: ... class UserUpdate(_message.Message): - __slots__ = ("enterpriseUserId", "nodeId", "encryptedData", "keyType", "fullName", "jobTitle", "email") + __slots__ = ("enterpriseUserId", "nodeId", "encryptedData", "keyType", "fullName", "jobTitle", "email", "inviteeLocale", "encryptedDataString") ENTERPRISEUSERID_FIELD_NUMBER: _ClassVar[int] NODEID_FIELD_NUMBER: _ClassVar[int] ENCRYPTEDDATA_FIELD_NUMBER: _ClassVar[int] @@ -1426,6 +1443,8 @@ class UserUpdate(_message.Message): FULLNAME_FIELD_NUMBER: _ClassVar[int] JOBTITLE_FIELD_NUMBER: _ClassVar[int] EMAIL_FIELD_NUMBER: _ClassVar[int] + INVITEELOCALE_FIELD_NUMBER: _ClassVar[int] + ENCRYPTEDDATASTRING_FIELD_NUMBER: _ClassVar[int] enterpriseUserId: int nodeId: int encryptedData: bytes @@ -1433,7 +1452,9 @@ class UserUpdate(_message.Message): fullName: str jobTitle: str email: str - def __init__(self, enterpriseUserId: _Optional[int] = ..., nodeId: _Optional[int] = ..., encryptedData: _Optional[bytes] = ..., keyType: _Optional[_Union[EncryptedKeyType, str]] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., email: _Optional[str] = ...) -> None: ... + inviteeLocale: str + encryptedDataString: str + def __init__(self, enterpriseUserId: _Optional[int] = ..., nodeId: _Optional[int] = ..., encryptedData: _Optional[bytes] = ..., keyType: _Optional[_Union[EncryptedKeyType, str]] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., email: _Optional[str] = ..., inviteeLocale: _Optional[str] = ..., encryptedDataString: _Optional[str] = ...) -> None: ... class UserUpdateResponse(_message.Message): __slots__ = ("users",) @@ -1442,12 +1463,16 @@ class UserUpdateResponse(_message.Message): def __init__(self, users: _Optional[_Iterable[_Union[UserUpdateResult, _Mapping]]] = ...) -> None: ... class UserUpdateResult(_message.Message): - __slots__ = ("enterpriseUserId", "status") + __slots__ = ("enterpriseUserId", "status", "errorMessage", "additionalInfo") ENTERPRISEUSERID_FIELD_NUMBER: _ClassVar[int] STATUS_FIELD_NUMBER: _ClassVar[int] + ERRORMESSAGE_FIELD_NUMBER: _ClassVar[int] + ADDITIONALINFO_FIELD_NUMBER: _ClassVar[int] enterpriseUserId: int status: UserUpdateStatus - def __init__(self, enterpriseUserId: _Optional[int] = ..., status: _Optional[_Union[UserUpdateStatus, str]] = ...) -> None: ... + errorMessage: str + additionalInfo: str + def __init__(self, enterpriseUserId: _Optional[int] = ..., status: _Optional[_Union[UserUpdateStatus, str]] = ..., errorMessage: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... class ComplianceRecordOwnersRequest(_message.Message): __slots__ = ("nodeIds", "includeNonShared") @@ -1455,7 +1480,7 @@ class ComplianceRecordOwnersRequest(_message.Message): INCLUDENONSHARED_FIELD_NUMBER: _ClassVar[int] nodeIds: _containers.RepeatedScalarFieldContainer[int] includeNonShared: bool - def __init__(self, nodeIds: _Optional[_Iterable[int]] = ..., includeNonShared: bool = ...) -> None: ... + def __init__(self, nodeIds: _Optional[_Iterable[int]] = ..., includeNonShared: _Optional[bool] = ...) -> None: ... class ComplianceRecordOwnersResponse(_message.Message): __slots__ = ("recordOwners",) @@ -1469,7 +1494,7 @@ class RecordOwner(_message.Message): SHARED_FIELD_NUMBER: _ClassVar[int] enterpriseUserId: int shared: bool - def __init__(self, enterpriseUserId: _Optional[int] = ..., shared: bool = ...) -> None: ... + def __init__(self, enterpriseUserId: _Optional[int] = ..., shared: _Optional[bool] = ...) -> None: ... class PreliminaryComplianceDataRequest(_message.Message): __slots__ = ("enterpriseUserIds", "includeNonShared", "continuationToken", "includeTotalMatchingRecordsInFirstResponse") @@ -1481,7 +1506,7 @@ class PreliminaryComplianceDataRequest(_message.Message): includeNonShared: bool continuationToken: bytes includeTotalMatchingRecordsInFirstResponse: bool - def __init__(self, enterpriseUserIds: _Optional[_Iterable[int]] = ..., includeNonShared: bool = ..., continuationToken: _Optional[bytes] = ..., includeTotalMatchingRecordsInFirstResponse: bool = ...) -> None: ... + def __init__(self, enterpriseUserIds: _Optional[_Iterable[int]] = ..., includeNonShared: _Optional[bool] = ..., continuationToken: _Optional[bytes] = ..., includeTotalMatchingRecordsInFirstResponse: _Optional[bool] = ...) -> None: ... class PreliminaryComplianceDataResponse(_message.Message): __slots__ = ("auditUserData", "continuationToken", "hasMore", "totalMatchingRecords") @@ -1493,17 +1518,19 @@ class PreliminaryComplianceDataResponse(_message.Message): continuationToken: bytes hasMore: bool totalMatchingRecords: int - def __init__(self, auditUserData: _Optional[_Iterable[_Union[AuditUserData, _Mapping]]] = ..., continuationToken: _Optional[bytes] = ..., hasMore: bool = ..., totalMatchingRecords: _Optional[int] = ...) -> None: ... + def __init__(self, auditUserData: _Optional[_Iterable[_Union[AuditUserData, _Mapping]]] = ..., continuationToken: _Optional[bytes] = ..., hasMore: _Optional[bool] = ..., totalMatchingRecords: _Optional[int] = ...) -> None: ... class AuditUserRecord(_message.Message): - __slots__ = ("recordUid", "encryptedData", "shared") + __slots__ = ("recordUid", "encryptedData", "shared", "isDriveRecord") RECORDUID_FIELD_NUMBER: _ClassVar[int] ENCRYPTEDDATA_FIELD_NUMBER: _ClassVar[int] SHARED_FIELD_NUMBER: _ClassVar[int] + ISDRIVERECORD_FIELD_NUMBER: _ClassVar[int] recordUid: bytes encryptedData: bytes shared: bool - def __init__(self, recordUid: _Optional[bytes] = ..., encryptedData: _Optional[bytes] = ..., shared: bool = ...) -> None: ... + isDriveRecord: bool + def __init__(self, recordUid: _Optional[bytes] = ..., encryptedData: _Optional[bytes] = ..., shared: _Optional[bool] = ..., isDriveRecord: _Optional[bool] = ...) -> None: ... class AuditUserData(_message.Message): __slots__ = ("enterpriseUserId", "auditUserRecords", "status") @@ -1537,7 +1564,7 @@ class ComplianceReportRequest(_message.Message): complianceReportRun: ComplianceReportRun reportName: str saveReport: bool - def __init__(self, complianceReportRun: _Optional[_Union[ComplianceReportRun, _Mapping]] = ..., reportName: _Optional[str] = ..., saveReport: bool = ...) -> None: ... + def __init__(self, complianceReportRun: _Optional[_Union[ComplianceReportRun, _Mapping]] = ..., reportName: _Optional[str] = ..., saveReport: _Optional[bool] = ...) -> None: ... class ComplianceReportRun(_message.Message): __slots__ = ("reportCriteriaAndFilter", "users", "records") @@ -1575,7 +1602,7 @@ class ComplianceReportCriteria(_message.Message): jobTitles: _containers.RepeatedScalarFieldContainer[str] enterpriseUserIds: _containers.RepeatedScalarFieldContainer[int] includeNonShared: bool - def __init__(self, jobTitles: _Optional[_Iterable[str]] = ..., enterpriseUserIds: _Optional[_Iterable[int]] = ..., includeNonShared: bool = ...) -> None: ... + def __init__(self, jobTitles: _Optional[_Iterable[str]] = ..., enterpriseUserIds: _Optional[_Iterable[int]] = ..., includeNonShared: _Optional[bool] = ...) -> None: ... class ComplianceReportFilter(_message.Message): __slots__ = ("recordTitles", "recordUids", "jobTitles", "urls", "recordTypes") @@ -1626,20 +1653,22 @@ class ComplianceReportResponse(_message.Message): def __init__(self, dateGenerated: _Optional[int] = ..., runByUserName: _Optional[str] = ..., reportName: _Optional[str] = ..., reportUid: _Optional[bytes] = ..., complianceReportRun: _Optional[_Union[ComplianceReportRun, _Mapping]] = ..., userProfiles: _Optional[_Iterable[_Union[UserProfile, _Mapping]]] = ..., auditTeams: _Optional[_Iterable[_Union[AuditTeam, _Mapping]]] = ..., auditRecords: _Optional[_Iterable[_Union[AuditRecord, _Mapping]]] = ..., userRecords: _Optional[_Iterable[_Union[UserRecord, _Mapping]]] = ..., sharedFolderRecords: _Optional[_Iterable[_Union[SharedFolderRecord, _Mapping]]] = ..., sharedFolderUsers: _Optional[_Iterable[_Union[SharedFolderUser, _Mapping]]] = ..., sharedFolderTeams: _Optional[_Iterable[_Union[SharedFolderTeam, _Mapping]]] = ..., auditTeamUsers: _Optional[_Iterable[_Union[AuditTeamUser, _Mapping]]] = ..., auditRoles: _Optional[_Iterable[_Union[AuditRole, _Mapping]]] = ..., linkedRecords: _Optional[_Iterable[_Union[LinkedRecord, _Mapping]]] = ...) -> None: ... class AuditRecord(_message.Message): - __slots__ = ("recordUid", "auditData", "hasAttachments", "inTrash", "treeLeft", "treeRight") + __slots__ = ("recordUid", "auditData", "hasAttachments", "inTrash", "treeLeft", "treeRight", "isDriveRecord") RECORDUID_FIELD_NUMBER: _ClassVar[int] AUDITDATA_FIELD_NUMBER: _ClassVar[int] HASATTACHMENTS_FIELD_NUMBER: _ClassVar[int] INTRASH_FIELD_NUMBER: _ClassVar[int] TREELEFT_FIELD_NUMBER: _ClassVar[int] TREERIGHT_FIELD_NUMBER: _ClassVar[int] + ISDRIVERECORD_FIELD_NUMBER: _ClassVar[int] recordUid: bytes auditData: bytes hasAttachments: bool inTrash: bool treeLeft: int treeRight: int - def __init__(self, recordUid: _Optional[bytes] = ..., auditData: _Optional[bytes] = ..., hasAttachments: bool = ..., inTrash: bool = ..., treeLeft: _Optional[int] = ..., treeRight: _Optional[int] = ...) -> None: ... + isDriveRecord: bool + def __init__(self, recordUid: _Optional[bytes] = ..., auditData: _Optional[bytes] = ..., hasAttachments: _Optional[bool] = ..., inTrash: _Optional[bool] = ..., treeLeft: _Optional[int] = ..., treeRight: _Optional[int] = ..., isDriveRecord: _Optional[bool] = ...) -> None: ... class AuditRole(_message.Message): __slots__ = ("roleId", "encryptedData", "restrictShareOutsideEnterprise", "restrictShareAll", "restrictShareOfAttachments", "restrictMaskPasswordsWhileEditing", "roleNodeManagements") @@ -1657,7 +1686,7 @@ class AuditRole(_message.Message): restrictShareOfAttachments: bool restrictMaskPasswordsWhileEditing: bool roleNodeManagements: _containers.RepeatedCompositeFieldContainer[RoleNodeManagement] - def __init__(self, roleId: _Optional[int] = ..., encryptedData: _Optional[bytes] = ..., restrictShareOutsideEnterprise: bool = ..., restrictShareAll: bool = ..., restrictShareOfAttachments: bool = ..., restrictMaskPasswordsWhileEditing: bool = ..., roleNodeManagements: _Optional[_Iterable[_Union[RoleNodeManagement, _Mapping]]] = ...) -> None: ... + def __init__(self, roleId: _Optional[int] = ..., encryptedData: _Optional[bytes] = ..., restrictShareOutsideEnterprise: _Optional[bool] = ..., restrictShareAll: _Optional[bool] = ..., restrictShareOfAttachments: _Optional[bool] = ..., restrictMaskPasswordsWhileEditing: _Optional[bool] = ..., roleNodeManagements: _Optional[_Iterable[_Union[RoleNodeManagement, _Mapping]]] = ...) -> None: ... class RoleNodeManagement(_message.Message): __slots__ = ("treeLeft", "treeRight", "cascade", "privileges") @@ -1669,7 +1698,7 @@ class RoleNodeManagement(_message.Message): treeRight: int cascade: bool privileges: int - def __init__(self, treeLeft: _Optional[int] = ..., treeRight: _Optional[int] = ..., cascade: bool = ..., privileges: _Optional[int] = ...) -> None: ... + def __init__(self, treeLeft: _Optional[int] = ..., treeRight: _Optional[int] = ..., cascade: _Optional[bool] = ..., privileges: _Optional[int] = ...) -> None: ... class UserProfile(_message.Message): __slots__ = ("enterpriseUserId", "fullName", "jobTitle", "email", "roleIds") @@ -1686,12 +1715,32 @@ class UserProfile(_message.Message): def __init__(self, enterpriseUserId: _Optional[int] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., email: _Optional[str] = ..., roleIds: _Optional[_Iterable[int]] = ...) -> None: ... class RecordPermission(_message.Message): - __slots__ = ("recordUid", "permissionBits") + __slots__ = ("recordUid", "permissionBits", "drive") RECORDUID_FIELD_NUMBER: _ClassVar[int] PERMISSIONBITS_FIELD_NUMBER: _ClassVar[int] + DRIVE_FIELD_NUMBER: _ClassVar[int] recordUid: bytes permissionBits: int - def __init__(self, recordUid: _Optional[bytes] = ..., permissionBits: _Optional[int] = ...) -> None: ... + drive: DrivePermission + def __init__(self, recordUid: _Optional[bytes] = ..., permissionBits: _Optional[int] = ..., drive: _Optional[_Union[DrivePermission, _Mapping]] = ...) -> None: ... + +class DrivePermission(_message.Message): + __slots__ = ("owner", "denied", "canEdit", "canShare", "isShareAdmin", "accessType", "folderPermissions") + OWNER_FIELD_NUMBER: _ClassVar[int] + DENIED_FIELD_NUMBER: _ClassVar[int] + CANEDIT_FIELD_NUMBER: _ClassVar[int] + CANSHARE_FIELD_NUMBER: _ClassVar[int] + ISSHAREADMIN_FIELD_NUMBER: _ClassVar[int] + ACCESSTYPE_FIELD_NUMBER: _ClassVar[int] + FOLDERPERMISSIONS_FIELD_NUMBER: _ClassVar[int] + owner: bool + denied: bool + canEdit: bool + canShare: bool + isShareAdmin: bool + accessType: _folder_pb2.AccessType + folderPermissions: _folder_pb2.FolderPermissions + def __init__(self, owner: _Optional[bool] = ..., denied: _Optional[bool] = ..., canEdit: _Optional[bool] = ..., canShare: _Optional[bool] = ..., isShareAdmin: _Optional[bool] = ..., accessType: _Optional[_Union[_folder_pb2.AccessType, str]] = ..., folderPermissions: _Optional[_Union[_folder_pb2.FolderPermissions, _Mapping]] = ...) -> None: ... class UserRecord(_message.Message): __slots__ = ("enterpriseUserId", "recordPermissions") @@ -1711,7 +1760,7 @@ class AuditTeam(_message.Message): teamName: str restrictEdit: bool restrictShare: bool - def __init__(self, teamUid: _Optional[bytes] = ..., teamName: _Optional[str] = ..., restrictEdit: bool = ..., restrictShare: bool = ...) -> None: ... + def __init__(self, teamUid: _Optional[bytes] = ..., teamName: _Optional[str] = ..., restrictEdit: _Optional[bool] = ..., restrictShare: _Optional[bool] = ...) -> None: ... class AuditTeamUser(_message.Message): __slots__ = ("teamUid", "enterpriseUserIds") @@ -1815,7 +1864,7 @@ class UserProfileExt(_message.Message): isShareAdminForRequestedObject: bool isShareAdminForSharedFolderOwner: bool hasAccessToObject: bool - def __init__(self, email: _Optional[str] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., isMSPMCAdmin: bool = ..., isInSharedFolder: bool = ..., isShareAdminForRequestedObject: bool = ..., isShareAdminForSharedFolderOwner: bool = ..., hasAccessToObject: bool = ...) -> None: ... + def __init__(self, email: _Optional[str] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., isMSPMCAdmin: _Optional[bool] = ..., isInSharedFolder: _Optional[bool] = ..., isShareAdminForRequestedObject: _Optional[bool] = ..., isShareAdminForSharedFolderOwner: _Optional[bool] = ..., hasAccessToObject: _Optional[bool] = ...) -> None: ... class GetSharingAdminsResponse(_message.Message): __slots__ = ("userProfileExts",) @@ -1879,7 +1928,7 @@ class TeamsEnterpriseUsersAddTeamResponse(_message.Message): message: str resultCode: str additionalInfo: str - def __init__(self, teamUid: _Optional[bytes] = ..., users: _Optional[_Iterable[_Union[TeamsEnterpriseUsersAddUserResponse, _Mapping]]] = ..., success: bool = ..., message: _Optional[str] = ..., resultCode: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... + def __init__(self, teamUid: _Optional[bytes] = ..., users: _Optional[_Iterable[_Union[TeamsEnterpriseUsersAddUserResponse, _Mapping]]] = ..., success: _Optional[bool] = ..., message: _Optional[str] = ..., resultCode: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... class TeamsEnterpriseUsersAddUserResponse(_message.Message): __slots__ = ("enterpriseUserId", "revision", "success", "message", "resultCode", "additionalInfo") @@ -1895,7 +1944,7 @@ class TeamsEnterpriseUsersAddUserResponse(_message.Message): message: str resultCode: str additionalInfo: str - def __init__(self, enterpriseUserId: _Optional[int] = ..., revision: _Optional[int] = ..., success: bool = ..., message: _Optional[str] = ..., resultCode: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... + def __init__(self, enterpriseUserId: _Optional[int] = ..., revision: _Optional[int] = ..., success: _Optional[bool] = ..., message: _Optional[str] = ..., resultCode: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... class TeamEnterpriseUserRemove(_message.Message): __slots__ = ("teamUid", "enterpriseUserId") @@ -1929,7 +1978,7 @@ class TeamEnterpriseUserRemoveResponse(_message.Message): resultCode: str message: str additionalInfo: str - def __init__(self, teamEnterpriseUserRemove: _Optional[_Union[TeamEnterpriseUserRemove, _Mapping]] = ..., success: bool = ..., resultCode: _Optional[str] = ..., message: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... + def __init__(self, teamEnterpriseUserRemove: _Optional[_Union[TeamEnterpriseUserRemove, _Mapping]] = ..., success: _Optional[bool] = ..., resultCode: _Optional[str] = ..., message: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... class DomainAlias(_message.Message): __slots__ = ("domain", "alias", "status", "message") @@ -2049,7 +2098,7 @@ class EnterpriseUsersAdd(_message.Message): inviteeLocale: str move: bool roleId: int - def __init__(self, enterpriseUserId: _Optional[int] = ..., username: _Optional[str] = ..., nodeId: _Optional[int] = ..., encryptedData: _Optional[str] = ..., keyType: _Optional[_Union[EncryptedKeyType, str]] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., suppressEmailInvite: bool = ..., inviteeLocale: _Optional[str] = ..., move: bool = ..., roleId: _Optional[int] = ...) -> None: ... + def __init__(self, enterpriseUserId: _Optional[int] = ..., username: _Optional[str] = ..., nodeId: _Optional[int] = ..., encryptedData: _Optional[str] = ..., keyType: _Optional[_Union[EncryptedKeyType, str]] = ..., fullName: _Optional[str] = ..., jobTitle: _Optional[str] = ..., suppressEmailInvite: _Optional[bool] = ..., inviteeLocale: _Optional[str] = ..., move: _Optional[bool] = ..., roleId: _Optional[int] = ...) -> None: ... class EnterpriseUsersAddResponse(_message.Message): __slots__ = ("results", "success", "code", "message", "additionalInfo") @@ -2063,7 +2112,7 @@ class EnterpriseUsersAddResponse(_message.Message): code: str message: str additionalInfo: str - def __init__(self, results: _Optional[_Iterable[_Union[EnterpriseUsersAddResult, _Mapping]]] = ..., success: bool = ..., code: _Optional[str] = ..., message: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... + def __init__(self, results: _Optional[_Iterable[_Union[EnterpriseUsersAddResult, _Mapping]]] = ..., success: _Optional[bool] = ..., code: _Optional[str] = ..., message: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... class EnterpriseUsersAddResult(_message.Message): __slots__ = ("enterpriseUserId", "success", "verificationCode", "code", "message", "additionalInfo") @@ -2079,7 +2128,7 @@ class EnterpriseUsersAddResult(_message.Message): code: str message: str additionalInfo: str - def __init__(self, enterpriseUserId: _Optional[int] = ..., success: bool = ..., verificationCode: _Optional[str] = ..., code: _Optional[str] = ..., message: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... + def __init__(self, enterpriseUserId: _Optional[int] = ..., success: _Optional[bool] = ..., verificationCode: _Optional[str] = ..., code: _Optional[str] = ..., message: _Optional[str] = ..., additionalInfo: _Optional[str] = ...) -> None: ... class UpdateMSPPermitsRequest(_message.Message): __slots__ = ("mspEnterpriseId", "maxAllowedLicenses", "allowedMcProducts", "allowedAddOns", "maxFilePlanType", "allowUnlimitedLicenses") @@ -2095,7 +2144,7 @@ class UpdateMSPPermitsRequest(_message.Message): allowedAddOns: _containers.RepeatedScalarFieldContainer[str] maxFilePlanType: str allowUnlimitedLicenses: bool - def __init__(self, mspEnterpriseId: _Optional[int] = ..., maxAllowedLicenses: _Optional[int] = ..., allowedMcProducts: _Optional[_Iterable[str]] = ..., allowedAddOns: _Optional[_Iterable[str]] = ..., maxFilePlanType: _Optional[str] = ..., allowUnlimitedLicenses: bool = ...) -> None: ... + def __init__(self, mspEnterpriseId: _Optional[int] = ..., maxAllowedLicenses: _Optional[int] = ..., allowedMcProducts: _Optional[_Iterable[str]] = ..., allowedAddOns: _Optional[_Iterable[str]] = ..., maxFilePlanType: _Optional[str] = ..., allowUnlimitedLicenses: _Optional[bool] = ...) -> None: ... class DeleteEnterpriseUsersRequest(_message.Message): __slots__ = ("enterpriseUserIds",) @@ -2125,7 +2174,7 @@ class ClearSecurityDataRequest(_message.Message): enterpriseUserId: _containers.RepeatedScalarFieldContainer[int] allUsers: bool type: ClearSecurityDataType - def __init__(self, enterpriseUserId: _Optional[_Iterable[int]] = ..., allUsers: bool = ..., type: _Optional[_Union[ClearSecurityDataType, str]] = ...) -> None: ... + def __init__(self, enterpriseUserId: _Optional[_Iterable[int]] = ..., allUsers: _Optional[bool] = ..., type: _Optional[_Union[ClearSecurityDataType, str]] = ...) -> None: ... class ListDomainsResponse(_message.Message): __slots__ = ("domain",) @@ -2165,7 +2214,7 @@ class LockUsersRequest(_message.Message): disableEnterpriseUserIds: _containers.RepeatedScalarFieldContainer[int] unlockEnterpriseUserIds: _containers.RepeatedScalarFieldContainer[int] deleteIfPending: bool - def __init__(self, lockEnterpriseUserIds: _Optional[_Iterable[int]] = ..., disableEnterpriseUserIds: _Optional[_Iterable[int]] = ..., unlockEnterpriseUserIds: _Optional[_Iterable[int]] = ..., deleteIfPending: bool = ...) -> None: ... + def __init__(self, lockEnterpriseUserIds: _Optional[_Iterable[int]] = ..., disableEnterpriseUserIds: _Optional[_Iterable[int]] = ..., unlockEnterpriseUserIds: _Optional[_Iterable[int]] = ..., deleteIfPending: _Optional[bool] = ...) -> None: ... class LockUsersResponse(_message.Message): __slots__ = ("response",) diff --git a/keepercommander/proto/folder_access_pb2.pyi b/keepercommander/proto/folder_access_pb2.pyi index 9e2e82bbf..6e93d97bc 100644 --- a/keepercommander/proto/folder_access_pb2.pyi +++ b/keepercommander/proto/folder_access_pb2.pyi @@ -25,7 +25,7 @@ class GetFolderAccessResponse(_message.Message): folderAccessResults: _containers.RepeatedCompositeFieldContainer[GetFolderAccessResult] continuationToken: ContinuationToken hasMore: bool - def __init__(self, folderAccessResults: _Optional[_Iterable[_Union[GetFolderAccessResult, _Mapping]]] = ..., continuationToken: _Optional[_Union[ContinuationToken, _Mapping]] = ..., hasMore: bool = ...) -> None: ... + def __init__(self, folderAccessResults: _Optional[_Iterable[_Union[GetFolderAccessResult, _Mapping]]] = ..., continuationToken: _Optional[_Union[ContinuationToken, _Mapping]] = ..., hasMore: _Optional[bool] = ...) -> None: ... class ContinuationToken(_message.Message): __slots__ = ("lastModified",) diff --git a/keepercommander/proto/folder_pb2.py b/keepercommander/proto/folder_pb2.py index d934a4354..935aed71a 100644 --- a/keepercommander/proto/folder_pb2.py +++ b/keepercommander/proto/folder_pb2.py @@ -26,7 +26,7 @@ from . import tla_pb2 as tla__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x66older.proto\x12\x06\x46older\x1a\x0crecord.proto\x1a\ttla.proto\"\\\n\x10\x45ncryptedDataKey\x12\x14\n\x0c\x65ncryptedKey\x18\x01 \x01(\x0c\x12\x32\n\x10\x65ncryptedKeyType\x18\x02 \x01(\x0e\x32\x18.Folder.EncryptedKeyType\"\x82\x01\n\x16SharedFolderRecordData\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x0e\n\x06userId\x18\x03 \x01(\x05\x12\x32\n\x10\x65ncryptedDataKey\x18\x04 \x03(\x0b\x32\x18.Folder.EncryptedDataKey\"\\\n\x1aSharedFolderRecordDataList\x12>\n\x16sharedFolderRecordData\x18\x01 \x03(\x0b\x32\x1e.Folder.SharedFolderRecordData\"_\n\x15SharedFolderRecordFix\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12 \n\x18\x65ncryptedRecordFolderKey\x18\x03 \x01(\x0c\"Y\n\x19SharedFolderRecordFixList\x12<\n\x15sharedFolderRecordFix\x18\x01 \x03(\x0b\x32\x1d.Folder.SharedFolderRecordFix\"\xa2\x02\n\rRecordRequest\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12&\n\nrecordType\x18\x02 \x01(\x0e\x32\x12.Folder.RecordType\x12\x12\n\nrecordData\x18\x03 \x01(\x0c\x12\x1a\n\x12\x65ncryptedRecordKey\x18\x04 \x01(\x0c\x12&\n\nfolderType\x18\x05 \x01(\x0e\x32\x12.Folder.FolderType\x12\x12\n\nhowLongAgo\x18\x06 \x01(\x03\x12\x11\n\tfolderUid\x18\x07 \x01(\x0c\x12 \n\x18\x65ncryptedRecordFolderKey\x18\x08 \x01(\x0c\x12\r\n\x05\x65xtra\x18\t \x01(\x0c\x12\x15\n\rnonSharedData\x18\n \x01(\x0c\x12\x0f\n\x07\x66ileIds\x18\x0b \x03(\x03\"E\n\x0eRecordResponse\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x10\n\x08revision\x18\x02 \x01(\x03\x12\x0e\n\x06status\x18\x03 \x01(\t\"\x80\x01\n\x12SharedFolderFields\x12\x1b\n\x13\x65ncryptedFolderName\x18\x01 \x01(\x0c\x12\x13\n\x0bmanageUsers\x18\x02 \x01(\x08\x12\x15\n\rmanageRecords\x18\x03 \x01(\x08\x12\x0f\n\x07\x63\x61nEdit\x18\x04 \x01(\x08\x12\x10\n\x08\x63\x61nShare\x18\x05 \x01(\x08\"3\n\x18SharedFolderFolderFields\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\"\x8f\x02\n\rFolderRequest\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12&\n\nfolderType\x18\x02 \x01(\x0e\x32\x12.Folder.FolderType\x12\x17\n\x0fparentFolderUid\x18\x03 \x01(\x0c\x12\x12\n\nfolderData\x18\x04 \x01(\x0c\x12\x1a\n\x12\x65ncryptedFolderKey\x18\x05 \x01(\x0c\x12\x36\n\x12sharedFolderFields\x18\x06 \x01(\x0b\x32\x1a.Folder.SharedFolderFields\x12\x42\n\x18sharedFolderFolderFields\x18\x07 \x01(\x0b\x32 .Folder.SharedFolderFolderFields\"E\n\x0e\x46olderResponse\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x10\n\x08revision\x18\x02 \x01(\x03\x12\x0e\n\x06status\x18\x03 \x01(\t\"w\n\x19ImportFolderRecordRequest\x12,\n\rfolderRequest\x18\x01 \x03(\x0b\x32\x15.Folder.FolderRequest\x12,\n\rrecordRequest\x18\x02 \x03(\x0b\x32\x15.Folder.RecordRequest\"|\n\x1aImportFolderRecordResponse\x12.\n\x0e\x66olderResponse\x18\x01 \x03(\x0b\x32\x16.Folder.FolderResponse\x12.\n\x0erecordResponse\x18\x02 \x03(\x0b\x32\x16.Folder.RecordResponse\"\xc9\x02\n\x18SharedFolderUpdateRecord\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x17\n\x0fsharedFolderUid\x18\x02 \x01(\x0c\x12\x0f\n\x07teamUid\x18\x03 \x01(\x0c\x12(\n\x07\x63\x61nEdit\x18\x04 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12)\n\x08\x63\x61nShare\x18\x05 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x1a\n\x12\x65ncryptedRecordKey\x18\x06 \x01(\x0c\x12\x10\n\x08revision\x18\x07 \x01(\x05\x12\x12\n\nexpiration\x18\x08 \x01(\x12\x12=\n\x15timerNotificationType\x18\t \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x1a\n\x12rotateOnExpiration\x18\n \x01(\x08\"\xcc\x02\n\x16SharedFolderUpdateUser\x12\x10\n\x08username\x18\x01 \x01(\t\x12,\n\x0bmanageUsers\x18\x02 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12.\n\rmanageRecords\x18\x03 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x1b\n\x0fsharedFolderKey\x18\x04 \x01(\x0c\x42\x02\x18\x01\x12\x12\n\nexpiration\x18\x05 \x01(\x12\x12=\n\x15timerNotificationType\x18\x06 \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x36\n\x14typedSharedFolderKey\x18\x07 \x01(\x0b\x32\x18.Folder.EncryptedDataKey\x12\x1a\n\x12rotateOnExpiration\x18\x08 \x01(\x08\"\x99\x02\n\x16SharedFolderUpdateTeam\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x13\n\x0bmanageUsers\x18\x02 \x01(\x08\x12\x15\n\rmanageRecords\x18\x03 \x01(\x08\x12\x1b\n\x0fsharedFolderKey\x18\x04 \x01(\x0c\x42\x02\x18\x01\x12\x12\n\nexpiration\x18\x05 \x01(\x12\x12=\n\x15timerNotificationType\x18\x06 \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x36\n\x14typedSharedFolderKey\x18\x07 \x01(\x0b\x32\x18.Folder.EncryptedDataKey\x12\x1a\n\x12rotateOnExpiration\x18\x08 \x01(\x08\"\x8e\x07\n\x1bSharedFolderUpdateV3Request\x12,\n$sharedFolderUpdateOperation_dont_use\x18\x01 \x01(\x05\x12\x17\n\x0fsharedFolderUid\x18\x02 \x01(\x0c\x12!\n\x19\x65ncryptedSharedFolderName\x18\x03 \x01(\x0c\x12\x10\n\x08revision\x18\x04 \x01(\x03\x12\x13\n\x0b\x66orceUpdate\x18\x05 \x01(\x08\x12\x13\n\x0b\x66romTeamUid\x18\x06 \x01(\x0c\x12\x33\n\x12\x64\x65\x66\x61ultManageUsers\x18\x07 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x35\n\x14\x64\x65\x66\x61ultManageRecords\x18\x08 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12/\n\x0e\x64\x65\x66\x61ultCanEdit\x18\t \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x30\n\x0f\x64\x65\x66\x61ultCanShare\x18\n \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12?\n\x15sharedFolderAddRecord\x18\x0b \x03(\x0b\x32 .Folder.SharedFolderUpdateRecord\x12;\n\x13sharedFolderAddUser\x18\x0c \x03(\x0b\x32\x1e.Folder.SharedFolderUpdateUser\x12;\n\x13sharedFolderAddTeam\x18\r \x03(\x0b\x32\x1e.Folder.SharedFolderUpdateTeam\x12\x42\n\x18sharedFolderUpdateRecord\x18\x0e \x03(\x0b\x32 .Folder.SharedFolderUpdateRecord\x12>\n\x16sharedFolderUpdateUser\x18\x0f \x03(\x0b\x32\x1e.Folder.SharedFolderUpdateUser\x12>\n\x16sharedFolderUpdateTeam\x18\x10 \x03(\x0b\x32\x1e.Folder.SharedFolderUpdateTeam\x12 \n\x18sharedFolderRemoveRecord\x18\x11 \x03(\x0c\x12\x1e\n\x16sharedFolderRemoveUser\x18\x12 \x03(\t\x12\x1e\n\x16sharedFolderRemoveTeam\x18\x13 \x03(\x0c\x12\x19\n\x11sharedFolderOwner\x18\x14 \x01(\t\"c\n\x1dSharedFolderUpdateV3RequestV2\x12\x42\n\x15sharedFoldersUpdateV3\x18\x01 \x03(\x0b\x32#.Folder.SharedFolderUpdateV3Request\"C\n\x1eSharedFolderUpdateRecordStatus\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x0e\n\x06status\x18\x02 \x01(\t\"@\n\x1cSharedFolderUpdateUserStatus\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x0e\n\x06status\x18\x02 \x01(\t\"?\n\x1cSharedFolderUpdateTeamStatus\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x0e\n\x06status\x18\x02 \x01(\t\"\x88\x06\n\x1cSharedFolderUpdateV3Response\x12\x10\n\x08revision\x18\x01 \x01(\x03\x12K\n\x1bsharedFolderAddRecordStatus\x18\x02 \x03(\x0b\x32&.Folder.SharedFolderUpdateRecordStatus\x12G\n\x19sharedFolderAddUserStatus\x18\x03 \x03(\x0b\x32$.Folder.SharedFolderUpdateUserStatus\x12G\n\x19sharedFolderAddTeamStatus\x18\x04 \x03(\x0b\x32$.Folder.SharedFolderUpdateTeamStatus\x12N\n\x1esharedFolderUpdateRecordStatus\x18\x05 \x03(\x0b\x32&.Folder.SharedFolderUpdateRecordStatus\x12J\n\x1csharedFolderUpdateUserStatus\x18\x06 \x03(\x0b\x32$.Folder.SharedFolderUpdateUserStatus\x12J\n\x1csharedFolderUpdateTeamStatus\x18\x07 \x03(\x0b\x32$.Folder.SharedFolderUpdateTeamStatus\x12N\n\x1esharedFolderRemoveRecordStatus\x18\x08 \x03(\x0b\x32&.Folder.SharedFolderUpdateRecordStatus\x12J\n\x1csharedFolderRemoveUserStatus\x18\t \x03(\x0b\x32$.Folder.SharedFolderUpdateUserStatus\x12J\n\x1csharedFolderRemoveTeamStatus\x18\n \x03(\x0b\x32$.Folder.SharedFolderUpdateTeamStatus\x12\x17\n\x0fsharedFolderUid\x18\x0c \x01(\x0c\x12\x0e\n\x06status\x18\r \x01(\t\"m\n\x1eSharedFolderUpdateV3ResponseV2\x12K\n\x1dsharedFoldersUpdateV3Response\x18\x01 \x03(\x0b\x32$.Folder.SharedFolderUpdateV3Response\"\xfa\x01\n)GetDeletedSharedFoldersAndRecordsResponse\x12\x32\n\rsharedFolders\x18\x01 \x03(\x0b\x32\x1b.Folder.DeletedSharedFolder\x12>\n\x13sharedFolderRecords\x18\x02 \x03(\x0b\x32!.Folder.DeletedSharedFolderRecord\x12\x34\n\x11\x64\x65letedRecordData\x18\x03 \x03(\x0b\x32\x19.Folder.DeletedRecordData\x12#\n\tusernames\x18\x04 \x03(\x0b\x32\x10.Folder.Username\"\xd1\x01\n\x13\x44\x65letedSharedFolder\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x11\n\tfolderUid\x18\x02 \x01(\x0c\x12\x11\n\tparentUid\x18\x03 \x01(\x0c\x12\x17\n\x0fsharedFolderKey\x18\x04 \x01(\x0c\x12-\n\rfolderKeyType\x18\x05 \x01(\x0e\x32\x16.Records.RecordKeyType\x12\x0c\n\x04\x64\x61ta\x18\x06 \x01(\x0c\x12\x13\n\x0b\x64\x61teDeleted\x18\x07 \x01(\x03\x12\x10\n\x08revision\x18\x08 \x01(\x03\"\x81\x01\n\x19\x44\x65letedSharedFolderRecord\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x17\n\x0fsharedRecordKey\x18\x03 \x01(\x0c\x12\x13\n\x0b\x64\x61teDeleted\x18\x04 \x01(\x03\x12\x10\n\x08revision\x18\x05 \x01(\x03\"\x85\x01\n\x11\x44\x65letedRecordData\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x10\n\x08ownerUid\x18\x02 \x01(\x0c\x12\x10\n\x08revision\x18\x03 \x01(\x03\x12\x1a\n\x12\x63lientModifiedTime\x18\x04 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x05 \x01(\x0c\x12\x0f\n\x07version\x18\x06 \x01(\x05\"0\n\x08Username\x12\x12\n\naccountUid\x18\x01 \x01(\x0c\x12\x10\n\x08username\x18\x02 \x01(\t\"\x8a\x01\n,RestoreDeletedSharedFoldersAndRecordsRequest\x12,\n\x07\x66olders\x18\x01 \x03(\x0b\x32\x1b.Folder.RestoreSharedObject\x12,\n\x07records\x18\x02 \x03(\x0b\x32\x1b.Folder.RestoreSharedObject\"<\n\x13RestoreSharedObject\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x12\n\nrecordUids\x18\x02 \x03(\x0c\"\x83\x02\n\nFolderData\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\tparentUid\x18\x02 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12%\n\x04type\x18\x04 \x01(\x0e\x32\x17.Folder.FolderUsageType\x12\x37\n\x16inheritUserPermissions\x18\x05 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x11\n\tfolderKey\x18\x06 \x01(\x0c\x12#\n\townerInfo\x18\x07 \x01(\x0b\x32\x10.Folder.UserInfo\x12\x13\n\x0b\x64\x61teCreated\x18\x08 \x01(\x03\x12\x14\n\x0clastModified\x18\t \x01(\x03\"z\n\tFolderKey\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\tparentUid\x18\x02 \x01(\x0c\x12\x11\n\tfolderKey\x18\x03 \x01(\x0c\x12\x34\n\x0b\x65ncryptedBy\x18\x04 \x01(\x0e\x32\x1f.Folder.FolderKeyEncryptionType\":\n\x10\x46olderAddRequest\x12&\n\nfolderData\x18\x01 \x03(\x0b\x32\x12.Folder.FolderData\"d\n\x12\x46olderModifyResult\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12*\n\x06status\x18\x02 \x01(\x0e\x32\x1a.Folder.FolderModifyStatus\x12\x0f\n\x07message\x18\x03 \x01(\t\"I\n\x11\x46olderAddResponse\x12\x34\n\x10\x66olderAddResults\x18\x01 \x03(\x0b\x32\x1a.Folder.FolderModifyResult\"=\n\x13\x46olderUpdateRequest\x12&\n\nfolderData\x18\x01 \x03(\x0b\x32\x12.Folder.FolderData\"O\n\x14\x46olderUpdateResponse\x12\x37\n\x13\x66olderUpdateResults\x18\x01 \x03(\x0b\x32\x1a.Folder.FolderModifyResult\"\xc3\x02\n\x11\x46olderPermissions\x12\x0e\n\x06\x63\x61nAdd\x18\x01 \x01(\x08\x12\x11\n\tcanRemove\x18\x02 \x01(\x08\x12\x11\n\tcanDelete\x18\x03 \x01(\x08\x12\x15\n\rcanListAccess\x18\x04 \x01(\x08\x12\x17\n\x0f\x63\x61nUpdateAccess\x18\x05 \x01(\x08\x12\x1a\n\x12\x63\x61nChangeOwnership\x18\x06 \x01(\x08\x12\x16\n\x0e\x63\x61nEditRecords\x18\x07 \x01(\x08\x12\x16\n\x0e\x63\x61nViewRecords\x18\x08 \x01(\x08\x12\x18\n\x10\x63\x61nApproveAccess\x18\t \x01(\x08\x12\x18\n\x10\x63\x61nRequestAccess\x18\n \x01(\x08\x12\x18\n\x10\x63\x61nUpdateSetting\x18\x0b \x01(\x08\x12\x16\n\x0e\x63\x61nListRecords\x18\x0c \x01(\x08\x12\x16\n\x0e\x63\x61nListFolders\x18\r \x01(\x08\"\x83\x05\n\x0c\x43\x61pabilities\x12\'\n\x06\x63\x61nAdd\x18\x01 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12*\n\tcanRemove\x18\x02 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12*\n\tcanDelete\x18\x03 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12.\n\rcanListAccess\x18\x04 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x30\n\x0f\x63\x61nUpdateAccess\x18\x05 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x33\n\x12\x63\x61nChangeOwnership\x18\x06 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12/\n\x0e\x63\x61nEditRecords\x18\x07 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12/\n\x0e\x63\x61nViewRecords\x18\x08 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x31\n\x10\x63\x61nApproveAccess\x18\t \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x31\n\x10\x63\x61nRequestAccess\x18\n \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x31\n\x10\x63\x61nUpdateSetting\x18\x0b \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12/\n\x0e\x63\x61nListRecords\x18\x0c \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12/\n\x0e\x63\x61nListFolders\x18\r \x01(\x0e\x32\x17.Folder.SetBooleanValue\"\xb8\x01\n\x19\x46olderRecordUpdateRequest\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12*\n\naddRecords\x18\x02 \x03(\x0b\x32\x16.Folder.RecordMetadata\x12-\n\rupdateRecords\x18\x03 \x03(\x0b\x32\x16.Folder.RecordMetadata\x12-\n\rremoveRecords\x18\x04 \x03(\x0b\x32\x16.Folder.RecordMetadata\"\xab\x01\n\x0eRecordMetadata\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x1a\n\x12\x65ncryptedRecordKey\x18\x02 \x01(\x0c\x12\x38\n\x16\x65ncryptedRecordKeyType\x18\x03 \x01(\x0e\x32\x18.Folder.EncryptedKeyType\x12\x30\n\rtlaProperties\x18\x05 \x01(\x0b\x32\x19.common.tla.TLAProperties\"\x93\x01\n\x0c\x46olderRecord\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12.\n\x0erecordMetadata\x18\x02 \x01(\x0b\x32\x16.Folder.RecordMetadata\x12@\n\x17\x66olderKeyEncryptionType\x18\x03 \x01(\x0e\x32\x1f.Folder.FolderKeyEncryptionType\"s\n\x1a\x46olderRecordUpdateResponse\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x42\n\x18\x66olderRecordUpdateResult\x18\x04 \x03(\x0b\x32 .Folder.FolderRecordUpdateResult\"j\n\x18\x46olderRecordUpdateResult\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12*\n\x06status\x18\x02 \x01(\x0e\x32\x1a.Folder.FolderModifyStatus\x12\x0f\n\x07message\x18\x03 \x01(\t\"\x87\x03\n\x10\x46olderAccessData\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x15\n\raccessTypeUid\x18\x02 \x01(\x0c\x12&\n\naccessType\x18\x03 \x01(\x0e\x32\x12.Folder.AccessType\x12.\n\x0e\x61\x63\x63\x65ssRoleType\x18\x04 \x01(\x0e\x32\x16.Folder.AccessRoleType\x12+\n\tfolderKey\x18\x05 \x01(\x0b\x32\x18.Folder.EncryptedDataKey\x12\x11\n\tinherited\x18\x06 \x01(\x08\x12\x0e\n\x06hidden\x18\x07 \x01(\x08\x12.\n\x0bpermissions\x18\x08 \x01(\x0b\x32\x19.Folder.FolderPermissions\x12\x30\n\rtlaProperties\x18\t \x01(\x0b\x32\x19.common.tla.TLAProperties\x12\x13\n\x0b\x64\x61teCreated\x18\n \x01(\x03\x12\x14\n\x0clastModified\x18\x0b \x01(\x03\x12\x14\n\x0c\x64\x65niedAccess\x18\x0c \x01(\x08\"\\\n\rRevokedAccess\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x10\n\x08\x61\x63torUid\x18\x02 \x01(\x0c\x12&\n\naccessType\x18\x03 \x01(\x0e\x32\x12.Folder.AccessType\"#\n\rFolderRemoved\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\"\x93\x04\n\x10RecordAccessData\x12\x15\n\raccessTypeUid\x18\x01 \x01(\x0c\x12&\n\naccessType\x18\x02 \x01(\x0e\x32\x12.Folder.AccessType\x12\x11\n\trecordUid\x18\x03 \x01(\x0c\x12.\n\x0e\x61\x63\x63\x65ssRoleType\x18\x04 \x01(\x0e\x32\x16.Folder.AccessRoleType\x12\r\n\x05owner\x18\x05 \x01(\x08\x12\x11\n\tinherited\x18\x06 \x01(\x08\x12\x0e\n\x06hidden\x18\x07 \x01(\x08\x12\x14\n\x0c\x64\x65niedAccess\x18\x08 \x01(\x08\x12\x16\n\x0e\x63\x61n_view_title\x18\t \x01(\x08\x12\x10\n\x08\x63\x61n_edit\x18\n \x01(\x08\x12\x10\n\x08\x63\x61n_view\x18\x0b \x01(\x08\x12\x17\n\x0f\x63\x61n_list_access\x18\x0c \x01(\x08\x12\x19\n\x11\x63\x61n_update_access\x18\r \x01(\x08\x12\x12\n\ncan_delete\x18\x0e \x01(\x08\x12\x1c\n\x14\x63\x61n_change_ownership\x18\x0f \x01(\x08\x12\x1a\n\x12\x63\x61n_request_access\x18\x10 \x01(\x08\x12\x1a\n\x12\x63\x61n_approve_access\x18\x11 \x01(\x08\x12\x13\n\x0b\x64\x61teCreated\x18\x12 \x01(\x03\x12\x14\n\x0clastModified\x18\x13 \x01(\x03\x12\x30\n\rtlaProperties\x18\x14 \x01(\x0b\x32\x19.common.tla.TLAProperties\"\xb8\x01\n\nAccessData\x12\x15\n\raccessTypeUid\x18\x01 \x01(\x0c\x12.\n\x0e\x61\x63\x63\x65ssRoleType\x18\x02 \x01(\x0e\x32\x16.Folder.AccessRoleType\x12\x14\n\x0c\x64\x65niedAccess\x18\x03 \x01(\x08\x12\x11\n\tinherited\x18\x04 \x01(\x08\x12\x0e\n\x06hidden\x18\x05 \x01(\x08\x12*\n\x0c\x63\x61pabilities\x18\x06 \x01(\x0b\x32\x14.Folder.Capabilities\"\xb7\x01\n\x13\x46olderAccessRequest\x12\x32\n\x10\x66olderAccessAdds\x18\x01 \x03(\x0b\x32\x18.Folder.FolderAccessData\x12\x35\n\x13\x66olderAccessUpdates\x18\x02 \x03(\x0b\x32\x18.Folder.FolderAccessData\x12\x35\n\x13\x66olderAccessRemoves\x18\x03 \x03(\x0b\x32\x18.Folder.FolderAccessData\"\x9f\x01\n\x12\x46olderAccessResult\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\taccessUid\x18\x02 \x01(\x0c\x12&\n\naccessType\x18\x03 \x01(\x0e\x32\x12.Folder.AccessType\x12*\n\x06status\x18\x04 \x01(\x0e\x32\x1a.Folder.FolderModifyStatus\x12\x0f\n\x07message\x18\x05 \x01(\t\"O\n\x14\x46olderAccessResponse\x12\x37\n\x13\x66olderAccessResults\x18\x01 \x03(\x0b\x32\x1a.Folder.FolderAccessResult\"0\n\x08UserInfo\x12\x12\n\naccountUid\x18\x01 \x01(\x0c\x12\x10\n\x08username\x18\x02 \x01(\t\"M\n\nRecordData\x12\x1e\n\x04user\x18\x01 \x01(\x0b\x32\x10.Folder.UserInfo\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x11\n\trecordUid\x18\x03 \x01(\x0c\"{\n\tRecordKey\x12\x10\n\x08user_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_uid\x18\x02 \x01(\x0c\x12\x12\n\nrecord_key\x18\x03 \x01(\x0c\x12\x34\n\x12\x65ncrypted_key_type\x18\x04 \x01(\x0e\x32\x18.Folder.EncryptedKeyType*\x1a\n\nRecordType\x12\x0c\n\x08password\x10\x00*^\n\nFolderType\x12\x12\n\x0e\x64\x65\x66\x61ult_folder\x10\x00\x12\x0f\n\x0buser_folder\x10\x01\x12\x11\n\rshared_folder\x10\x02\x12\x18\n\x14shared_folder_folder\x10\x03*\x96\x01\n\x10\x45ncryptedKeyType\x12\n\n\x06no_key\x10\x00\x12\x19\n\x15\x65ncrypted_by_data_key\x10\x01\x12\x1b\n\x17\x65ncrypted_by_public_key\x10\x02\x12\x1d\n\x19\x65ncrypted_by_data_key_gcm\x10\x03\x12\x1f\n\x1b\x65ncrypted_by_public_key_ecc\x10\x04*M\n\x0fSetBooleanValue\x12\x15\n\x11\x42OOLEAN_NO_CHANGE\x10\x00\x12\x10\n\x0c\x42OOLEAN_TRUE\x10\x01\x12\x11\n\rBOOLEAN_FALSE\x10\x02*R\n\x0f\x46olderUsageType\x12\x0e\n\nUT_UNKNOWN\x10\x00\x12\r\n\tUT_NORMAL\x10\x01\x12\x0f\n\x0bUT_WORKFLOW\x10\x02\x12\x0f\n\x0bUT_TRASHCAN\x10\x03*l\n\x17\x46olderKeyEncryptionType\x12\x19\n\x15\x45NCRYPTED_BY_USER_KEY\x10\x00\x12\x1b\n\x17\x45NCRYPTED_BY_PARENT_KEY\x10\x01\x12\x19\n\x15\x45NCRYPTED_BY_TEAM_KEY\x10\x02*T\n\x12\x46olderModifyStatus\x12\x0b\n\x07SUCCESS\x10\x00\x12\x0f\n\x0b\x42\x41\x44_REQUEST\x10\x01\x12\x11\n\rACCESS_DENIED\x10\x02\x12\r\n\tNOT_FOUND\x10\x03*\xa4\x02\n\x14\x46olderPermissionBits\x12\n\n\x06noBits\x10\x00\x12\n\n\x06\x63\x61nAdd\x10\x01\x12\r\n\tcanRemove\x10\x02\x12\r\n\tcanDelete\x10\x04\x12\x11\n\rcanListAccess\x10\x08\x12\x13\n\x0f\x63\x61nUpdateAccess\x10\x10\x12\x16\n\x12\x63\x61nChangeOwnership\x10 \x12\x12\n\x0e\x63\x61nEditRecords\x10@\x12\x13\n\x0e\x63\x61nViewRecords\x10\x80\x01\x12\x15\n\x10\x63\x61nApproveAccess\x10\x80\x02\x12\x15\n\x10\x63\x61nRequestAccess\x10\x80\x04\x12\x15\n\x10\x63\x61nUpdateSetting\x10\x80\x08\x12\x13\n\x0e\x63\x61nListRecords\x10\x80\x10\x12\x13\n\x0e\x63\x61nListFolders\x10\x80 *\x9b\x01\n\x0e\x41\x63\x63\x65ssRoleType\x12\r\n\tNAVIGATOR\x10\x00\x12\r\n\tREQUESTOR\x10\x01\x12\n\n\x06VIEWER\x10\x02\x12\x12\n\x0eSHARED_MANAGER\x10\x03\x12\x13\n\x0f\x43ONTENT_MANAGER\x10\x04\x12\x19\n\x15\x43ONTENT_SHARE_MANAGER\x10\x05\x12\x0b\n\x07MANAGER\x10\x06\x12\x0e\n\nUNRESOLVED\x10\x07*z\n\nAccessType\x12\x0e\n\nAT_UNKNOWN\x10\x00\x12\x0c\n\x08\x41T_OWNER\x10\x01\x12\x0b\n\x07\x41T_USER\x10\x02\x12\x0b\n\x07\x41T_TEAM\x10\x03\x12\x11\n\rAT_ENTERPRISE\x10\x04\x12\r\n\tAT_FOLDER\x10\x05\x12\x12\n\x0e\x41T_APPLICATION\x10\x06*:\n\nObjectType\x12\x0e\n\nOT_UNKNOWN\x10\x00\x12\r\n\tOT_RECORD\x10\x01\x12\r\n\tOT_FOLDER\x10\x02\x42\"\n\x18\x63om.keepersecurity.protoB\x06\x46olderb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x66older.proto\x12\x06\x46older\x1a\x0crecord.proto\x1a\ttla.proto\"\\\n\x10\x45ncryptedDataKey\x12\x14\n\x0c\x65ncryptedKey\x18\x01 \x01(\x0c\x12\x32\n\x10\x65ncryptedKeyType\x18\x02 \x01(\x0e\x32\x18.Folder.EncryptedKeyType\"\x82\x01\n\x16SharedFolderRecordData\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x0e\n\x06userId\x18\x03 \x01(\x05\x12\x32\n\x10\x65ncryptedDataKey\x18\x04 \x03(\x0b\x32\x18.Folder.EncryptedDataKey\"\\\n\x1aSharedFolderRecordDataList\x12>\n\x16sharedFolderRecordData\x18\x01 \x03(\x0b\x32\x1e.Folder.SharedFolderRecordData\"_\n\x15SharedFolderRecordFix\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12 \n\x18\x65ncryptedRecordFolderKey\x18\x03 \x01(\x0c\"Y\n\x19SharedFolderRecordFixList\x12<\n\x15sharedFolderRecordFix\x18\x01 \x03(\x0b\x32\x1d.Folder.SharedFolderRecordFix\"\xa2\x02\n\rRecordRequest\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12&\n\nrecordType\x18\x02 \x01(\x0e\x32\x12.Folder.RecordType\x12\x12\n\nrecordData\x18\x03 \x01(\x0c\x12\x1a\n\x12\x65ncryptedRecordKey\x18\x04 \x01(\x0c\x12&\n\nfolderType\x18\x05 \x01(\x0e\x32\x12.Folder.FolderType\x12\x12\n\nhowLongAgo\x18\x06 \x01(\x03\x12\x11\n\tfolderUid\x18\x07 \x01(\x0c\x12 \n\x18\x65ncryptedRecordFolderKey\x18\x08 \x01(\x0c\x12\r\n\x05\x65xtra\x18\t \x01(\x0c\x12\x15\n\rnonSharedData\x18\n \x01(\x0c\x12\x0f\n\x07\x66ileIds\x18\x0b \x03(\x03\"E\n\x0eRecordResponse\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x10\n\x08revision\x18\x02 \x01(\x03\x12\x0e\n\x06status\x18\x03 \x01(\t\"\x80\x01\n\x12SharedFolderFields\x12\x1b\n\x13\x65ncryptedFolderName\x18\x01 \x01(\x0c\x12\x13\n\x0bmanageUsers\x18\x02 \x01(\x08\x12\x15\n\rmanageRecords\x18\x03 \x01(\x08\x12\x0f\n\x07\x63\x61nEdit\x18\x04 \x01(\x08\x12\x10\n\x08\x63\x61nShare\x18\x05 \x01(\x08\"3\n\x18SharedFolderFolderFields\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\"\x8f\x02\n\rFolderRequest\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12&\n\nfolderType\x18\x02 \x01(\x0e\x32\x12.Folder.FolderType\x12\x17\n\x0fparentFolderUid\x18\x03 \x01(\x0c\x12\x12\n\nfolderData\x18\x04 \x01(\x0c\x12\x1a\n\x12\x65ncryptedFolderKey\x18\x05 \x01(\x0c\x12\x36\n\x12sharedFolderFields\x18\x06 \x01(\x0b\x32\x1a.Folder.SharedFolderFields\x12\x42\n\x18sharedFolderFolderFields\x18\x07 \x01(\x0b\x32 .Folder.SharedFolderFolderFields\"E\n\x0e\x46olderResponse\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x10\n\x08revision\x18\x02 \x01(\x03\x12\x0e\n\x06status\x18\x03 \x01(\t\"w\n\x19ImportFolderRecordRequest\x12,\n\rfolderRequest\x18\x01 \x03(\x0b\x32\x15.Folder.FolderRequest\x12,\n\rrecordRequest\x18\x02 \x03(\x0b\x32\x15.Folder.RecordRequest\"|\n\x1aImportFolderRecordResponse\x12.\n\x0e\x66olderResponse\x18\x01 \x03(\x0b\x32\x16.Folder.FolderResponse\x12.\n\x0erecordResponse\x18\x02 \x03(\x0b\x32\x16.Folder.RecordResponse\"\xc9\x02\n\x18SharedFolderUpdateRecord\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x17\n\x0fsharedFolderUid\x18\x02 \x01(\x0c\x12\x0f\n\x07teamUid\x18\x03 \x01(\x0c\x12(\n\x07\x63\x61nEdit\x18\x04 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12)\n\x08\x63\x61nShare\x18\x05 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x1a\n\x12\x65ncryptedRecordKey\x18\x06 \x01(\x0c\x12\x10\n\x08revision\x18\x07 \x01(\x05\x12\x12\n\nexpiration\x18\x08 \x01(\x12\x12=\n\x15timerNotificationType\x18\t \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x1a\n\x12rotateOnExpiration\x18\n \x01(\x08\"\xcc\x02\n\x16SharedFolderUpdateUser\x12\x10\n\x08username\x18\x01 \x01(\t\x12,\n\x0bmanageUsers\x18\x02 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12.\n\rmanageRecords\x18\x03 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x1b\n\x0fsharedFolderKey\x18\x04 \x01(\x0c\x42\x02\x18\x01\x12\x12\n\nexpiration\x18\x05 \x01(\x12\x12=\n\x15timerNotificationType\x18\x06 \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x36\n\x14typedSharedFolderKey\x18\x07 \x01(\x0b\x32\x18.Folder.EncryptedDataKey\x12\x1a\n\x12rotateOnExpiration\x18\x08 \x01(\x08\"\x99\x02\n\x16SharedFolderUpdateTeam\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x13\n\x0bmanageUsers\x18\x02 \x01(\x08\x12\x15\n\rmanageRecords\x18\x03 \x01(\x08\x12\x1b\n\x0fsharedFolderKey\x18\x04 \x01(\x0c\x42\x02\x18\x01\x12\x12\n\nexpiration\x18\x05 \x01(\x12\x12=\n\x15timerNotificationType\x18\x06 \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x36\n\x14typedSharedFolderKey\x18\x07 \x01(\x0b\x32\x18.Folder.EncryptedDataKey\x12\x1a\n\x12rotateOnExpiration\x18\x08 \x01(\x08\"\x8e\x07\n\x1bSharedFolderUpdateV3Request\x12,\n$sharedFolderUpdateOperation_dont_use\x18\x01 \x01(\x05\x12\x17\n\x0fsharedFolderUid\x18\x02 \x01(\x0c\x12!\n\x19\x65ncryptedSharedFolderName\x18\x03 \x01(\x0c\x12\x10\n\x08revision\x18\x04 \x01(\x03\x12\x13\n\x0b\x66orceUpdate\x18\x05 \x01(\x08\x12\x13\n\x0b\x66romTeamUid\x18\x06 \x01(\x0c\x12\x33\n\x12\x64\x65\x66\x61ultManageUsers\x18\x07 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x35\n\x14\x64\x65\x66\x61ultManageRecords\x18\x08 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12/\n\x0e\x64\x65\x66\x61ultCanEdit\x18\t \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x30\n\x0f\x64\x65\x66\x61ultCanShare\x18\n \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12?\n\x15sharedFolderAddRecord\x18\x0b \x03(\x0b\x32 .Folder.SharedFolderUpdateRecord\x12;\n\x13sharedFolderAddUser\x18\x0c \x03(\x0b\x32\x1e.Folder.SharedFolderUpdateUser\x12;\n\x13sharedFolderAddTeam\x18\r \x03(\x0b\x32\x1e.Folder.SharedFolderUpdateTeam\x12\x42\n\x18sharedFolderUpdateRecord\x18\x0e \x03(\x0b\x32 .Folder.SharedFolderUpdateRecord\x12>\n\x16sharedFolderUpdateUser\x18\x0f \x03(\x0b\x32\x1e.Folder.SharedFolderUpdateUser\x12>\n\x16sharedFolderUpdateTeam\x18\x10 \x03(\x0b\x32\x1e.Folder.SharedFolderUpdateTeam\x12 \n\x18sharedFolderRemoveRecord\x18\x11 \x03(\x0c\x12\x1e\n\x16sharedFolderRemoveUser\x18\x12 \x03(\t\x12\x1e\n\x16sharedFolderRemoveTeam\x18\x13 \x03(\x0c\x12\x19\n\x11sharedFolderOwner\x18\x14 \x01(\t\"c\n\x1dSharedFolderUpdateV3RequestV2\x12\x42\n\x15sharedFoldersUpdateV3\x18\x01 \x03(\x0b\x32#.Folder.SharedFolderUpdateV3Request\"C\n\x1eSharedFolderUpdateRecordStatus\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x0e\n\x06status\x18\x02 \x01(\t\"@\n\x1cSharedFolderUpdateUserStatus\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x0e\n\x06status\x18\x02 \x01(\t\"?\n\x1cSharedFolderUpdateTeamStatus\x12\x0f\n\x07teamUid\x18\x01 \x01(\x0c\x12\x0e\n\x06status\x18\x02 \x01(\t\"\x88\x06\n\x1cSharedFolderUpdateV3Response\x12\x10\n\x08revision\x18\x01 \x01(\x03\x12K\n\x1bsharedFolderAddRecordStatus\x18\x02 \x03(\x0b\x32&.Folder.SharedFolderUpdateRecordStatus\x12G\n\x19sharedFolderAddUserStatus\x18\x03 \x03(\x0b\x32$.Folder.SharedFolderUpdateUserStatus\x12G\n\x19sharedFolderAddTeamStatus\x18\x04 \x03(\x0b\x32$.Folder.SharedFolderUpdateTeamStatus\x12N\n\x1esharedFolderUpdateRecordStatus\x18\x05 \x03(\x0b\x32&.Folder.SharedFolderUpdateRecordStatus\x12J\n\x1csharedFolderUpdateUserStatus\x18\x06 \x03(\x0b\x32$.Folder.SharedFolderUpdateUserStatus\x12J\n\x1csharedFolderUpdateTeamStatus\x18\x07 \x03(\x0b\x32$.Folder.SharedFolderUpdateTeamStatus\x12N\n\x1esharedFolderRemoveRecordStatus\x18\x08 \x03(\x0b\x32&.Folder.SharedFolderUpdateRecordStatus\x12J\n\x1csharedFolderRemoveUserStatus\x18\t \x03(\x0b\x32$.Folder.SharedFolderUpdateUserStatus\x12J\n\x1csharedFolderRemoveTeamStatus\x18\n \x03(\x0b\x32$.Folder.SharedFolderUpdateTeamStatus\x12\x17\n\x0fsharedFolderUid\x18\x0c \x01(\x0c\x12\x0e\n\x06status\x18\r \x01(\t\"m\n\x1eSharedFolderUpdateV3ResponseV2\x12K\n\x1dsharedFoldersUpdateV3Response\x18\x01 \x03(\x0b\x32$.Folder.SharedFolderUpdateV3Response\"\xfa\x01\n)GetDeletedSharedFoldersAndRecordsResponse\x12\x32\n\rsharedFolders\x18\x01 \x03(\x0b\x32\x1b.Folder.DeletedSharedFolder\x12>\n\x13sharedFolderRecords\x18\x02 \x03(\x0b\x32!.Folder.DeletedSharedFolderRecord\x12\x34\n\x11\x64\x65letedRecordData\x18\x03 \x03(\x0b\x32\x19.Folder.DeletedRecordData\x12#\n\tusernames\x18\x04 \x03(\x0b\x32\x10.Folder.Username\"\xd1\x01\n\x13\x44\x65letedSharedFolder\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x11\n\tfolderUid\x18\x02 \x01(\x0c\x12\x11\n\tparentUid\x18\x03 \x01(\x0c\x12\x17\n\x0fsharedFolderKey\x18\x04 \x01(\x0c\x12-\n\rfolderKeyType\x18\x05 \x01(\x0e\x32\x16.Records.RecordKeyType\x12\x0c\n\x04\x64\x61ta\x18\x06 \x01(\x0c\x12\x13\n\x0b\x64\x61teDeleted\x18\x07 \x01(\x03\x12\x10\n\x08revision\x18\x08 \x01(\x03\"\x81\x01\n\x19\x44\x65letedSharedFolderRecord\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x17\n\x0fsharedRecordKey\x18\x03 \x01(\x0c\x12\x13\n\x0b\x64\x61teDeleted\x18\x04 \x01(\x03\x12\x10\n\x08revision\x18\x05 \x01(\x03\"\x85\x01\n\x11\x44\x65letedRecordData\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x10\n\x08ownerUid\x18\x02 \x01(\x0c\x12\x10\n\x08revision\x18\x03 \x01(\x03\x12\x1a\n\x12\x63lientModifiedTime\x18\x04 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x05 \x01(\x0c\x12\x0f\n\x07version\x18\x06 \x01(\x05\"0\n\x08Username\x12\x12\n\naccountUid\x18\x01 \x01(\x0c\x12\x10\n\x08username\x18\x02 \x01(\t\"\x8a\x01\n,RestoreDeletedSharedFoldersAndRecordsRequest\x12,\n\x07\x66olders\x18\x01 \x03(\x0b\x32\x1b.Folder.RestoreSharedObject\x12,\n\x07records\x18\x02 \x03(\x0b\x32\x1b.Folder.RestoreSharedObject\"<\n\x13RestoreSharedObject\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x12\n\nrecordUids\x18\x02 \x03(\x0c\"\x83\x02\n\nFolderData\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\tparentUid\x18\x02 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12%\n\x04type\x18\x04 \x01(\x0e\x32\x17.Folder.FolderUsageType\x12\x37\n\x16inheritUserPermissions\x18\x05 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x11\n\tfolderKey\x18\x06 \x01(\x0c\x12#\n\townerInfo\x18\x07 \x01(\x0b\x32\x10.Folder.UserInfo\x12\x13\n\x0b\x64\x61teCreated\x18\x08 \x01(\x03\x12\x14\n\x0clastModified\x18\t \x01(\x03\"z\n\tFolderKey\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\tparentUid\x18\x02 \x01(\x0c\x12\x11\n\tfolderKey\x18\x03 \x01(\x0c\x12\x34\n\x0b\x65ncryptedBy\x18\x04 \x01(\x0e\x32\x1f.Folder.FolderKeyEncryptionType\":\n\x10\x46olderAddRequest\x12&\n\nfolderData\x18\x01 \x03(\x0b\x32\x12.Folder.FolderData\"d\n\x12\x46olderModifyResult\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12*\n\x06status\x18\x02 \x01(\x0e\x32\x1a.Folder.FolderModifyStatus\x12\x0f\n\x07message\x18\x03 \x01(\t\"I\n\x11\x46olderAddResponse\x12\x34\n\x10\x66olderAddResults\x18\x01 \x03(\x0b\x32\x1a.Folder.FolderModifyResult\"=\n\x13\x46olderUpdateRequest\x12&\n\nfolderData\x18\x01 \x03(\x0b\x32\x12.Folder.FolderData\"O\n\x14\x46olderUpdateResponse\x12\x37\n\x13\x66olderUpdateResults\x18\x01 \x03(\x0b\x32\x1a.Folder.FolderModifyResult\"\xc3\x02\n\x11\x46olderPermissions\x12\x0e\n\x06\x63\x61nAdd\x18\x01 \x01(\x08\x12\x11\n\tcanRemove\x18\x02 \x01(\x08\x12\x11\n\tcanDelete\x18\x03 \x01(\x08\x12\x15\n\rcanListAccess\x18\x04 \x01(\x08\x12\x17\n\x0f\x63\x61nUpdateAccess\x18\x05 \x01(\x08\x12\x1a\n\x12\x63\x61nChangeOwnership\x18\x06 \x01(\x08\x12\x16\n\x0e\x63\x61nEditRecords\x18\x07 \x01(\x08\x12\x16\n\x0e\x63\x61nViewRecords\x18\x08 \x01(\x08\x12\x18\n\x10\x63\x61nApproveAccess\x18\t \x01(\x08\x12\x18\n\x10\x63\x61nRequestAccess\x18\n \x01(\x08\x12\x18\n\x10\x63\x61nUpdateSetting\x18\x0b \x01(\x08\x12\x16\n\x0e\x63\x61nListRecords\x18\x0c \x01(\x08\x12\x16\n\x0e\x63\x61nListFolders\x18\r \x01(\x08\"\x83\x05\n\x0c\x43\x61pabilities\x12\'\n\x06\x63\x61nAdd\x18\x01 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12*\n\tcanRemove\x18\x02 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12*\n\tcanDelete\x18\x03 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12.\n\rcanListAccess\x18\x04 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x30\n\x0f\x63\x61nUpdateAccess\x18\x05 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x33\n\x12\x63\x61nChangeOwnership\x18\x06 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12/\n\x0e\x63\x61nEditRecords\x18\x07 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12/\n\x0e\x63\x61nViewRecords\x18\x08 \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x31\n\x10\x63\x61nApproveAccess\x18\t \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x31\n\x10\x63\x61nRequestAccess\x18\n \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12\x31\n\x10\x63\x61nUpdateSetting\x18\x0b \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12/\n\x0e\x63\x61nListRecords\x18\x0c \x01(\x0e\x32\x17.Folder.SetBooleanValue\x12/\n\x0e\x63\x61nListFolders\x18\r \x01(\x0e\x32\x17.Folder.SetBooleanValue\"\xb8\x01\n\x19\x46olderRecordUpdateRequest\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12*\n\naddRecords\x18\x02 \x03(\x0b\x32\x16.Folder.RecordMetadata\x12-\n\rupdateRecords\x18\x03 \x03(\x0b\x32\x16.Folder.RecordMetadata\x12-\n\rremoveRecords\x18\x04 \x03(\x0b\x32\x16.Folder.RecordMetadata\"\xd1\x01\n\x0eRecordMetadata\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x1a\n\x12\x65ncryptedRecordKey\x18\x02 \x01(\x0c\x12\x38\n\x16\x65ncryptedRecordKeyType\x18\x03 \x01(\x0e\x32\x18.Folder.EncryptedKeyType\x12\x30\n\rtlaProperties\x18\x05 \x01(\x0b\x32\x19.common.tla.TLAProperties\x12$\n\x1crecordKeyEncryptedByOwnerKey\x18\x06 \x01(\x0c\"\x93\x01\n\x0c\x46olderRecord\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12.\n\x0erecordMetadata\x18\x02 \x01(\x0b\x32\x16.Folder.RecordMetadata\x12@\n\x17\x66olderKeyEncryptionType\x18\x03 \x01(\x0e\x32\x1f.Folder.FolderKeyEncryptionType\"s\n\x1a\x46olderRecordUpdateResponse\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x42\n\x18\x66olderRecordUpdateResult\x18\x04 \x03(\x0b\x32 .Folder.FolderRecordUpdateResult\"j\n\x18\x46olderRecordUpdateResult\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12*\n\x06status\x18\x02 \x01(\x0e\x32\x1a.Folder.FolderModifyStatus\x12\x0f\n\x07message\x18\x03 \x01(\t\"\x87\x03\n\x10\x46olderAccessData\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x15\n\raccessTypeUid\x18\x02 \x01(\x0c\x12&\n\naccessType\x18\x03 \x01(\x0e\x32\x12.Folder.AccessType\x12.\n\x0e\x61\x63\x63\x65ssRoleType\x18\x04 \x01(\x0e\x32\x16.Folder.AccessRoleType\x12+\n\tfolderKey\x18\x05 \x01(\x0b\x32\x18.Folder.EncryptedDataKey\x12\x11\n\tinherited\x18\x06 \x01(\x08\x12\x0e\n\x06hidden\x18\x07 \x01(\x08\x12.\n\x0bpermissions\x18\x08 \x01(\x0b\x32\x19.Folder.FolderPermissions\x12\x30\n\rtlaProperties\x18\t \x01(\x0b\x32\x19.common.tla.TLAProperties\x12\x13\n\x0b\x64\x61teCreated\x18\n \x01(\x03\x12\x14\n\x0clastModified\x18\x0b \x01(\x03\x12\x14\n\x0c\x64\x65niedAccess\x18\x0c \x01(\x08\"\\\n\rRevokedAccess\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x10\n\x08\x61\x63torUid\x18\x02 \x01(\x0c\x12&\n\naccessType\x18\x03 \x01(\x0e\x32\x12.Folder.AccessType\"#\n\rFolderRemoved\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\"\x93\x04\n\x10RecordAccessData\x12\x15\n\raccessTypeUid\x18\x01 \x01(\x0c\x12&\n\naccessType\x18\x02 \x01(\x0e\x32\x12.Folder.AccessType\x12\x11\n\trecordUid\x18\x03 \x01(\x0c\x12.\n\x0e\x61\x63\x63\x65ssRoleType\x18\x04 \x01(\x0e\x32\x16.Folder.AccessRoleType\x12\r\n\x05owner\x18\x05 \x01(\x08\x12\x11\n\tinherited\x18\x06 \x01(\x08\x12\x0e\n\x06hidden\x18\x07 \x01(\x08\x12\x14\n\x0c\x64\x65niedAccess\x18\x08 \x01(\x08\x12\x16\n\x0e\x63\x61n_view_title\x18\t \x01(\x08\x12\x10\n\x08\x63\x61n_edit\x18\n \x01(\x08\x12\x10\n\x08\x63\x61n_view\x18\x0b \x01(\x08\x12\x17\n\x0f\x63\x61n_list_access\x18\x0c \x01(\x08\x12\x19\n\x11\x63\x61n_update_access\x18\r \x01(\x08\x12\x12\n\ncan_delete\x18\x0e \x01(\x08\x12\x1c\n\x14\x63\x61n_change_ownership\x18\x0f \x01(\x08\x12\x1a\n\x12\x63\x61n_request_access\x18\x10 \x01(\x08\x12\x1a\n\x12\x63\x61n_approve_access\x18\x11 \x01(\x08\x12\x13\n\x0b\x64\x61teCreated\x18\x12 \x01(\x03\x12\x14\n\x0clastModified\x18\x13 \x01(\x03\x12\x30\n\rtlaProperties\x18\x14 \x01(\x0b\x32\x19.common.tla.TLAProperties\"\xb8\x01\n\nAccessData\x12\x15\n\raccessTypeUid\x18\x01 \x01(\x0c\x12.\n\x0e\x61\x63\x63\x65ssRoleType\x18\x02 \x01(\x0e\x32\x16.Folder.AccessRoleType\x12\x14\n\x0c\x64\x65niedAccess\x18\x03 \x01(\x08\x12\x11\n\tinherited\x18\x04 \x01(\x08\x12\x0e\n\x06hidden\x18\x05 \x01(\x08\x12*\n\x0c\x63\x61pabilities\x18\x06 \x01(\x0b\x32\x14.Folder.Capabilities\"\xb7\x01\n\x13\x46olderAccessRequest\x12\x32\n\x10\x66olderAccessAdds\x18\x01 \x03(\x0b\x32\x18.Folder.FolderAccessData\x12\x35\n\x13\x66olderAccessUpdates\x18\x02 \x03(\x0b\x32\x18.Folder.FolderAccessData\x12\x35\n\x13\x66olderAccessRemoves\x18\x03 \x03(\x0b\x32\x18.Folder.FolderAccessData\"\x9f\x01\n\x12\x46olderAccessResult\x12\x11\n\tfolderUid\x18\x01 \x01(\x0c\x12\x11\n\taccessUid\x18\x02 \x01(\x0c\x12&\n\naccessType\x18\x03 \x01(\x0e\x32\x12.Folder.AccessType\x12*\n\x06status\x18\x04 \x01(\x0e\x32\x1a.Folder.FolderModifyStatus\x12\x0f\n\x07message\x18\x05 \x01(\t\"O\n\x14\x46olderAccessResponse\x12\x37\n\x13\x66olderAccessResults\x18\x01 \x03(\x0b\x32\x1a.Folder.FolderAccessResult\"0\n\x08UserInfo\x12\x12\n\naccountUid\x18\x01 \x01(\x0c\x12\x10\n\x08username\x18\x02 \x01(\t\"M\n\nRecordData\x12\x1e\n\x04user\x18\x01 \x01(\x0b\x32\x10.Folder.UserInfo\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x11\n\trecordUid\x18\x03 \x01(\x0c\"{\n\tRecordKey\x12\x10\n\x08user_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_uid\x18\x02 \x01(\x0c\x12\x12\n\nrecord_key\x18\x03 \x01(\x0c\x12\x34\n\x12\x65ncrypted_key_type\x18\x04 \x01(\x0e\x32\x18.Folder.EncryptedKeyType*\x1a\n\nRecordType\x12\x0c\n\x08password\x10\x00*^\n\nFolderType\x12\x12\n\x0e\x64\x65\x66\x61ult_folder\x10\x00\x12\x0f\n\x0buser_folder\x10\x01\x12\x11\n\rshared_folder\x10\x02\x12\x18\n\x14shared_folder_folder\x10\x03*\x96\x01\n\x10\x45ncryptedKeyType\x12\n\n\x06no_key\x10\x00\x12\x19\n\x15\x65ncrypted_by_data_key\x10\x01\x12\x1b\n\x17\x65ncrypted_by_public_key\x10\x02\x12\x1d\n\x19\x65ncrypted_by_data_key_gcm\x10\x03\x12\x1f\n\x1b\x65ncrypted_by_public_key_ecc\x10\x04*M\n\x0fSetBooleanValue\x12\x15\n\x11\x42OOLEAN_NO_CHANGE\x10\x00\x12\x10\n\x0c\x42OOLEAN_TRUE\x10\x01\x12\x11\n\rBOOLEAN_FALSE\x10\x02*R\n\x0f\x46olderUsageType\x12\x0e\n\nUT_UNKNOWN\x10\x00\x12\r\n\tUT_NORMAL\x10\x01\x12\x0f\n\x0bUT_WORKFLOW\x10\x02\x12\x0f\n\x0bUT_TRASHCAN\x10\x03*l\n\x17\x46olderKeyEncryptionType\x12\x19\n\x15\x45NCRYPTED_BY_USER_KEY\x10\x00\x12\x1b\n\x17\x45NCRYPTED_BY_PARENT_KEY\x10\x01\x12\x19\n\x15\x45NCRYPTED_BY_TEAM_KEY\x10\x02*T\n\x12\x46olderModifyStatus\x12\x0b\n\x07SUCCESS\x10\x00\x12\x0f\n\x0b\x42\x41\x44_REQUEST\x10\x01\x12\x11\n\rACCESS_DENIED\x10\x02\x12\r\n\tNOT_FOUND\x10\x03*\xa4\x02\n\x14\x46olderPermissionBits\x12\n\n\x06noBits\x10\x00\x12\n\n\x06\x63\x61nAdd\x10\x01\x12\r\n\tcanRemove\x10\x02\x12\r\n\tcanDelete\x10\x04\x12\x11\n\rcanListAccess\x10\x08\x12\x13\n\x0f\x63\x61nUpdateAccess\x10\x10\x12\x16\n\x12\x63\x61nChangeOwnership\x10 \x12\x12\n\x0e\x63\x61nEditRecords\x10@\x12\x13\n\x0e\x63\x61nViewRecords\x10\x80\x01\x12\x15\n\x10\x63\x61nApproveAccess\x10\x80\x02\x12\x15\n\x10\x63\x61nRequestAccess\x10\x80\x04\x12\x15\n\x10\x63\x61nUpdateSetting\x10\x80\x08\x12\x13\n\x0e\x63\x61nListRecords\x10\x80\x10\x12\x13\n\x0e\x63\x61nListFolders\x10\x80 *\x9b\x01\n\x0e\x41\x63\x63\x65ssRoleType\x12\r\n\tNAVIGATOR\x10\x00\x12\r\n\tREQUESTOR\x10\x01\x12\n\n\x06VIEWER\x10\x02\x12\x12\n\x0eSHARED_MANAGER\x10\x03\x12\x13\n\x0f\x43ONTENT_MANAGER\x10\x04\x12\x19\n\x15\x43ONTENT_SHARE_MANAGER\x10\x05\x12\x0b\n\x07MANAGER\x10\x06\x12\x0e\n\nUNRESOLVED\x10\x07*z\n\nAccessType\x12\x0e\n\nAT_UNKNOWN\x10\x00\x12\x0c\n\x08\x41T_OWNER\x10\x01\x12\x0b\n\x07\x41T_USER\x10\x02\x12\x0b\n\x07\x41T_TEAM\x10\x03\x12\x11\n\rAT_ENTERPRISE\x10\x04\x12\r\n\tAT_FOLDER\x10\x05\x12\x12\n\x0e\x41T_APPLICATION\x10\x06*:\n\nObjectType\x12\x0e\n\nOT_UNKNOWN\x10\x00\x12\r\n\tOT_RECORD\x10\x01\x12\r\n\tOT_FOLDER\x10\x02\x42\"\n\x18\x63om.keepersecurity.protoB\x06\x46olderb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -38,28 +38,28 @@ _globals['_SHAREDFOLDERUPDATEUSER'].fields_by_name['sharedFolderKey']._serialized_options = b'\030\001' _globals['_SHAREDFOLDERUPDATETEAM'].fields_by_name['sharedFolderKey']._loaded_options = None _globals['_SHAREDFOLDERUPDATETEAM'].fields_by_name['sharedFolderKey']._serialized_options = b'\030\001' - _globals['_RECORDTYPE']._serialized_start=10143 - _globals['_RECORDTYPE']._serialized_end=10169 - _globals['_FOLDERTYPE']._serialized_start=10171 - _globals['_FOLDERTYPE']._serialized_end=10265 - _globals['_ENCRYPTEDKEYTYPE']._serialized_start=10268 - _globals['_ENCRYPTEDKEYTYPE']._serialized_end=10418 - _globals['_SETBOOLEANVALUE']._serialized_start=10420 - _globals['_SETBOOLEANVALUE']._serialized_end=10497 - _globals['_FOLDERUSAGETYPE']._serialized_start=10499 - _globals['_FOLDERUSAGETYPE']._serialized_end=10581 - _globals['_FOLDERKEYENCRYPTIONTYPE']._serialized_start=10583 - _globals['_FOLDERKEYENCRYPTIONTYPE']._serialized_end=10691 - _globals['_FOLDERMODIFYSTATUS']._serialized_start=10693 - _globals['_FOLDERMODIFYSTATUS']._serialized_end=10777 - _globals['_FOLDERPERMISSIONBITS']._serialized_start=10780 - _globals['_FOLDERPERMISSIONBITS']._serialized_end=11072 - _globals['_ACCESSROLETYPE']._serialized_start=11075 - _globals['_ACCESSROLETYPE']._serialized_end=11230 - _globals['_ACCESSTYPE']._serialized_start=11232 - _globals['_ACCESSTYPE']._serialized_end=11354 - _globals['_OBJECTTYPE']._serialized_start=11356 - _globals['_OBJECTTYPE']._serialized_end=11414 + _globals['_RECORDTYPE']._serialized_start=10181 + _globals['_RECORDTYPE']._serialized_end=10207 + _globals['_FOLDERTYPE']._serialized_start=10209 + _globals['_FOLDERTYPE']._serialized_end=10303 + _globals['_ENCRYPTEDKEYTYPE']._serialized_start=10306 + _globals['_ENCRYPTEDKEYTYPE']._serialized_end=10456 + _globals['_SETBOOLEANVALUE']._serialized_start=10458 + _globals['_SETBOOLEANVALUE']._serialized_end=10535 + _globals['_FOLDERUSAGETYPE']._serialized_start=10537 + _globals['_FOLDERUSAGETYPE']._serialized_end=10619 + _globals['_FOLDERKEYENCRYPTIONTYPE']._serialized_start=10621 + _globals['_FOLDERKEYENCRYPTIONTYPE']._serialized_end=10729 + _globals['_FOLDERMODIFYSTATUS']._serialized_start=10731 + _globals['_FOLDERMODIFYSTATUS']._serialized_end=10815 + _globals['_FOLDERPERMISSIONBITS']._serialized_start=10818 + _globals['_FOLDERPERMISSIONBITS']._serialized_end=11110 + _globals['_ACCESSROLETYPE']._serialized_start=11113 + _globals['_ACCESSROLETYPE']._serialized_end=11268 + _globals['_ACCESSTYPE']._serialized_start=11270 + _globals['_ACCESSTYPE']._serialized_end=11392 + _globals['_OBJECTTYPE']._serialized_start=11394 + _globals['_OBJECTTYPE']._serialized_end=11452 _globals['_ENCRYPTEDDATAKEY']._serialized_start=49 _globals['_ENCRYPTEDDATAKEY']._serialized_end=141 _globals['_SHAREDFOLDERRECORDDATA']._serialized_start=144 @@ -141,33 +141,33 @@ _globals['_FOLDERRECORDUPDATEREQUEST']._serialized_start=7479 _globals['_FOLDERRECORDUPDATEREQUEST']._serialized_end=7663 _globals['_RECORDMETADATA']._serialized_start=7666 - _globals['_RECORDMETADATA']._serialized_end=7837 - _globals['_FOLDERRECORD']._serialized_start=7840 - _globals['_FOLDERRECORD']._serialized_end=7987 - _globals['_FOLDERRECORDUPDATERESPONSE']._serialized_start=7989 - _globals['_FOLDERRECORDUPDATERESPONSE']._serialized_end=8104 - _globals['_FOLDERRECORDUPDATERESULT']._serialized_start=8106 - _globals['_FOLDERRECORDUPDATERESULT']._serialized_end=8212 - _globals['_FOLDERACCESSDATA']._serialized_start=8215 - _globals['_FOLDERACCESSDATA']._serialized_end=8606 - _globals['_REVOKEDACCESS']._serialized_start=8608 - _globals['_REVOKEDACCESS']._serialized_end=8700 - _globals['_FOLDERREMOVED']._serialized_start=8702 - _globals['_FOLDERREMOVED']._serialized_end=8737 - _globals['_RECORDACCESSDATA']._serialized_start=8740 - _globals['_RECORDACCESSDATA']._serialized_end=9271 - _globals['_ACCESSDATA']._serialized_start=9274 - _globals['_ACCESSDATA']._serialized_end=9458 - _globals['_FOLDERACCESSREQUEST']._serialized_start=9461 - _globals['_FOLDERACCESSREQUEST']._serialized_end=9644 - _globals['_FOLDERACCESSRESULT']._serialized_start=9647 - _globals['_FOLDERACCESSRESULT']._serialized_end=9806 - _globals['_FOLDERACCESSRESPONSE']._serialized_start=9808 - _globals['_FOLDERACCESSRESPONSE']._serialized_end=9887 - _globals['_USERINFO']._serialized_start=9889 - _globals['_USERINFO']._serialized_end=9937 - _globals['_RECORDDATA']._serialized_start=9939 - _globals['_RECORDDATA']._serialized_end=10016 - _globals['_RECORDKEY']._serialized_start=10018 - _globals['_RECORDKEY']._serialized_end=10141 + _globals['_RECORDMETADATA']._serialized_end=7875 + _globals['_FOLDERRECORD']._serialized_start=7878 + _globals['_FOLDERRECORD']._serialized_end=8025 + _globals['_FOLDERRECORDUPDATERESPONSE']._serialized_start=8027 + _globals['_FOLDERRECORDUPDATERESPONSE']._serialized_end=8142 + _globals['_FOLDERRECORDUPDATERESULT']._serialized_start=8144 + _globals['_FOLDERRECORDUPDATERESULT']._serialized_end=8250 + _globals['_FOLDERACCESSDATA']._serialized_start=8253 + _globals['_FOLDERACCESSDATA']._serialized_end=8644 + _globals['_REVOKEDACCESS']._serialized_start=8646 + _globals['_REVOKEDACCESS']._serialized_end=8738 + _globals['_FOLDERREMOVED']._serialized_start=8740 + _globals['_FOLDERREMOVED']._serialized_end=8775 + _globals['_RECORDACCESSDATA']._serialized_start=8778 + _globals['_RECORDACCESSDATA']._serialized_end=9309 + _globals['_ACCESSDATA']._serialized_start=9312 + _globals['_ACCESSDATA']._serialized_end=9496 + _globals['_FOLDERACCESSREQUEST']._serialized_start=9499 + _globals['_FOLDERACCESSREQUEST']._serialized_end=9682 + _globals['_FOLDERACCESSRESULT']._serialized_start=9685 + _globals['_FOLDERACCESSRESULT']._serialized_end=9844 + _globals['_FOLDERACCESSRESPONSE']._serialized_start=9846 + _globals['_FOLDERACCESSRESPONSE']._serialized_end=9925 + _globals['_USERINFO']._serialized_start=9927 + _globals['_USERINFO']._serialized_end=9975 + _globals['_RECORDDATA']._serialized_start=9977 + _globals['_RECORDDATA']._serialized_end=10054 + _globals['_RECORDKEY']._serialized_start=10056 + _globals['_RECORDKEY']._serialized_end=10179 # @@protoc_insertion_point(module_scope) diff --git a/keepercommander/proto/folder_pb2.pyi b/keepercommander/proto/folder_pb2.pyi index 57a857974..4e97bb0c2 100644 --- a/keepercommander/proto/folder_pb2.pyi +++ b/keepercommander/proto/folder_pb2.pyi @@ -243,7 +243,7 @@ class SharedFolderFields(_message.Message): manageRecords: bool canEdit: bool canShare: bool - def __init__(self, encryptedFolderName: _Optional[bytes] = ..., manageUsers: bool = ..., manageRecords: bool = ..., canEdit: bool = ..., canShare: bool = ...) -> None: ... + def __init__(self, encryptedFolderName: _Optional[bytes] = ..., manageUsers: _Optional[bool] = ..., manageRecords: _Optional[bool] = ..., canEdit: _Optional[bool] = ..., canShare: _Optional[bool] = ...) -> None: ... class SharedFolderFolderFields(_message.Message): __slots__ = ("sharedFolderUid",) @@ -317,7 +317,7 @@ class SharedFolderUpdateRecord(_message.Message): expiration: int timerNotificationType: _record_pb2.TimerNotificationType rotateOnExpiration: bool - def __init__(self, recordUid: _Optional[bytes] = ..., sharedFolderUid: _Optional[bytes] = ..., teamUid: _Optional[bytes] = ..., canEdit: _Optional[_Union[SetBooleanValue, str]] = ..., canShare: _Optional[_Union[SetBooleanValue, str]] = ..., encryptedRecordKey: _Optional[bytes] = ..., revision: _Optional[int] = ..., expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., rotateOnExpiration: bool = ...) -> None: ... + def __init__(self, recordUid: _Optional[bytes] = ..., sharedFolderUid: _Optional[bytes] = ..., teamUid: _Optional[bytes] = ..., canEdit: _Optional[_Union[SetBooleanValue, str]] = ..., canShare: _Optional[_Union[SetBooleanValue, str]] = ..., encryptedRecordKey: _Optional[bytes] = ..., revision: _Optional[int] = ..., expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., rotateOnExpiration: _Optional[bool] = ...) -> None: ... class SharedFolderUpdateUser(_message.Message): __slots__ = ("username", "manageUsers", "manageRecords", "sharedFolderKey", "expiration", "timerNotificationType", "typedSharedFolderKey", "rotateOnExpiration") @@ -337,7 +337,7 @@ class SharedFolderUpdateUser(_message.Message): timerNotificationType: _record_pb2.TimerNotificationType typedSharedFolderKey: EncryptedDataKey rotateOnExpiration: bool - def __init__(self, username: _Optional[str] = ..., manageUsers: _Optional[_Union[SetBooleanValue, str]] = ..., manageRecords: _Optional[_Union[SetBooleanValue, str]] = ..., sharedFolderKey: _Optional[bytes] = ..., expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., typedSharedFolderKey: _Optional[_Union[EncryptedDataKey, _Mapping]] = ..., rotateOnExpiration: bool = ...) -> None: ... + def __init__(self, username: _Optional[str] = ..., manageUsers: _Optional[_Union[SetBooleanValue, str]] = ..., manageRecords: _Optional[_Union[SetBooleanValue, str]] = ..., sharedFolderKey: _Optional[bytes] = ..., expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., typedSharedFolderKey: _Optional[_Union[EncryptedDataKey, _Mapping]] = ..., rotateOnExpiration: _Optional[bool] = ...) -> None: ... class SharedFolderUpdateTeam(_message.Message): __slots__ = ("teamUid", "manageUsers", "manageRecords", "sharedFolderKey", "expiration", "timerNotificationType", "typedSharedFolderKey", "rotateOnExpiration") @@ -357,7 +357,7 @@ class SharedFolderUpdateTeam(_message.Message): timerNotificationType: _record_pb2.TimerNotificationType typedSharedFolderKey: EncryptedDataKey rotateOnExpiration: bool - def __init__(self, teamUid: _Optional[bytes] = ..., manageUsers: bool = ..., manageRecords: bool = ..., sharedFolderKey: _Optional[bytes] = ..., expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., typedSharedFolderKey: _Optional[_Union[EncryptedDataKey, _Mapping]] = ..., rotateOnExpiration: bool = ...) -> None: ... + def __init__(self, teamUid: _Optional[bytes] = ..., manageUsers: _Optional[bool] = ..., manageRecords: _Optional[bool] = ..., sharedFolderKey: _Optional[bytes] = ..., expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[_record_pb2.TimerNotificationType, str]] = ..., typedSharedFolderKey: _Optional[_Union[EncryptedDataKey, _Mapping]] = ..., rotateOnExpiration: _Optional[bool] = ...) -> None: ... class SharedFolderUpdateV3Request(_message.Message): __slots__ = ("sharedFolderUpdateOperation_dont_use", "sharedFolderUid", "encryptedSharedFolderName", "revision", "forceUpdate", "fromTeamUid", "defaultManageUsers", "defaultManageRecords", "defaultCanEdit", "defaultCanShare", "sharedFolderAddRecord", "sharedFolderAddUser", "sharedFolderAddTeam", "sharedFolderUpdateRecord", "sharedFolderUpdateUser", "sharedFolderUpdateTeam", "sharedFolderRemoveRecord", "sharedFolderRemoveUser", "sharedFolderRemoveTeam", "sharedFolderOwner") @@ -401,7 +401,7 @@ class SharedFolderUpdateV3Request(_message.Message): sharedFolderRemoveUser: _containers.RepeatedScalarFieldContainer[str] sharedFolderRemoveTeam: _containers.RepeatedScalarFieldContainer[bytes] sharedFolderOwner: str - def __init__(self, sharedFolderUpdateOperation_dont_use: _Optional[int] = ..., sharedFolderUid: _Optional[bytes] = ..., encryptedSharedFolderName: _Optional[bytes] = ..., revision: _Optional[int] = ..., forceUpdate: bool = ..., fromTeamUid: _Optional[bytes] = ..., defaultManageUsers: _Optional[_Union[SetBooleanValue, str]] = ..., defaultManageRecords: _Optional[_Union[SetBooleanValue, str]] = ..., defaultCanEdit: _Optional[_Union[SetBooleanValue, str]] = ..., defaultCanShare: _Optional[_Union[SetBooleanValue, str]] = ..., sharedFolderAddRecord: _Optional[_Iterable[_Union[SharedFolderUpdateRecord, _Mapping]]] = ..., sharedFolderAddUser: _Optional[_Iterable[_Union[SharedFolderUpdateUser, _Mapping]]] = ..., sharedFolderAddTeam: _Optional[_Iterable[_Union[SharedFolderUpdateTeam, _Mapping]]] = ..., sharedFolderUpdateRecord: _Optional[_Iterable[_Union[SharedFolderUpdateRecord, _Mapping]]] = ..., sharedFolderUpdateUser: _Optional[_Iterable[_Union[SharedFolderUpdateUser, _Mapping]]] = ..., sharedFolderUpdateTeam: _Optional[_Iterable[_Union[SharedFolderUpdateTeam, _Mapping]]] = ..., sharedFolderRemoveRecord: _Optional[_Iterable[bytes]] = ..., sharedFolderRemoveUser: _Optional[_Iterable[str]] = ..., sharedFolderRemoveTeam: _Optional[_Iterable[bytes]] = ..., sharedFolderOwner: _Optional[str] = ...) -> None: ... + def __init__(self, sharedFolderUpdateOperation_dont_use: _Optional[int] = ..., sharedFolderUid: _Optional[bytes] = ..., encryptedSharedFolderName: _Optional[bytes] = ..., revision: _Optional[int] = ..., forceUpdate: _Optional[bool] = ..., fromTeamUid: _Optional[bytes] = ..., defaultManageUsers: _Optional[_Union[SetBooleanValue, str]] = ..., defaultManageRecords: _Optional[_Union[SetBooleanValue, str]] = ..., defaultCanEdit: _Optional[_Union[SetBooleanValue, str]] = ..., defaultCanShare: _Optional[_Union[SetBooleanValue, str]] = ..., sharedFolderAddRecord: _Optional[_Iterable[_Union[SharedFolderUpdateRecord, _Mapping]]] = ..., sharedFolderAddUser: _Optional[_Iterable[_Union[SharedFolderUpdateUser, _Mapping]]] = ..., sharedFolderAddTeam: _Optional[_Iterable[_Union[SharedFolderUpdateTeam, _Mapping]]] = ..., sharedFolderUpdateRecord: _Optional[_Iterable[_Union[SharedFolderUpdateRecord, _Mapping]]] = ..., sharedFolderUpdateUser: _Optional[_Iterable[_Union[SharedFolderUpdateUser, _Mapping]]] = ..., sharedFolderUpdateTeam: _Optional[_Iterable[_Union[SharedFolderUpdateTeam, _Mapping]]] = ..., sharedFolderRemoveRecord: _Optional[_Iterable[bytes]] = ..., sharedFolderRemoveUser: _Optional[_Iterable[str]] = ..., sharedFolderRemoveTeam: _Optional[_Iterable[bytes]] = ..., sharedFolderOwner: _Optional[str] = ...) -> None: ... class SharedFolderUpdateV3RequestV2(_message.Message): __slots__ = ("sharedFoldersUpdateV3",) @@ -649,7 +649,7 @@ class FolderPermissions(_message.Message): canUpdateSetting: bool canListRecords: bool canListFolders: bool - def __init__(self, canAdd: bool = ..., canRemove: bool = ..., canDelete: bool = ..., canListAccess: bool = ..., canUpdateAccess: bool = ..., canChangeOwnership: bool = ..., canEditRecords: bool = ..., canViewRecords: bool = ..., canApproveAccess: bool = ..., canRequestAccess: bool = ..., canUpdateSetting: bool = ..., canListRecords: bool = ..., canListFolders: bool = ...) -> None: ... + def __init__(self, canAdd: _Optional[bool] = ..., canRemove: _Optional[bool] = ..., canDelete: _Optional[bool] = ..., canListAccess: _Optional[bool] = ..., canUpdateAccess: _Optional[bool] = ..., canChangeOwnership: _Optional[bool] = ..., canEditRecords: _Optional[bool] = ..., canViewRecords: _Optional[bool] = ..., canApproveAccess: _Optional[bool] = ..., canRequestAccess: _Optional[bool] = ..., canUpdateSetting: _Optional[bool] = ..., canListRecords: _Optional[bool] = ..., canListFolders: _Optional[bool] = ...) -> None: ... class Capabilities(_message.Message): __slots__ = ("canAdd", "canRemove", "canDelete", "canListAccess", "canUpdateAccess", "canChangeOwnership", "canEditRecords", "canViewRecords", "canApproveAccess", "canRequestAccess", "canUpdateSetting", "canListRecords", "canListFolders") @@ -694,16 +694,18 @@ class FolderRecordUpdateRequest(_message.Message): def __init__(self, folderUid: _Optional[bytes] = ..., addRecords: _Optional[_Iterable[_Union[RecordMetadata, _Mapping]]] = ..., updateRecords: _Optional[_Iterable[_Union[RecordMetadata, _Mapping]]] = ..., removeRecords: _Optional[_Iterable[_Union[RecordMetadata, _Mapping]]] = ...) -> None: ... class RecordMetadata(_message.Message): - __slots__ = ("recordUid", "encryptedRecordKey", "encryptedRecordKeyType", "tlaProperties") + __slots__ = ("recordUid", "encryptedRecordKey", "encryptedRecordKeyType", "tlaProperties", "recordKeyEncryptedByOwnerKey") RECORDUID_FIELD_NUMBER: _ClassVar[int] ENCRYPTEDRECORDKEY_FIELD_NUMBER: _ClassVar[int] ENCRYPTEDRECORDKEYTYPE_FIELD_NUMBER: _ClassVar[int] TLAPROPERTIES_FIELD_NUMBER: _ClassVar[int] + RECORDKEYENCRYPTEDBYOWNERKEY_FIELD_NUMBER: _ClassVar[int] recordUid: bytes encryptedRecordKey: bytes encryptedRecordKeyType: EncryptedKeyType tlaProperties: _tla_pb2.TLAProperties - def __init__(self, recordUid: _Optional[bytes] = ..., encryptedRecordKey: _Optional[bytes] = ..., encryptedRecordKeyType: _Optional[_Union[EncryptedKeyType, str]] = ..., tlaProperties: _Optional[_Union[_tla_pb2.TLAProperties, _Mapping]] = ...) -> None: ... + recordKeyEncryptedByOwnerKey: bytes + def __init__(self, recordUid: _Optional[bytes] = ..., encryptedRecordKey: _Optional[bytes] = ..., encryptedRecordKeyType: _Optional[_Union[EncryptedKeyType, str]] = ..., tlaProperties: _Optional[_Union[_tla_pb2.TLAProperties, _Mapping]] = ..., recordKeyEncryptedByOwnerKey: _Optional[bytes] = ...) -> None: ... class FolderRecord(_message.Message): __slots__ = ("folderUid", "recordMetadata", "folderKeyEncryptionType") @@ -759,7 +761,7 @@ class FolderAccessData(_message.Message): dateCreated: int lastModified: int deniedAccess: bool - def __init__(self, folderUid: _Optional[bytes] = ..., accessTypeUid: _Optional[bytes] = ..., accessType: _Optional[_Union[AccessType, str]] = ..., accessRoleType: _Optional[_Union[AccessRoleType, str]] = ..., folderKey: _Optional[_Union[EncryptedDataKey, _Mapping]] = ..., inherited: bool = ..., hidden: bool = ..., permissions: _Optional[_Union[FolderPermissions, _Mapping]] = ..., tlaProperties: _Optional[_Union[_tla_pb2.TLAProperties, _Mapping]] = ..., dateCreated: _Optional[int] = ..., lastModified: _Optional[int] = ..., deniedAccess: bool = ...) -> None: ... + def __init__(self, folderUid: _Optional[bytes] = ..., accessTypeUid: _Optional[bytes] = ..., accessType: _Optional[_Union[AccessType, str]] = ..., accessRoleType: _Optional[_Union[AccessRoleType, str]] = ..., folderKey: _Optional[_Union[EncryptedDataKey, _Mapping]] = ..., inherited: _Optional[bool] = ..., hidden: _Optional[bool] = ..., permissions: _Optional[_Union[FolderPermissions, _Mapping]] = ..., tlaProperties: _Optional[_Union[_tla_pb2.TLAProperties, _Mapping]] = ..., dateCreated: _Optional[int] = ..., lastModified: _Optional[int] = ..., deniedAccess: _Optional[bool] = ...) -> None: ... class RevokedAccess(_message.Message): __slots__ = ("folderUid", "actorUid", "accessType") @@ -819,7 +821,7 @@ class RecordAccessData(_message.Message): dateCreated: int lastModified: int tlaProperties: _tla_pb2.TLAProperties - def __init__(self, accessTypeUid: _Optional[bytes] = ..., accessType: _Optional[_Union[AccessType, str]] = ..., recordUid: _Optional[bytes] = ..., accessRoleType: _Optional[_Union[AccessRoleType, str]] = ..., owner: bool = ..., inherited: bool = ..., hidden: bool = ..., deniedAccess: bool = ..., can_view_title: bool = ..., can_edit: bool = ..., can_view: bool = ..., can_list_access: bool = ..., can_update_access: bool = ..., can_delete: bool = ..., can_change_ownership: bool = ..., can_request_access: bool = ..., can_approve_access: bool = ..., dateCreated: _Optional[int] = ..., lastModified: _Optional[int] = ..., tlaProperties: _Optional[_Union[_tla_pb2.TLAProperties, _Mapping]] = ...) -> None: ... + def __init__(self, accessTypeUid: _Optional[bytes] = ..., accessType: _Optional[_Union[AccessType, str]] = ..., recordUid: _Optional[bytes] = ..., accessRoleType: _Optional[_Union[AccessRoleType, str]] = ..., owner: _Optional[bool] = ..., inherited: _Optional[bool] = ..., hidden: _Optional[bool] = ..., deniedAccess: _Optional[bool] = ..., can_view_title: _Optional[bool] = ..., can_edit: _Optional[bool] = ..., can_view: _Optional[bool] = ..., can_list_access: _Optional[bool] = ..., can_update_access: _Optional[bool] = ..., can_delete: _Optional[bool] = ..., can_change_ownership: _Optional[bool] = ..., can_request_access: _Optional[bool] = ..., can_approve_access: _Optional[bool] = ..., dateCreated: _Optional[int] = ..., lastModified: _Optional[int] = ..., tlaProperties: _Optional[_Union[_tla_pb2.TLAProperties, _Mapping]] = ...) -> None: ... class AccessData(_message.Message): __slots__ = ("accessTypeUid", "accessRoleType", "deniedAccess", "inherited", "hidden", "capabilities") @@ -835,7 +837,7 @@ class AccessData(_message.Message): inherited: bool hidden: bool capabilities: Capabilities - def __init__(self, accessTypeUid: _Optional[bytes] = ..., accessRoleType: _Optional[_Union[AccessRoleType, str]] = ..., deniedAccess: bool = ..., inherited: bool = ..., hidden: bool = ..., capabilities: _Optional[_Union[Capabilities, _Mapping]] = ...) -> None: ... + def __init__(self, accessTypeUid: _Optional[bytes] = ..., accessRoleType: _Optional[_Union[AccessRoleType, str]] = ..., deniedAccess: _Optional[bool] = ..., inherited: _Optional[bool] = ..., hidden: _Optional[bool] = ..., capabilities: _Optional[_Union[Capabilities, _Mapping]] = ...) -> None: ... class FolderAccessRequest(_message.Message): __slots__ = ("folderAccessAdds", "folderAccessUpdates", "folderAccessRemoves") diff --git a/keepercommander/proto/pagination_pb2.pyi b/keepercommander/proto/pagination_pb2.pyi index bb7a09bfb..08c2e73a5 100644 --- a/keepercommander/proto/pagination_pb2.pyi +++ b/keepercommander/proto/pagination_pb2.pyi @@ -26,4 +26,4 @@ class PageInfo(_message.Message): totalCount: int hasMore: bool cursorToken: str - def __init__(self, pageNumber: _Optional[int] = ..., pageSize: _Optional[int] = ..., totalCount: _Optional[int] = ..., hasMore: bool = ..., cursorToken: _Optional[str] = ...) -> None: ... + def __init__(self, pageNumber: _Optional[int] = ..., pageSize: _Optional[int] = ..., totalCount: _Optional[int] = ..., hasMore: _Optional[bool] = ..., cursorToken: _Optional[str] = ...) -> None: ... diff --git a/keepercommander/proto/record_endpoints_pb2.py b/keepercommander/proto/record_endpoints_pb2.py index 55cbe6d3b..a33789aec 100644 --- a/keepercommander/proto/record_endpoints_pb2.py +++ b/keepercommander/proto/record_endpoints_pb2.py @@ -26,7 +26,7 @@ from . import folder_pb2 as folder__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16record_endpoints.proto\x12\trecord.v3\x1a\x0crecord.proto\x1a\x0c\x66older.proto\"\x83\x01\n\x11RecordsAddRequest\x12%\n\x07records\x18\x01 \x03(\x0b\x32\x14.record.v3.RecordAdd\x12\x12\n\nclientTime\x18\x02 \x01(\x03\x12\x33\n\x13securityDataKeyType\x18\x03 \x01(\x0e\x32\x16.Records.RecordKeyType\"\xa8\x03\n\tRecordAdd\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x11\n\trecordKey\x18\x02 \x01(\x0c\x12/\n\rrecordKeyType\x18\x03 \x01(\x0e\x32\x18.Folder.EncryptedKeyType\x12=\n\x14recordKeyEncryptedBy\x18\x04 \x01(\x0e\x32\x1f.Folder.FolderKeyEncryptionType\x12\x1a\n\x12\x63lientModifiedTime\x18\x05 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x06 \x01(\x0c\x12\x15\n\rnonSharedData\x18\x07 \x01(\x0c\x12\x11\n\tfolderUid\x18\x08 \x01(\x0c\x12(\n\x0brecordLinks\x18\t \x03(\x0b\x32\x13.Records.RecordLink\x12#\n\x05\x61udit\x18\n \x01(\x0b\x32\x14.Records.RecordAudit\x12+\n\x0csecurityData\x18\x0b \x01(\x0b\x32\x15.Records.SecurityData\x12\x35\n\x11securityScoreData\x18\x0c \x01(\x0b\x32\x1a.Records.SecurityScoreDataB*\n&com.keepersecurity.proto.api.record.v3P\x01\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16record_endpoints.proto\x12\trecord.v3\x1a\x0crecord.proto\x1a\x0c\x66older.proto\"\x83\x01\n\x11RecordsAddRequest\x12%\n\x07records\x18\x01 \x03(\x0b\x32\x14.record.v3.RecordAdd\x12\x12\n\nclientTime\x18\x02 \x01(\x03\x12\x33\n\x13securityDataKeyType\x18\x03 \x01(\x0e\x32\x16.Records.RecordKeyType\"\xce\x03\n\tRecordAdd\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x11\n\trecordKey\x18\x02 \x01(\x0c\x12/\n\rrecordKeyType\x18\x03 \x01(\x0e\x32\x18.Folder.EncryptedKeyType\x12=\n\x14recordKeyEncryptedBy\x18\x04 \x01(\x0e\x32\x1f.Folder.FolderKeyEncryptionType\x12\x1a\n\x12\x63lientModifiedTime\x18\x05 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x06 \x01(\x0c\x12\x15\n\rnonSharedData\x18\x07 \x01(\x0c\x12\x11\n\tfolderUid\x18\x08 \x01(\x0c\x12(\n\x0brecordLinks\x18\t \x03(\x0b\x32\x13.Records.RecordLink\x12#\n\x05\x61udit\x18\n \x01(\x0b\x32\x14.Records.RecordAudit\x12+\n\x0csecurityData\x18\x0b \x01(\x0b\x32\x15.Records.SecurityData\x12\x35\n\x11securityScoreData\x18\x0c \x01(\x0b\x32\x1a.Records.SecurityScoreData\x12$\n\x1crecordKeyEncryptedByOwnerKey\x18\r \x01(\x0c\x42*\n&com.keepersecurity.proto.api.record.v3P\x01\x62\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -37,5 +37,5 @@ _globals['_RECORDSADDREQUEST']._serialized_start=66 _globals['_RECORDSADDREQUEST']._serialized_end=197 _globals['_RECORDADD']._serialized_start=200 - _globals['_RECORDADD']._serialized_end=624 + _globals['_RECORDADD']._serialized_end=662 # @@protoc_insertion_point(module_scope) diff --git a/keepercommander/proto/record_endpoints_pb2.pyi b/keepercommander/proto/record_endpoints_pb2.pyi index a79e7e9c4..d52d8c60a 100644 --- a/keepercommander/proto/record_endpoints_pb2.pyi +++ b/keepercommander/proto/record_endpoints_pb2.pyi @@ -18,7 +18,7 @@ class RecordsAddRequest(_message.Message): def __init__(self, records: _Optional[_Iterable[_Union[RecordAdd, _Mapping]]] = ..., clientTime: _Optional[int] = ..., securityDataKeyType: _Optional[_Union[_record_pb2.RecordKeyType, str]] = ...) -> None: ... class RecordAdd(_message.Message): - __slots__ = ("recordUid", "recordKey", "recordKeyType", "recordKeyEncryptedBy", "clientModifiedTime", "data", "nonSharedData", "folderUid", "recordLinks", "audit", "securityData", "securityScoreData") + __slots__ = ("recordUid", "recordKey", "recordKeyType", "recordKeyEncryptedBy", "clientModifiedTime", "data", "nonSharedData", "folderUid", "recordLinks", "audit", "securityData", "securityScoreData", "recordKeyEncryptedByOwnerKey") RECORDUID_FIELD_NUMBER: _ClassVar[int] RECORDKEY_FIELD_NUMBER: _ClassVar[int] RECORDKEYTYPE_FIELD_NUMBER: _ClassVar[int] @@ -31,6 +31,7 @@ class RecordAdd(_message.Message): AUDIT_FIELD_NUMBER: _ClassVar[int] SECURITYDATA_FIELD_NUMBER: _ClassVar[int] SECURITYSCOREDATA_FIELD_NUMBER: _ClassVar[int] + RECORDKEYENCRYPTEDBYOWNERKEY_FIELD_NUMBER: _ClassVar[int] recordUid: bytes recordKey: bytes recordKeyType: _folder_pb2.EncryptedKeyType @@ -43,4 +44,5 @@ class RecordAdd(_message.Message): audit: _record_pb2.RecordAudit securityData: _record_pb2.SecurityData securityScoreData: _record_pb2.SecurityScoreData - def __init__(self, recordUid: _Optional[bytes] = ..., recordKey: _Optional[bytes] = ..., recordKeyType: _Optional[_Union[_folder_pb2.EncryptedKeyType, str]] = ..., recordKeyEncryptedBy: _Optional[_Union[_folder_pb2.FolderKeyEncryptionType, str]] = ..., clientModifiedTime: _Optional[int] = ..., data: _Optional[bytes] = ..., nonSharedData: _Optional[bytes] = ..., folderUid: _Optional[bytes] = ..., recordLinks: _Optional[_Iterable[_Union[_record_pb2.RecordLink, _Mapping]]] = ..., audit: _Optional[_Union[_record_pb2.RecordAudit, _Mapping]] = ..., securityData: _Optional[_Union[_record_pb2.SecurityData, _Mapping]] = ..., securityScoreData: _Optional[_Union[_record_pb2.SecurityScoreData, _Mapping]] = ...) -> None: ... + recordKeyEncryptedByOwnerKey: bytes + def __init__(self, recordUid: _Optional[bytes] = ..., recordKey: _Optional[bytes] = ..., recordKeyType: _Optional[_Union[_folder_pb2.EncryptedKeyType, str]] = ..., recordKeyEncryptedBy: _Optional[_Union[_folder_pb2.FolderKeyEncryptionType, str]] = ..., clientModifiedTime: _Optional[int] = ..., data: _Optional[bytes] = ..., nonSharedData: _Optional[bytes] = ..., folderUid: _Optional[bytes] = ..., recordLinks: _Optional[_Iterable[_Union[_record_pb2.RecordLink, _Mapping]]] = ..., audit: _Optional[_Union[_record_pb2.RecordAudit, _Mapping]] = ..., securityData: _Optional[_Union[_record_pb2.SecurityData, _Mapping]] = ..., securityScoreData: _Optional[_Union[_record_pb2.SecurityScoreData, _Mapping]] = ..., recordKeyEncryptedByOwnerKey: _Optional[bytes] = ...) -> None: ... diff --git a/keepercommander/proto/record_pb2.py b/keepercommander/proto/record_pb2.py index 6fb04617e..0f4ac5822 100644 --- a/keepercommander/proto/record_pb2.py +++ b/keepercommander/proto/record_pb2.py @@ -24,7 +24,7 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0crecord.proto\x12\x07Records\"\\\n\nRecordType\x12\x14\n\x0crecordTypeId\x18\x01 \x01(\x05\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\'\n\x05scope\x18\x03 \x01(\x0e\x32\x18.Records.RecordTypeScope\"U\n\x12RecordTypesRequest\x12\x10\n\x08standard\x18\x01 \x01(\x08\x12\x0c\n\x04user\x18\x02 \x01(\x08\x12\x12\n\nenterprise\x18\x03 \x01(\x08\x12\x0b\n\x03pam\x18\x04 \x01(\x08\"\x9c\x01\n\x13RecordTypesResponse\x12(\n\x0brecordTypes\x18\x01 \x03(\x0b\x32\x13.Records.RecordType\x12\x17\n\x0fstandardCounter\x18\x02 \x01(\x05\x12\x13\n\x0buserCounter\x18\x03 \x01(\x05\x12\x19\n\x11\x65nterpriseCounter\x18\x04 \x01(\x05\x12\x12\n\npamCounter\x18\x05 \x01(\x05\"A\n\x18RecordTypeModifyResponse\x12\x14\n\x0crecordTypeId\x18\x01 \x01(\x05\x12\x0f\n\x07\x63ounter\x18\x02 \x01(\x05\"=\n\x11RecordsGetRequest\x12\x13\n\x0brecord_uids\x18\x01 \x03(\x0c\x12\x13\n\x0b\x63lient_time\x18\x02 \x01(\x03\"\xd1\x01\n\x06Record\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_key\x18\x02 \x01(\x0c\x12/\n\x0frecord_key_type\x18\x03 \x01(\x0e\x32\x16.Records.RecordKeyType\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\r\n\x05\x65xtra\x18\x05 \x01(\x0c\x12\x0f\n\x07version\x18\x06 \x01(\x05\x12\x1c\n\x14\x63lient_modified_time\x18\x07 \x01(\x03\x12\x10\n\x08revision\x18\x08 \x01(\x03\x12\x10\n\x08\x66ile_ids\x18\t \x03(\x0c\"M\n\x0f\x46olderRecordKey\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_uid\x18\x02 \x01(\x0c\x12\x12\n\nrecord_key\x18\x03 \x01(\x0c\"a\n\x06\x46older\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x12\n\nfolder_key\x18\x02 \x01(\x0c\x12/\n\x0f\x66older_key_type\x18\x03 \x01(\x0e\x32\x16.Records.RecordKeyType\"\x95\x01\n\x04Team\x12\x10\n\x08team_uid\x18\x01 \x01(\x0c\x12\x10\n\x08team_key\x18\x02 \x01(\x0c\x12\x18\n\x10team_private_key\x18\x03 \x01(\x0c\x12-\n\rteam_key_type\x18\x04 \x01(\x0e\x32\x16.Records.RecordKeyType\x12 \n\x07\x66olders\x18\x05 \x03(\x0b\x32\x0f.Records.Folder\"\xac\x01\n\x12RecordsGetResponse\x12 \n\x07records\x18\x01 \x03(\x0b\x32\x0f.Records.Record\x12\x34\n\x12\x66older_record_keys\x18\x02 \x03(\x0b\x32\x18.Records.FolderRecordKey\x12 \n\x07\x66olders\x18\x03 \x03(\x0b\x32\x0f.Records.Folder\x12\x1c\n\x05teams\x18\x04 \x03(\x0b\x32\r.Records.Team\"4\n\nRecordLink\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_key\x18\x02 \x01(\x0c\",\n\x0bRecordAudit\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"\x1c\n\x0cSecurityData\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"!\n\x11SecurityScoreData\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\x84\x03\n\tRecordAdd\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_key\x18\x02 \x01(\x0c\x12\x1c\n\x14\x63lient_modified_time\x18\x03 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x17\n\x0fnon_shared_data\x18\x05 \x01(\x0c\x12.\n\x0b\x66older_type\x18\x06 \x01(\x0e\x32\x19.Records.RecordFolderType\x12\x12\n\nfolder_uid\x18\x07 \x01(\x0c\x12\x12\n\nfolder_key\x18\x08 \x01(\x0c\x12)\n\x0crecord_links\x18\t \x03(\x0b\x32\x13.Records.RecordLink\x12#\n\x05\x61udit\x18\n \x01(\x0b\x32\x14.Records.RecordAudit\x12+\n\x0csecurityData\x18\x0b \x01(\x0b\x32\x15.Records.SecurityData\x12\x35\n\x11securityScoreData\x18\x0c \x01(\x0b\x32\x1a.Records.SecurityScoreData\"\x85\x01\n\x11RecordsAddRequest\x12#\n\x07records\x18\x01 \x03(\x0b\x32\x12.Records.RecordAdd\x12\x13\n\x0b\x63lient_time\x18\x02 \x01(\x03\x12\x36\n\x16security_data_key_type\x18\x03 \x01(\x0e\x32\x16.Records.RecordKeyType\"\xce\x02\n\x0cRecordUpdate\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x1c\n\x14\x63lient_modified_time\x18\x02 \x01(\x03\x12\x10\n\x08revision\x18\x03 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x17\n\x0fnon_shared_data\x18\x05 \x01(\x0c\x12-\n\x10record_links_add\x18\x06 \x03(\x0b\x32\x13.Records.RecordLink\x12\x1b\n\x13record_links_remove\x18\x07 \x03(\x0c\x12#\n\x05\x61udit\x18\x08 \x01(\x0b\x32\x14.Records.RecordAudit\x12+\n\x0csecurityData\x18\t \x01(\x0b\x32\x15.Records.SecurityData\x12\x35\n\x11securityScoreData\x18\n \x01(\x0b\x32\x1a.Records.SecurityScoreData\"\x8b\x01\n\x14RecordsUpdateRequest\x12&\n\x07records\x18\x01 \x03(\x0b\x32\x15.Records.RecordUpdate\x12\x13\n\x0b\x63lient_time\x18\x02 \x01(\x03\x12\x36\n\x16security_data_key_type\x18\x03 \x01(\x0e\x32\x16.Records.RecordKeyType\"\x8e\x01\n\x17RecordFileForConversion\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x14\n\x0c\x66ile_file_id\x18\x02 \x01(\t\x12\x15\n\rthumb_file_id\x18\x03 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x12\n\nrecord_key\x18\x05 \x01(\x0c\x12\x10\n\x08link_key\x18\x06 \x01(\x0c\"J\n\x19RecordFolderForConversion\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x19\n\x11record_folder_key\x18\x02 \x01(\x0c\"\x92\x02\n\x11RecordConvertToV3\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x1c\n\x14\x63lient_modified_time\x18\x02 \x01(\x03\x12\x10\n\x08revision\x18\x03 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x17\n\x0fnon_shared_data\x18\x05 \x01(\x0c\x12#\n\x05\x61udit\x18\x06 \x01(\x0b\x32\x14.Records.RecordAudit\x12\x35\n\x0brecord_file\x18\x07 \x03(\x0b\x32 .Records.RecordFileForConversion\x12\x36\n\nfolder_key\x18\x08 \x03(\x0b\x32\".Records.RecordFolderForConversion\"]\n\x19RecordsConvertToV3Request\x12+\n\x07records\x18\x01 \x03(\x0b\x32\x1a.Records.RecordConvertToV3\x12\x13\n\x0b\x63lient_time\x18\x02 \x01(\x03\"\'\n\x14RecordsRemoveRequest\x12\x0f\n\x07records\x18\x01 \x03(\x0c\">\n\x0cRecordRevert\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x1a\n\x12revert_to_revision\x18\x02 \x01(\x03\">\n\x14RecordsRevertRequest\x12&\n\x07records\x18\x01 \x03(\x0b\x32\x15.Records.RecordRevert\"c\n\x0fRecordLinkError\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12+\n\x06status\x18\x02 \x01(\x0e\x32\x1b.Records.RecordModifyResult\x12\x0f\n\x07message\x18\x03 \x01(\t\"\x95\x01\n\x12RecordModifyStatus\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12+\n\x06status\x18\x02 \x01(\x0e\x32\x1b.Records.RecordModifyResult\x12\x0f\n\x07message\x18\x03 \x01(\t\x12-\n\x0blink_errors\x18\x04 \x03(\x0b\x32\x18.Records.RecordLinkError\"W\n\x15RecordsModifyResponse\x12,\n\x07records\x18\x01 \x03(\x0b\x32\x1b.Records.RecordModifyStatus\x12\x10\n\x08revision\x18\x02 \x01(\x03\"Y\n\x12RecordAddAuditData\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x10\n\x08revision\x18\x02 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\x0f\n\x07version\x18\x04 \x01(\x05\"C\n\x13\x41\x64\x64\x41uditDataRequest\x12,\n\x07records\x18\x01 \x03(\x0b\x32\x1b.Records.RecordAddAuditData\"t\n\x04\x46ile\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_key\x18\x02 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\x10\n\x08\x66ileSize\x18\x04 \x01(\x03\x12\x11\n\tthumbSize\x18\x05 \x01(\x05\x12\x11\n\tis_script\x18\x06 \x01(\x08\"D\n\x0f\x46ilesAddRequest\x12\x1c\n\x05\x66iles\x18\x01 \x03(\x0b\x32\r.Records.File\x12\x13\n\x0b\x63lient_time\x18\x02 \x01(\x03\"\xa7\x01\n\rFileAddStatus\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12&\n\x06status\x18\x02 \x01(\x0e\x32\x16.Records.FileAddResult\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\x12\n\nparameters\x18\x04 \x01(\t\x12\x1c\n\x14thumbnail_parameters\x18\x05 \x01(\t\x12\x1b\n\x13success_status_code\x18\x06 \x01(\x05\"K\n\x10\x46ilesAddResponse\x12%\n\x05\x66iles\x18\x01 \x03(\x0b\x32\x16.Records.FileAddStatus\x12\x10\n\x08revision\x18\x02 \x01(\x03\"f\n\x0f\x46ilesGetRequest\x12\x13\n\x0brecord_uids\x18\x01 \x03(\x0c\x12\x16\n\x0e\x66or_thumbnails\x18\x02 \x01(\x08\x12&\n\x1e\x65mergency_access_account_owner\x18\x03 \x01(\t\"\xa2\x01\n\rFileGetStatus\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12&\n\x06status\x18\x02 \x01(\x0e\x32\x16.Records.FileGetResult\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\x1b\n\x13success_status_code\x18\x04 \x01(\x05\x12+\n\x0b\x66ileKeyType\x18\x05 \x01(\x0e\x32\x16.Records.RecordKeyType\"9\n\x10\x46ilesGetResponse\x12%\n\x05\x66iles\x18\x01 \x03(\x0b\x32\x16.Records.FileGetStatus\"\x8d\x01\n\x15\x41pplicationAddRequest\x12\x0f\n\x07\x61pp_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_key\x18\x02 \x01(\x0c\x12\x1c\n\x14\x63lient_modified_time\x18\x03 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12#\n\x05\x61udit\x18\x05 \x01(\x0b\x32\x14.Records.RecordAudit\"\x88\x01\n\"GetRecordDataWithAccessInfoRequest\x12\x12\n\nclientTime\x18\x01 \x01(\x03\x12\x11\n\trecordUid\x18\x02 \x03(\x0c\x12;\n\x14recordDetailsInclude\x18\x03 \x01(\x0e\x32\x1d.Records.RecordDetailsInclude\"\x86\x02\n\x0eUserPermission\x12\x10\n\x08username\x18\x01 \x01(\t\x12\r\n\x05owner\x18\x02 \x01(\x08\x12\x12\n\nshareAdmin\x18\x03 \x01(\x08\x12\x10\n\x08sharable\x18\x04 \x01(\x08\x12\x10\n\x08\x65\x64itable\x18\x05 \x01(\x08\x12\x18\n\x10\x61waitingApproval\x18\x06 \x01(\x08\x12\x12\n\nexpiration\x18\x07 \x01(\x03\x12\x12\n\naccountUid\x18\x08 \x01(\x0c\x12=\n\x15timerNotificationType\x18\t \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x1a\n\x12rotateOnExpiration\x18\n \x01(\x08\"\xd8\x01\n\x16SharedFolderPermission\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x12\n\nresharable\x18\x02 \x01(\x08\x12\x10\n\x08\x65\x64itable\x18\x03 \x01(\x08\x12\x10\n\x08revision\x18\x04 \x01(\x03\x12\x12\n\nexpiration\x18\x05 \x01(\x03\x12=\n\x15timerNotificationType\x18\x06 \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x1a\n\x12rotateOnExpiration\x18\x07 \x01(\x08\"\xe8\x02\n\nRecordData\x12\x10\n\x08revision\x18\x01 \x01(\x03\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12\x0e\n\x06shared\x18\x03 \x01(\x08\x12\x1b\n\x13\x65ncryptedRecordData\x18\x04 \x01(\t\x12\x1a\n\x12\x65ncryptedExtraData\x18\x05 \x01(\t\x12\x1a\n\x12\x63lientModifiedTime\x18\x06 \x01(\x03\x12\x15\n\rnonSharedData\x18\x07 \x01(\t\x12-\n\x10linkedRecordData\x18\x08 \x03(\x0b\x32\x13.Records.RecordData\x12\x0e\n\x06\x66ileId\x18\t \x03(\x0c\x12\x10\n\x08\x66ileSize\x18\n \x01(\x03\x12\x15\n\rthumbnailSize\x18\x0b \x01(\x03\x12-\n\rrecordKeyType\x18\x0c \x01(\x0e\x32\x16.Records.RecordKeyType\x12\x11\n\trecordKey\x18\r \x01(\x0c\x12\x11\n\trecordUid\x18\x0e \x01(\x0c\"\xc8\x01\n\x18RecordDataWithAccessInfo\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\'\n\nrecordData\x18\x02 \x01(\x0b\x32\x13.Records.RecordData\x12/\n\x0euserPermission\x18\x03 \x03(\x0b\x32\x17.Records.UserPermission\x12?\n\x16sharedFolderPermission\x18\x04 \x03(\x0b\x32\x1f.Records.SharedFolderPermission\"\x89\x01\n#GetRecordDataWithAccessInfoResponse\x12\x43\n\x18recordDataWithAccessInfo\x18\x01 \x03(\x0b\x32!.Records.RecordDataWithAccessInfo\x12\x1d\n\x15noPermissionRecordUid\x18\x02 \x03(\x0c\"j\n\x12IsObjectShareAdmin\x12\x0b\n\x03uid\x18\x01 \x01(\x0c\x12\x0f\n\x07isAdmin\x18\x02 \x01(\x08\x12\x36\n\nobjectType\x18\x03 \x01(\x0e\x32\".Records.CheckShareAdminObjectType\"H\n\rAmIShareAdmin\x12\x37\n\x12isObjectShareAdmin\x18\x01 \x03(\x0b\x32\x1b.Records.IsObjectShareAdmin\"\xbc\x01\n\x18RecordShareUpdateRequest\x12.\n\x0f\x61\x64\x64SharedRecord\x18\x01 \x03(\x0b\x32\x15.Records.SharedRecord\x12\x31\n\x12updateSharedRecord\x18\x02 \x03(\x0b\x32\x15.Records.SharedRecord\x12\x31\n\x12removeSharedRecord\x18\x03 \x03(\x0b\x32\x15.Records.SharedRecord\x12\n\n\x02pt\x18\x04 \x01(\t\"\xc4\x02\n\x0cSharedRecord\x12\x12\n\ntoUsername\x18\x01 \x01(\t\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x11\n\trecordKey\x18\x03 \x01(\x0c\x12\x17\n\x0fsharedFolderUid\x18\x04 \x01(\x0c\x12\x0f\n\x07teamUid\x18\x05 \x01(\x0c\x12\x10\n\x08\x65\x64itable\x18\x06 \x01(\x08\x12\x11\n\tshareable\x18\x07 \x01(\x08\x12\x10\n\x08transfer\x18\x08 \x01(\x08\x12\x11\n\tuseEccKey\x18\t \x01(\x08\x12\x17\n\x0fremoveVaultData\x18\n \x01(\x08\x12\x12\n\nexpiration\x18\x0b \x01(\x03\x12=\n\x15timerNotificationType\x18\x0c \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x1a\n\x12rotateOnExpiration\x18\r \x01(\x08\"\xd5\x01\n\x19RecordShareUpdateResponse\x12:\n\x15\x61\x64\x64SharedRecordStatus\x18\x01 \x03(\x0b\x32\x1b.Records.SharedRecordStatus\x12=\n\x18updateSharedRecordStatus\x18\x02 \x03(\x0b\x32\x1b.Records.SharedRecordStatus\x12=\n\x18removeSharedRecordStatus\x18\x03 \x03(\x0b\x32\x1b.Records.SharedRecordStatus\"Z\n\x12SharedRecordStatus\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x0e\n\x06status\x18\x02 \x01(\t\x12\x0f\n\x07message\x18\x03 \x01(\t\x12\x10\n\x08username\x18\x04 \x01(\t\"G\n\x1bGetRecordPermissionsRequest\x12\x12\n\nrecordUids\x18\x01 \x03(\x0c\x12\x14\n\x0cisShareAdmin\x18\x02 \x01(\x08\"T\n\x1cGetRecordPermissionsResponse\x12\x34\n\x11recordPermissions\x18\x01 \x03(\x0b\x32\x19.Records.RecordPermission\"l\n\x10RecordPermission\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\r\n\x05owner\x18\x02 \x01(\x08\x12\x0f\n\x07\x63\x61nEdit\x18\x03 \x01(\x08\x12\x10\n\x08\x63\x61nShare\x18\x04 \x01(\x08\x12\x13\n\x0b\x63\x61nTransfer\x18\x05 \x01(\x08\"h\n\x16GetShareObjectsRequest\x12\x11\n\tstartWith\x18\x01 \x01(\t\x12\x10\n\x08\x63ontains\x18\x02 \x01(\t\x12\x10\n\x08\x66iltered\x18\x03 \x01(\x08\x12\x17\n\x0fsharedFolderUid\x18\x04 \x01(\x0c\"\xe7\x02\n\x17GetShareObjectsResponse\x12.\n\x12shareRelationships\x18\x01 \x03(\x0b\x32\x12.Records.ShareUser\x12,\n\x10shareFamilyUsers\x18\x02 \x03(\x0b\x32\x12.Records.ShareUser\x12\x30\n\x14shareEnterpriseUsers\x18\x03 \x03(\x0b\x32\x12.Records.ShareUser\x12&\n\nshareTeams\x18\x04 \x03(\x0b\x32\x12.Records.ShareTeam\x12(\n\x0cshareMCTeams\x18\x05 \x03(\x0b\x32\x12.Records.ShareTeam\x12\x32\n\x16shareMCEnterpriseUsers\x18\x06 \x03(\x0b\x32\x12.Records.ShareUser\x12\x36\n\x14shareEnterpriseNames\x18\x07 \x03(\x0b\x32\x18.Records.ShareEnterprise\"\xbd\x01\n\tShareUser\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x10\n\x08\x66ullname\x18\x02 \x01(\t\x12\x14\n\x0c\x65nterpriseId\x18\x03 \x01(\x05\x12$\n\x06status\x18\x04 \x01(\x0e\x32\x14.Records.ShareStatus\x12\x14\n\x0cisShareAdmin\x18\x05 \x01(\x08\x12\"\n\x1aisAdminOfSharedFolderOwner\x18\x06 \x01(\x08\x12\x16\n\x0euserAccountUid\x18\x07 \x01(\x0c\"D\n\tShareTeam\x12\x10\n\x08teamname\x18\x01 \x01(\t\x12\x14\n\x0c\x65nterpriseId\x18\x02 \x01(\x05\x12\x0f\n\x07teamUid\x18\x03 \x01(\x0c\"?\n\x0fShareEnterprise\x12\x16\n\x0e\x65nterprisename\x18\x01 \x01(\t\x12\x14\n\x0c\x65nterpriseId\x18\x02 \x01(\x05\"S\n\x1fRecordsOnwershipTransferRequest\x12\x30\n\x0ftransferRecords\x18\x01 \x03(\x0b\x32\x17.Records.TransferRecord\"[\n\x0eTransferRecord\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x11\n\trecordKey\x18\x03 \x01(\x0c\x12\x11\n\tuseEccKey\x18\x04 \x01(\x08\"_\n RecordsOnwershipTransferResponse\x12;\n\x14transferRecordStatus\x18\x01 \x03(\x0b\x32\x1d.Records.TransferRecordStatus\"\\\n\x14TransferRecordStatus\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x0e\n\x06status\x18\x03 \x01(\t\x12\x0f\n\x07message\x18\x04 \x01(\t\"y\n\x15RecordsUnshareRequest\x12\x34\n\rsharedFolders\x18\x01 \x03(\x0b\x32\x1d.Records.RecordsUnshareFolder\x12*\n\x05users\x18\x02 \x03(\x0b\x32\x1b.Records.RecordsUnshareUser\"\x86\x01\n\x16RecordsUnshareResponse\x12:\n\rsharedFolders\x18\x01 \x03(\x0b\x32#.Records.RecordsUnshareFolderStatus\x12\x30\n\x05users\x18\x02 \x03(\x0b\x32!.Records.RecordsUnshareUserStatus\"B\n\x14RecordsUnshareFolder\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x17\n\x0fsharedFolderUid\x18\x02 \x01(\x0c\";\n\x12RecordsUnshareUser\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x12\n\naccountUid\x18\x02 \x01(\x0c\"H\n\x1aRecordsUnshareFolderStatus\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x17\n\x0fsharedFolderUid\x18\x02 \x01(\x0c\"A\n\x18RecordsUnshareUserStatus\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x12\n\naccountUid\x18\x02 \x01(\x0c\"[\n\x1aTimedAccessCallbackPayload\x12=\n\x15timeLimitedAccessType\x18\x01 \x01(\x0e\x32\x1e.Records.TimeLimitedAccessType\"\xfd\x01\n\x18TimeLimitedAccessRequest\x12\x12\n\naccountUid\x18\x01 \x03(\x0c\x12\x0f\n\x07teamUid\x18\x02 \x03(\x0c\x12\x11\n\trecordUid\x18\x03 \x03(\x0c\x12\x17\n\x0fsharedObjectUid\x18\x04 \x01(\x0c\x12=\n\x15timeLimitedAccessType\x18\x05 \x01(\x0e\x32\x1e.Records.TimeLimitedAccessType\x12\x12\n\nexpiration\x18\x06 \x01(\x03\x12=\n\x15timerNotificationType\x18\x07 \x01(\x0e\x32\x1e.Records.TimerNotificationType\"7\n\x17TimeLimitedAccessStatus\x12\x0b\n\x03uid\x18\x01 \x01(\x0c\x12\x0f\n\x07message\x18\x02 \x01(\t\"\xe3\x01\n\x19TimeLimitedAccessResponse\x12\x10\n\x08revision\x18\x01 \x01(\x03\x12:\n\x10userAccessStatus\x18\x02 \x03(\x0b\x32 .Records.TimeLimitedAccessStatus\x12:\n\x10teamAccessStatus\x18\x03 \x03(\x0b\x32 .Records.TimeLimitedAccessStatus\x12<\n\x12recordAccessStatus\x18\x04 \x03(\x0b\x32 .Records.TimeLimitedAccessStatus*h\n\x0fRecordTypeScope\x12\x0f\n\x0bRT_STANDARD\x10\x00\x12\x0b\n\x07RT_USER\x10\x01\x12\x11\n\rRT_ENTERPRISE\x10\x02\x12\n\n\x06RT_PAM\x10\x03\x12\x18\n\x14RT_PAM_CONFIGURATION\x10\x04*\xd1\x01\n\rRecordKeyType\x12\n\n\x06NO_KEY\x10\x00\x12\x19\n\x15\x45NCRYPTED_BY_DATA_KEY\x10\x01\x12\x1b\n\x17\x45NCRYPTED_BY_PUBLIC_KEY\x10\x02\x12\x1d\n\x19\x45NCRYPTED_BY_DATA_KEY_GCM\x10\x03\x12\x1f\n\x1b\x45NCRYPTED_BY_PUBLIC_KEY_ECC\x10\x04\x12\x1d\n\x19\x45NCRYPTED_BY_ROOT_KEY_CBC\x10\x05\x12\x1d\n\x19\x45NCRYPTED_BY_ROOT_KEY_GCM\x10\x06*P\n\x10RecordFolderType\x12\x0f\n\x0buser_folder\x10\x00\x12\x11\n\rshared_folder\x10\x01\x12\x18\n\x14shared_folder_folder\x10\x02*\xec\x02\n\x12RecordModifyResult\x12\x0e\n\nRS_SUCCESS\x10\x00\x12\x12\n\x0eRS_OUT_OF_SYNC\x10\x01\x12\x14\n\x10RS_ACCESS_DENIED\x10\x02\x12\x13\n\x0fRS_SHARE_DENIED\x10\x03\x12\x14\n\x10RS_RECORD_EXISTS\x10\x04\x12\x1e\n\x1aRS_OLD_RECORD_VERSION_TYPE\x10\x05\x12\x1e\n\x1aRS_NEW_RECORD_VERSION_TYPE\x10\x06\x12\x16\n\x12RS_FILES_NOT_MATCH\x10\x07\x12\x1b\n\x17RS_RECORD_NOT_SHAREABLE\x10\x08\x12\x1f\n\x1bRS_ATTACHMENT_NOT_SHAREABLE\x10\t\x12\x19\n\x15RS_FILE_LIMIT_REACHED\x10\n\x12\x1a\n\x16RS_SIZE_EXCEEDED_LIMIT\x10\x0b\x12$\n RS_ONLY_OWNER_CAN_MODIFY_SCRIPTS\x10\x0c*-\n\rFileAddResult\x12\x0e\n\nFA_SUCCESS\x10\x00\x12\x0c\n\x08\x46\x41_ERROR\x10\x01*C\n\rFileGetResult\x12\x0e\n\nFG_SUCCESS\x10\x00\x12\x0c\n\x08\x46G_ERROR\x10\x01\x12\x14\n\x10\x46G_ACCESS_DENIED\x10\x02*J\n\x14RecordDetailsInclude\x12\x13\n\x0f\x44\x41TA_PLUS_SHARE\x10\x00\x12\r\n\tDATA_ONLY\x10\x01\x12\x0e\n\nSHARE_ONLY\x10\x02*b\n\x19\x43heckShareAdminObjectType\x12\x19\n\x15\x43HECK_SA_INVALID_TYPE\x10\x00\x12\x12\n\x0e\x43HECK_SA_ON_SF\x10\x01\x12\x16\n\x12\x43HECK_SA_ON_RECORD\x10\x02*1\n\x0bShareStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\t\n\x05\x42LOCK\x10\x01\x12\x0b\n\x07INVITED\x10\x02*:\n\x15RecordTransactionType\x12\x0f\n\x0bRTT_GENERAL\x10\x00\x12\x10\n\x0cRTT_ROTATION\x10\x01*\xdc\x02\n\x15TimeLimitedAccessType\x12$\n INVALID_TIME_LIMITED_ACCESS_TYPE\x10\x00\x12\x19\n\x15USER_ACCESS_TO_RECORD\x10\x01\x12\'\n#USER_OR_TEAM_ACCESS_TO_SHAREDFOLDER\x10\x02\x12!\n\x1dRECORD_ACCESS_TO_SHAREDFOLDER\x10\x03\x12\x1f\n\x1bUSER_ACCESS_TO_SHAREDFOLDER\x10\x04\x12\x1f\n\x1bTEAM_ACCESS_TO_SHAREDFOLDER\x10\x05\x12\x1b\n\x17RECORD_ACCESS_TO_FOLDER\x10\x06\x12\x19\n\x15USER_ACCESS_TO_FOLDER\x10\x07\x12\x19\n\x15TEAM_ACCESS_TO_FOLDER\x10\x08\x12!\n\x1dUSER_OR_TEAM_ACCESS_TO_FOLDER\x10\t*\\\n\x15TimerNotificationType\x12\x14\n\x10NOTIFICATION_OFF\x10\x00\x12\x10\n\x0cNOTIFY_OWNER\x10\x01\x12\x1b\n\x17NOTIFY_PRIVILEGED_USERS\x10\x02\x42#\n\x18\x63om.keepersecurity.protoB\x07Recordsb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0crecord.proto\x12\x07Records\"\\\n\nRecordType\x12\x14\n\x0crecordTypeId\x18\x01 \x01(\x05\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12\'\n\x05scope\x18\x03 \x01(\x0e\x32\x18.Records.RecordTypeScope\"U\n\x12RecordTypesRequest\x12\x10\n\x08standard\x18\x01 \x01(\x08\x12\x0c\n\x04user\x18\x02 \x01(\x08\x12\x12\n\nenterprise\x18\x03 \x01(\x08\x12\x0b\n\x03pam\x18\x04 \x01(\x08\"\x9c\x01\n\x13RecordTypesResponse\x12(\n\x0brecordTypes\x18\x01 \x03(\x0b\x32\x13.Records.RecordType\x12\x17\n\x0fstandardCounter\x18\x02 \x01(\x05\x12\x13\n\x0buserCounter\x18\x03 \x01(\x05\x12\x19\n\x11\x65nterpriseCounter\x18\x04 \x01(\x05\x12\x12\n\npamCounter\x18\x05 \x01(\x05\"A\n\x18RecordTypeModifyResponse\x12\x14\n\x0crecordTypeId\x18\x01 \x01(\x05\x12\x0f\n\x07\x63ounter\x18\x02 \x01(\x05\"=\n\x11RecordsGetRequest\x12\x13\n\x0brecord_uids\x18\x01 \x03(\x0c\x12\x13\n\x0b\x63lient_time\x18\x02 \x01(\x03\"\xd1\x01\n\x06Record\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_key\x18\x02 \x01(\x0c\x12/\n\x0frecord_key_type\x18\x03 \x01(\x0e\x32\x16.Records.RecordKeyType\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\r\n\x05\x65xtra\x18\x05 \x01(\x0c\x12\x0f\n\x07version\x18\x06 \x01(\x05\x12\x1c\n\x14\x63lient_modified_time\x18\x07 \x01(\x03\x12\x10\n\x08revision\x18\x08 \x01(\x03\x12\x10\n\x08\x66ile_ids\x18\t \x03(\x0c\"~\n\x0f\x46olderRecordKey\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_uid\x18\x02 \x01(\x0c\x12\x12\n\nrecord_key\x18\x03 \x01(\x0c\x12/\n\x0frecord_key_type\x18\x04 \x01(\x0e\x32\x16.Records.RecordKeyType\"a\n\x06\x46older\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x12\n\nfolder_key\x18\x02 \x01(\x0c\x12/\n\x0f\x66older_key_type\x18\x03 \x01(\x0e\x32\x16.Records.RecordKeyType\"\x95\x01\n\x04Team\x12\x10\n\x08team_uid\x18\x01 \x01(\x0c\x12\x10\n\x08team_key\x18\x02 \x01(\x0c\x12\x18\n\x10team_private_key\x18\x03 \x01(\x0c\x12-\n\rteam_key_type\x18\x04 \x01(\x0e\x32\x16.Records.RecordKeyType\x12 \n\x07\x66olders\x18\x05 \x03(\x0b\x32\x0f.Records.Folder\"\xac\x01\n\x12RecordsGetResponse\x12 \n\x07records\x18\x01 \x03(\x0b\x32\x0f.Records.Record\x12\x34\n\x12\x66older_record_keys\x18\x02 \x03(\x0b\x32\x18.Records.FolderRecordKey\x12 \n\x07\x66olders\x18\x03 \x03(\x0b\x32\x0f.Records.Folder\x12\x1c\n\x05teams\x18\x04 \x03(\x0b\x32\r.Records.Team\"4\n\nRecordLink\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_key\x18\x02 \x01(\x0c\",\n\x0bRecordAudit\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"\x1c\n\x0cSecurityData\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"!\n\x11SecurityScoreData\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\x84\x03\n\tRecordAdd\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_key\x18\x02 \x01(\x0c\x12\x1c\n\x14\x63lient_modified_time\x18\x03 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x17\n\x0fnon_shared_data\x18\x05 \x01(\x0c\x12.\n\x0b\x66older_type\x18\x06 \x01(\x0e\x32\x19.Records.RecordFolderType\x12\x12\n\nfolder_uid\x18\x07 \x01(\x0c\x12\x12\n\nfolder_key\x18\x08 \x01(\x0c\x12)\n\x0crecord_links\x18\t \x03(\x0b\x32\x13.Records.RecordLink\x12#\n\x05\x61udit\x18\n \x01(\x0b\x32\x14.Records.RecordAudit\x12+\n\x0csecurityData\x18\x0b \x01(\x0b\x32\x15.Records.SecurityData\x12\x35\n\x11securityScoreData\x18\x0c \x01(\x0b\x32\x1a.Records.SecurityScoreData\"\x85\x01\n\x11RecordsAddRequest\x12#\n\x07records\x18\x01 \x03(\x0b\x32\x12.Records.RecordAdd\x12\x13\n\x0b\x63lient_time\x18\x02 \x01(\x03\x12\x36\n\x16security_data_key_type\x18\x03 \x01(\x0e\x32\x16.Records.RecordKeyType\"\xce\x02\n\x0cRecordUpdate\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x1c\n\x14\x63lient_modified_time\x18\x02 \x01(\x03\x12\x10\n\x08revision\x18\x03 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x17\n\x0fnon_shared_data\x18\x05 \x01(\x0c\x12-\n\x10record_links_add\x18\x06 \x03(\x0b\x32\x13.Records.RecordLink\x12\x1b\n\x13record_links_remove\x18\x07 \x03(\x0c\x12#\n\x05\x61udit\x18\x08 \x01(\x0b\x32\x14.Records.RecordAudit\x12+\n\x0csecurityData\x18\t \x01(\x0b\x32\x15.Records.SecurityData\x12\x35\n\x11securityScoreData\x18\n \x01(\x0b\x32\x1a.Records.SecurityScoreData\"\x8b\x01\n\x14RecordsUpdateRequest\x12&\n\x07records\x18\x01 \x03(\x0b\x32\x15.Records.RecordUpdate\x12\x13\n\x0b\x63lient_time\x18\x02 \x01(\x03\x12\x36\n\x16security_data_key_type\x18\x03 \x01(\x0e\x32\x16.Records.RecordKeyType\"\x8e\x01\n\x17RecordFileForConversion\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x14\n\x0c\x66ile_file_id\x18\x02 \x01(\t\x12\x15\n\rthumb_file_id\x18\x03 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x12\n\nrecord_key\x18\x05 \x01(\x0c\x12\x10\n\x08link_key\x18\x06 \x01(\x0c\"J\n\x19RecordFolderForConversion\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x19\n\x11record_folder_key\x18\x02 \x01(\x0c\"\x92\x02\n\x11RecordConvertToV3\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x1c\n\x14\x63lient_modified_time\x18\x02 \x01(\x03\x12\x10\n\x08revision\x18\x03 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\x17\n\x0fnon_shared_data\x18\x05 \x01(\x0c\x12#\n\x05\x61udit\x18\x06 \x01(\x0b\x32\x14.Records.RecordAudit\x12\x35\n\x0brecord_file\x18\x07 \x03(\x0b\x32 .Records.RecordFileForConversion\x12\x36\n\nfolder_key\x18\x08 \x03(\x0b\x32\".Records.RecordFolderForConversion\"]\n\x19RecordsConvertToV3Request\x12+\n\x07records\x18\x01 \x03(\x0b\x32\x1a.Records.RecordConvertToV3\x12\x13\n\x0b\x63lient_time\x18\x02 \x01(\x03\"\'\n\x14RecordsRemoveRequest\x12\x0f\n\x07records\x18\x01 \x03(\x0c\">\n\x0cRecordRevert\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x1a\n\x12revert_to_revision\x18\x02 \x01(\x03\">\n\x14RecordsRevertRequest\x12&\n\x07records\x18\x01 \x03(\x0b\x32\x15.Records.RecordRevert\"c\n\x0fRecordLinkError\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12+\n\x06status\x18\x02 \x01(\x0e\x32\x1b.Records.RecordModifyResult\x12\x0f\n\x07message\x18\x03 \x01(\t\"\x95\x01\n\x12RecordModifyStatus\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12+\n\x06status\x18\x02 \x01(\x0e\x32\x1b.Records.RecordModifyResult\x12\x0f\n\x07message\x18\x03 \x01(\t\x12-\n\x0blink_errors\x18\x04 \x03(\x0b\x32\x18.Records.RecordLinkError\"W\n\x15RecordsModifyResponse\x12,\n\x07records\x18\x01 \x03(\x0b\x32\x1b.Records.RecordModifyStatus\x12\x10\n\x08revision\x18\x02 \x01(\x03\"Y\n\x12RecordAddAuditData\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x10\n\x08revision\x18\x02 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\x0f\n\x07version\x18\x04 \x01(\x05\"C\n\x13\x41\x64\x64\x41uditDataRequest\x12,\n\x07records\x18\x01 \x03(\x0b\x32\x1b.Records.RecordAddAuditData\"t\n\x04\x46ile\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_key\x18\x02 \x01(\x0c\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\x10\n\x08\x66ileSize\x18\x04 \x01(\x03\x12\x11\n\tthumbSize\x18\x05 \x01(\x05\x12\x11\n\tis_script\x18\x06 \x01(\x08\"D\n\x0f\x46ilesAddRequest\x12\x1c\n\x05\x66iles\x18\x01 \x03(\x0b\x32\r.Records.File\x12\x13\n\x0b\x63lient_time\x18\x02 \x01(\x03\"\xa7\x01\n\rFileAddStatus\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12&\n\x06status\x18\x02 \x01(\x0e\x32\x16.Records.FileAddResult\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\x12\n\nparameters\x18\x04 \x01(\t\x12\x1c\n\x14thumbnail_parameters\x18\x05 \x01(\t\x12\x1b\n\x13success_status_code\x18\x06 \x01(\x05\"K\n\x10\x46ilesAddResponse\x12%\n\x05\x66iles\x18\x01 \x03(\x0b\x32\x16.Records.FileAddStatus\x12\x10\n\x08revision\x18\x02 \x01(\x03\"f\n\x0f\x46ilesGetRequest\x12\x13\n\x0brecord_uids\x18\x01 \x03(\x0c\x12\x16\n\x0e\x66or_thumbnails\x18\x02 \x01(\x08\x12&\n\x1e\x65mergency_access_account_owner\x18\x03 \x01(\t\"\xa2\x01\n\rFileGetStatus\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12&\n\x06status\x18\x02 \x01(\x0e\x32\x16.Records.FileGetResult\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\x1b\n\x13success_status_code\x18\x04 \x01(\x05\x12+\n\x0b\x66ileKeyType\x18\x05 \x01(\x0e\x32\x16.Records.RecordKeyType\"9\n\x10\x46ilesGetResponse\x12%\n\x05\x66iles\x18\x01 \x03(\x0b\x32\x16.Records.FileGetStatus\"\x8d\x01\n\x15\x41pplicationAddRequest\x12\x0f\n\x07\x61pp_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_key\x18\x02 \x01(\x0c\x12\x1c\n\x14\x63lient_modified_time\x18\x03 \x01(\x03\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12#\n\x05\x61udit\x18\x05 \x01(\x0b\x32\x14.Records.RecordAudit\"\x88\x01\n\"GetRecordDataWithAccessInfoRequest\x12\x12\n\nclientTime\x18\x01 \x01(\x03\x12\x11\n\trecordUid\x18\x02 \x03(\x0c\x12;\n\x14recordDetailsInclude\x18\x03 \x01(\x0e\x32\x1d.Records.RecordDetailsInclude\"\x86\x02\n\x0eUserPermission\x12\x10\n\x08username\x18\x01 \x01(\t\x12\r\n\x05owner\x18\x02 \x01(\x08\x12\x12\n\nshareAdmin\x18\x03 \x01(\x08\x12\x10\n\x08sharable\x18\x04 \x01(\x08\x12\x10\n\x08\x65\x64itable\x18\x05 \x01(\x08\x12\x18\n\x10\x61waitingApproval\x18\x06 \x01(\x08\x12\x12\n\nexpiration\x18\x07 \x01(\x03\x12\x12\n\naccountUid\x18\x08 \x01(\x0c\x12=\n\x15timerNotificationType\x18\t \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x1a\n\x12rotateOnExpiration\x18\n \x01(\x08\"\xd8\x01\n\x16SharedFolderPermission\x12\x17\n\x0fsharedFolderUid\x18\x01 \x01(\x0c\x12\x12\n\nresharable\x18\x02 \x01(\x08\x12\x10\n\x08\x65\x64itable\x18\x03 \x01(\x08\x12\x10\n\x08revision\x18\x04 \x01(\x03\x12\x12\n\nexpiration\x18\x05 \x01(\x03\x12=\n\x15timerNotificationType\x18\x06 \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x1a\n\x12rotateOnExpiration\x18\x07 \x01(\x08\"\xe8\x02\n\nRecordData\x12\x10\n\x08revision\x18\x01 \x01(\x03\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12\x0e\n\x06shared\x18\x03 \x01(\x08\x12\x1b\n\x13\x65ncryptedRecordData\x18\x04 \x01(\t\x12\x1a\n\x12\x65ncryptedExtraData\x18\x05 \x01(\t\x12\x1a\n\x12\x63lientModifiedTime\x18\x06 \x01(\x03\x12\x15\n\rnonSharedData\x18\x07 \x01(\t\x12-\n\x10linkedRecordData\x18\x08 \x03(\x0b\x32\x13.Records.RecordData\x12\x0e\n\x06\x66ileId\x18\t \x03(\x0c\x12\x10\n\x08\x66ileSize\x18\n \x01(\x03\x12\x15\n\rthumbnailSize\x18\x0b \x01(\x03\x12-\n\rrecordKeyType\x18\x0c \x01(\x0e\x32\x16.Records.RecordKeyType\x12\x11\n\trecordKey\x18\r \x01(\x0c\x12\x11\n\trecordUid\x18\x0e \x01(\x0c\"\xc8\x01\n\x18RecordDataWithAccessInfo\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\'\n\nrecordData\x18\x02 \x01(\x0b\x32\x13.Records.RecordData\x12/\n\x0euserPermission\x18\x03 \x03(\x0b\x32\x17.Records.UserPermission\x12?\n\x16sharedFolderPermission\x18\x04 \x03(\x0b\x32\x1f.Records.SharedFolderPermission\"\x89\x01\n#GetRecordDataWithAccessInfoResponse\x12\x43\n\x18recordDataWithAccessInfo\x18\x01 \x03(\x0b\x32!.Records.RecordDataWithAccessInfo\x12\x1d\n\x15noPermissionRecordUid\x18\x02 \x03(\x0c\"j\n\x12IsObjectShareAdmin\x12\x0b\n\x03uid\x18\x01 \x01(\x0c\x12\x0f\n\x07isAdmin\x18\x02 \x01(\x08\x12\x36\n\nobjectType\x18\x03 \x01(\x0e\x32\".Records.CheckShareAdminObjectType\"H\n\rAmIShareAdmin\x12\x37\n\x12isObjectShareAdmin\x18\x01 \x03(\x0b\x32\x1b.Records.IsObjectShareAdmin\"\xbc\x01\n\x18RecordShareUpdateRequest\x12.\n\x0f\x61\x64\x64SharedRecord\x18\x01 \x03(\x0b\x32\x15.Records.SharedRecord\x12\x31\n\x12updateSharedRecord\x18\x02 \x03(\x0b\x32\x15.Records.SharedRecord\x12\x31\n\x12removeSharedRecord\x18\x03 \x03(\x0b\x32\x15.Records.SharedRecord\x12\n\n\x02pt\x18\x04 \x01(\t\"\xc4\x02\n\x0cSharedRecord\x12\x12\n\ntoUsername\x18\x01 \x01(\t\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x11\n\trecordKey\x18\x03 \x01(\x0c\x12\x17\n\x0fsharedFolderUid\x18\x04 \x01(\x0c\x12\x0f\n\x07teamUid\x18\x05 \x01(\x0c\x12\x10\n\x08\x65\x64itable\x18\x06 \x01(\x08\x12\x11\n\tshareable\x18\x07 \x01(\x08\x12\x10\n\x08transfer\x18\x08 \x01(\x08\x12\x11\n\tuseEccKey\x18\t \x01(\x08\x12\x17\n\x0fremoveVaultData\x18\n \x01(\x08\x12\x12\n\nexpiration\x18\x0b \x01(\x03\x12=\n\x15timerNotificationType\x18\x0c \x01(\x0e\x32\x1e.Records.TimerNotificationType\x12\x1a\n\x12rotateOnExpiration\x18\r \x01(\x08\"\xd5\x01\n\x19RecordShareUpdateResponse\x12:\n\x15\x61\x64\x64SharedRecordStatus\x18\x01 \x03(\x0b\x32\x1b.Records.SharedRecordStatus\x12=\n\x18updateSharedRecordStatus\x18\x02 \x03(\x0b\x32\x1b.Records.SharedRecordStatus\x12=\n\x18removeSharedRecordStatus\x18\x03 \x03(\x0b\x32\x1b.Records.SharedRecordStatus\"Z\n\x12SharedRecordStatus\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x0e\n\x06status\x18\x02 \x01(\t\x12\x0f\n\x07message\x18\x03 \x01(\t\x12\x10\n\x08username\x18\x04 \x01(\t\"G\n\x1bGetRecordPermissionsRequest\x12\x12\n\nrecordUids\x18\x01 \x03(\x0c\x12\x14\n\x0cisShareAdmin\x18\x02 \x01(\x08\"T\n\x1cGetRecordPermissionsResponse\x12\x34\n\x11recordPermissions\x18\x01 \x03(\x0b\x32\x19.Records.RecordPermission\"l\n\x10RecordPermission\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\r\n\x05owner\x18\x02 \x01(\x08\x12\x0f\n\x07\x63\x61nEdit\x18\x03 \x01(\x08\x12\x10\n\x08\x63\x61nShare\x18\x04 \x01(\x08\x12\x13\n\x0b\x63\x61nTransfer\x18\x05 \x01(\x08\"h\n\x16GetShareObjectsRequest\x12\x11\n\tstartWith\x18\x01 \x01(\t\x12\x10\n\x08\x63ontains\x18\x02 \x01(\t\x12\x10\n\x08\x66iltered\x18\x03 \x01(\x08\x12\x17\n\x0fsharedFolderUid\x18\x04 \x01(\x0c\"\xe7\x02\n\x17GetShareObjectsResponse\x12.\n\x12shareRelationships\x18\x01 \x03(\x0b\x32\x12.Records.ShareUser\x12,\n\x10shareFamilyUsers\x18\x02 \x03(\x0b\x32\x12.Records.ShareUser\x12\x30\n\x14shareEnterpriseUsers\x18\x03 \x03(\x0b\x32\x12.Records.ShareUser\x12&\n\nshareTeams\x18\x04 \x03(\x0b\x32\x12.Records.ShareTeam\x12(\n\x0cshareMCTeams\x18\x05 \x03(\x0b\x32\x12.Records.ShareTeam\x12\x32\n\x16shareMCEnterpriseUsers\x18\x06 \x03(\x0b\x32\x12.Records.ShareUser\x12\x36\n\x14shareEnterpriseNames\x18\x07 \x03(\x0b\x32\x18.Records.ShareEnterprise\"\xbd\x01\n\tShareUser\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x10\n\x08\x66ullname\x18\x02 \x01(\t\x12\x14\n\x0c\x65nterpriseId\x18\x03 \x01(\x05\x12$\n\x06status\x18\x04 \x01(\x0e\x32\x14.Records.ShareStatus\x12\x14\n\x0cisShareAdmin\x18\x05 \x01(\x08\x12\"\n\x1aisAdminOfSharedFolderOwner\x18\x06 \x01(\x08\x12\x16\n\x0euserAccountUid\x18\x07 \x01(\x0c\"D\n\tShareTeam\x12\x10\n\x08teamname\x18\x01 \x01(\t\x12\x14\n\x0c\x65nterpriseId\x18\x02 \x01(\x05\x12\x0f\n\x07teamUid\x18\x03 \x01(\x0c\"?\n\x0fShareEnterprise\x12\x16\n\x0e\x65nterprisename\x18\x01 \x01(\t\x12\x14\n\x0c\x65nterpriseId\x18\x02 \x01(\x05\"S\n\x1fRecordsOnwershipTransferRequest\x12\x30\n\x0ftransferRecords\x18\x01 \x03(\x0b\x32\x17.Records.TransferRecord\"[\n\x0eTransferRecord\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x11\n\trecordKey\x18\x03 \x01(\x0c\x12\x11\n\tuseEccKey\x18\x04 \x01(\x08\"_\n RecordsOnwershipTransferResponse\x12;\n\x14transferRecordStatus\x18\x01 \x03(\x0b\x32\x1d.Records.TransferRecordStatus\"\\\n\x14TransferRecordStatus\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x11\n\trecordUid\x18\x02 \x01(\x0c\x12\x0e\n\x06status\x18\x03 \x01(\t\x12\x0f\n\x07message\x18\x04 \x01(\t\"y\n\x15RecordsUnshareRequest\x12\x34\n\rsharedFolders\x18\x01 \x03(\x0b\x32\x1d.Records.RecordsUnshareFolder\x12*\n\x05users\x18\x02 \x03(\x0b\x32\x1b.Records.RecordsUnshareUser\"\x86\x01\n\x16RecordsUnshareResponse\x12:\n\rsharedFolders\x18\x01 \x03(\x0b\x32#.Records.RecordsUnshareFolderStatus\x12\x30\n\x05users\x18\x02 \x03(\x0b\x32!.Records.RecordsUnshareUserStatus\"B\n\x14RecordsUnshareFolder\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x17\n\x0fsharedFolderUid\x18\x02 \x01(\x0c\";\n\x12RecordsUnshareUser\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x12\n\naccountUid\x18\x02 \x01(\x0c\"H\n\x1aRecordsUnshareFolderStatus\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x17\n\x0fsharedFolderUid\x18\x02 \x01(\x0c\"A\n\x18RecordsUnshareUserStatus\x12\x11\n\trecordUid\x18\x01 \x01(\x0c\x12\x12\n\naccountUid\x18\x02 \x01(\x0c\"[\n\x1aTimedAccessCallbackPayload\x12=\n\x15timeLimitedAccessType\x18\x01 \x01(\x0e\x32\x1e.Records.TimeLimitedAccessType\"\xfd\x01\n\x18TimeLimitedAccessRequest\x12\x12\n\naccountUid\x18\x01 \x03(\x0c\x12\x0f\n\x07teamUid\x18\x02 \x03(\x0c\x12\x11\n\trecordUid\x18\x03 \x03(\x0c\x12\x17\n\x0fsharedObjectUid\x18\x04 \x01(\x0c\x12=\n\x15timeLimitedAccessType\x18\x05 \x01(\x0e\x32\x1e.Records.TimeLimitedAccessType\x12\x12\n\nexpiration\x18\x06 \x01(\x03\x12=\n\x15timerNotificationType\x18\x07 \x01(\x0e\x32\x1e.Records.TimerNotificationType\"7\n\x17TimeLimitedAccessStatus\x12\x0b\n\x03uid\x18\x01 \x01(\x0c\x12\x0f\n\x07message\x18\x02 \x01(\t\"\xe3\x01\n\x19TimeLimitedAccessResponse\x12\x10\n\x08revision\x18\x01 \x01(\x03\x12:\n\x10userAccessStatus\x18\x02 \x03(\x0b\x32 .Records.TimeLimitedAccessStatus\x12:\n\x10teamAccessStatus\x18\x03 \x03(\x0b\x32 .Records.TimeLimitedAccessStatus\x12<\n\x12recordAccessStatus\x18\x04 \x03(\x0b\x32 .Records.TimeLimitedAccessStatus*h\n\x0fRecordTypeScope\x12\x0f\n\x0bRT_STANDARD\x10\x00\x12\x0b\n\x07RT_USER\x10\x01\x12\x11\n\rRT_ENTERPRISE\x10\x02\x12\n\n\x06RT_PAM\x10\x03\x12\x18\n\x14RT_PAM_CONFIGURATION\x10\x04*\xd1\x01\n\rRecordKeyType\x12\n\n\x06NO_KEY\x10\x00\x12\x19\n\x15\x45NCRYPTED_BY_DATA_KEY\x10\x01\x12\x1b\n\x17\x45NCRYPTED_BY_PUBLIC_KEY\x10\x02\x12\x1d\n\x19\x45NCRYPTED_BY_DATA_KEY_GCM\x10\x03\x12\x1f\n\x1b\x45NCRYPTED_BY_PUBLIC_KEY_ECC\x10\x04\x12\x1d\n\x19\x45NCRYPTED_BY_ROOT_KEY_CBC\x10\x05\x12\x1d\n\x19\x45NCRYPTED_BY_ROOT_KEY_GCM\x10\x06*P\n\x10RecordFolderType\x12\x0f\n\x0buser_folder\x10\x00\x12\x11\n\rshared_folder\x10\x01\x12\x18\n\x14shared_folder_folder\x10\x02*\xec\x02\n\x12RecordModifyResult\x12\x0e\n\nRS_SUCCESS\x10\x00\x12\x12\n\x0eRS_OUT_OF_SYNC\x10\x01\x12\x14\n\x10RS_ACCESS_DENIED\x10\x02\x12\x13\n\x0fRS_SHARE_DENIED\x10\x03\x12\x14\n\x10RS_RECORD_EXISTS\x10\x04\x12\x1e\n\x1aRS_OLD_RECORD_VERSION_TYPE\x10\x05\x12\x1e\n\x1aRS_NEW_RECORD_VERSION_TYPE\x10\x06\x12\x16\n\x12RS_FILES_NOT_MATCH\x10\x07\x12\x1b\n\x17RS_RECORD_NOT_SHAREABLE\x10\x08\x12\x1f\n\x1bRS_ATTACHMENT_NOT_SHAREABLE\x10\t\x12\x19\n\x15RS_FILE_LIMIT_REACHED\x10\n\x12\x1a\n\x16RS_SIZE_EXCEEDED_LIMIT\x10\x0b\x12$\n RS_ONLY_OWNER_CAN_MODIFY_SCRIPTS\x10\x0c*-\n\rFileAddResult\x12\x0e\n\nFA_SUCCESS\x10\x00\x12\x0c\n\x08\x46\x41_ERROR\x10\x01*C\n\rFileGetResult\x12\x0e\n\nFG_SUCCESS\x10\x00\x12\x0c\n\x08\x46G_ERROR\x10\x01\x12\x14\n\x10\x46G_ACCESS_DENIED\x10\x02*J\n\x14RecordDetailsInclude\x12\x13\n\x0f\x44\x41TA_PLUS_SHARE\x10\x00\x12\r\n\tDATA_ONLY\x10\x01\x12\x0e\n\nSHARE_ONLY\x10\x02*b\n\x19\x43heckShareAdminObjectType\x12\x19\n\x15\x43HECK_SA_INVALID_TYPE\x10\x00\x12\x12\n\x0e\x43HECK_SA_ON_SF\x10\x01\x12\x16\n\x12\x43HECK_SA_ON_RECORD\x10\x02*1\n\x0bShareStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\t\n\x05\x42LOCK\x10\x01\x12\x0b\n\x07INVITED\x10\x02*:\n\x15RecordTransactionType\x12\x0f\n\x0bRTT_GENERAL\x10\x00\x12\x10\n\x0cRTT_ROTATION\x10\x01*\xdc\x02\n\x15TimeLimitedAccessType\x12$\n INVALID_TIME_LIMITED_ACCESS_TYPE\x10\x00\x12\x19\n\x15USER_ACCESS_TO_RECORD\x10\x01\x12\'\n#USER_OR_TEAM_ACCESS_TO_SHAREDFOLDER\x10\x02\x12!\n\x1dRECORD_ACCESS_TO_SHAREDFOLDER\x10\x03\x12\x1f\n\x1bUSER_ACCESS_TO_SHAREDFOLDER\x10\x04\x12\x1f\n\x1bTEAM_ACCESS_TO_SHAREDFOLDER\x10\x05\x12\x1b\n\x17RECORD_ACCESS_TO_FOLDER\x10\x06\x12\x19\n\x15USER_ACCESS_TO_FOLDER\x10\x07\x12\x19\n\x15TEAM_ACCESS_TO_FOLDER\x10\x08\x12!\n\x1dUSER_OR_TEAM_ACCESS_TO_FOLDER\x10\t*\\\n\x15TimerNotificationType\x12\x14\n\x10NOTIFICATION_OFF\x10\x00\x12\x10\n\x0cNOTIFY_OWNER\x10\x01\x12\x1b\n\x17NOTIFY_PRIVILEGED_USERS\x10\x02\x42#\n\x18\x63om.keepersecurity.protoB\x07Recordsb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -32,30 +32,30 @@ if not _descriptor._USE_C_DESCRIPTORS: _globals['DESCRIPTOR']._loaded_options = None _globals['DESCRIPTOR']._serialized_options = b'\n\030com.keepersecurity.protoB\007Records' - _globals['_RECORDTYPESCOPE']._serialized_start=9490 - _globals['_RECORDTYPESCOPE']._serialized_end=9594 - _globals['_RECORDKEYTYPE']._serialized_start=9597 - _globals['_RECORDKEYTYPE']._serialized_end=9806 - _globals['_RECORDFOLDERTYPE']._serialized_start=9808 - _globals['_RECORDFOLDERTYPE']._serialized_end=9888 - _globals['_RECORDMODIFYRESULT']._serialized_start=9891 - _globals['_RECORDMODIFYRESULT']._serialized_end=10255 - _globals['_FILEADDRESULT']._serialized_start=10257 - _globals['_FILEADDRESULT']._serialized_end=10302 - _globals['_FILEGETRESULT']._serialized_start=10304 - _globals['_FILEGETRESULT']._serialized_end=10371 - _globals['_RECORDDETAILSINCLUDE']._serialized_start=10373 - _globals['_RECORDDETAILSINCLUDE']._serialized_end=10447 - _globals['_CHECKSHAREADMINOBJECTTYPE']._serialized_start=10449 - _globals['_CHECKSHAREADMINOBJECTTYPE']._serialized_end=10547 - _globals['_SHARESTATUS']._serialized_start=10549 - _globals['_SHARESTATUS']._serialized_end=10598 - _globals['_RECORDTRANSACTIONTYPE']._serialized_start=10600 - _globals['_RECORDTRANSACTIONTYPE']._serialized_end=10658 - _globals['_TIMELIMITEDACCESSTYPE']._serialized_start=10661 - _globals['_TIMELIMITEDACCESSTYPE']._serialized_end=11009 - _globals['_TIMERNOTIFICATIONTYPE']._serialized_start=11011 - _globals['_TIMERNOTIFICATIONTYPE']._serialized_end=11103 + _globals['_RECORDTYPESCOPE']._serialized_start=9539 + _globals['_RECORDTYPESCOPE']._serialized_end=9643 + _globals['_RECORDKEYTYPE']._serialized_start=9646 + _globals['_RECORDKEYTYPE']._serialized_end=9855 + _globals['_RECORDFOLDERTYPE']._serialized_start=9857 + _globals['_RECORDFOLDERTYPE']._serialized_end=9937 + _globals['_RECORDMODIFYRESULT']._serialized_start=9940 + _globals['_RECORDMODIFYRESULT']._serialized_end=10304 + _globals['_FILEADDRESULT']._serialized_start=10306 + _globals['_FILEADDRESULT']._serialized_end=10351 + _globals['_FILEGETRESULT']._serialized_start=10353 + _globals['_FILEGETRESULT']._serialized_end=10420 + _globals['_RECORDDETAILSINCLUDE']._serialized_start=10422 + _globals['_RECORDDETAILSINCLUDE']._serialized_end=10496 + _globals['_CHECKSHAREADMINOBJECTTYPE']._serialized_start=10498 + _globals['_CHECKSHAREADMINOBJECTTYPE']._serialized_end=10596 + _globals['_SHARESTATUS']._serialized_start=10598 + _globals['_SHARESTATUS']._serialized_end=10647 + _globals['_RECORDTRANSACTIONTYPE']._serialized_start=10649 + _globals['_RECORDTRANSACTIONTYPE']._serialized_end=10707 + _globals['_TIMELIMITEDACCESSTYPE']._serialized_start=10710 + _globals['_TIMELIMITEDACCESSTYPE']._serialized_end=11058 + _globals['_TIMERNOTIFICATIONTYPE']._serialized_start=11060 + _globals['_TIMERNOTIFICATIONTYPE']._serialized_end=11152 _globals['_RECORDTYPE']._serialized_start=25 _globals['_RECORDTYPE']._serialized_end=117 _globals['_RECORDTYPESREQUEST']._serialized_start=119 @@ -69,135 +69,135 @@ _globals['_RECORD']._serialized_start=496 _globals['_RECORD']._serialized_end=705 _globals['_FOLDERRECORDKEY']._serialized_start=707 - _globals['_FOLDERRECORDKEY']._serialized_end=784 - _globals['_FOLDER']._serialized_start=786 - _globals['_FOLDER']._serialized_end=883 - _globals['_TEAM']._serialized_start=886 - _globals['_TEAM']._serialized_end=1035 - _globals['_RECORDSGETRESPONSE']._serialized_start=1038 - _globals['_RECORDSGETRESPONSE']._serialized_end=1210 - _globals['_RECORDLINK']._serialized_start=1212 - _globals['_RECORDLINK']._serialized_end=1264 - _globals['_RECORDAUDIT']._serialized_start=1266 - _globals['_RECORDAUDIT']._serialized_end=1310 - _globals['_SECURITYDATA']._serialized_start=1312 - _globals['_SECURITYDATA']._serialized_end=1340 - _globals['_SECURITYSCOREDATA']._serialized_start=1342 - _globals['_SECURITYSCOREDATA']._serialized_end=1375 - _globals['_RECORDADD']._serialized_start=1378 - _globals['_RECORDADD']._serialized_end=1766 - _globals['_RECORDSADDREQUEST']._serialized_start=1769 - _globals['_RECORDSADDREQUEST']._serialized_end=1902 - _globals['_RECORDUPDATE']._serialized_start=1905 - _globals['_RECORDUPDATE']._serialized_end=2239 - _globals['_RECORDSUPDATEREQUEST']._serialized_start=2242 - _globals['_RECORDSUPDATEREQUEST']._serialized_end=2381 - _globals['_RECORDFILEFORCONVERSION']._serialized_start=2384 - _globals['_RECORDFILEFORCONVERSION']._serialized_end=2526 - _globals['_RECORDFOLDERFORCONVERSION']._serialized_start=2528 - _globals['_RECORDFOLDERFORCONVERSION']._serialized_end=2602 - _globals['_RECORDCONVERTTOV3']._serialized_start=2605 - _globals['_RECORDCONVERTTOV3']._serialized_end=2879 - _globals['_RECORDSCONVERTTOV3REQUEST']._serialized_start=2881 - _globals['_RECORDSCONVERTTOV3REQUEST']._serialized_end=2974 - _globals['_RECORDSREMOVEREQUEST']._serialized_start=2976 - _globals['_RECORDSREMOVEREQUEST']._serialized_end=3015 - _globals['_RECORDREVERT']._serialized_start=3017 - _globals['_RECORDREVERT']._serialized_end=3079 - _globals['_RECORDSREVERTREQUEST']._serialized_start=3081 - _globals['_RECORDSREVERTREQUEST']._serialized_end=3143 - _globals['_RECORDLINKERROR']._serialized_start=3145 - _globals['_RECORDLINKERROR']._serialized_end=3244 - _globals['_RECORDMODIFYSTATUS']._serialized_start=3247 - _globals['_RECORDMODIFYSTATUS']._serialized_end=3396 - _globals['_RECORDSMODIFYRESPONSE']._serialized_start=3398 - _globals['_RECORDSMODIFYRESPONSE']._serialized_end=3485 - _globals['_RECORDADDAUDITDATA']._serialized_start=3487 - _globals['_RECORDADDAUDITDATA']._serialized_end=3576 - _globals['_ADDAUDITDATAREQUEST']._serialized_start=3578 - _globals['_ADDAUDITDATAREQUEST']._serialized_end=3645 - _globals['_FILE']._serialized_start=3647 - _globals['_FILE']._serialized_end=3763 - _globals['_FILESADDREQUEST']._serialized_start=3765 - _globals['_FILESADDREQUEST']._serialized_end=3833 - _globals['_FILEADDSTATUS']._serialized_start=3836 - _globals['_FILEADDSTATUS']._serialized_end=4003 - _globals['_FILESADDRESPONSE']._serialized_start=4005 - _globals['_FILESADDRESPONSE']._serialized_end=4080 - _globals['_FILESGETREQUEST']._serialized_start=4082 - _globals['_FILESGETREQUEST']._serialized_end=4184 - _globals['_FILEGETSTATUS']._serialized_start=4187 - _globals['_FILEGETSTATUS']._serialized_end=4349 - _globals['_FILESGETRESPONSE']._serialized_start=4351 - _globals['_FILESGETRESPONSE']._serialized_end=4408 - _globals['_APPLICATIONADDREQUEST']._serialized_start=4411 - _globals['_APPLICATIONADDREQUEST']._serialized_end=4552 - _globals['_GETRECORDDATAWITHACCESSINFOREQUEST']._serialized_start=4555 - _globals['_GETRECORDDATAWITHACCESSINFOREQUEST']._serialized_end=4691 - _globals['_USERPERMISSION']._serialized_start=4694 - _globals['_USERPERMISSION']._serialized_end=4956 - _globals['_SHAREDFOLDERPERMISSION']._serialized_start=4959 - _globals['_SHAREDFOLDERPERMISSION']._serialized_end=5175 - _globals['_RECORDDATA']._serialized_start=5178 - _globals['_RECORDDATA']._serialized_end=5538 - _globals['_RECORDDATAWITHACCESSINFO']._serialized_start=5541 - _globals['_RECORDDATAWITHACCESSINFO']._serialized_end=5741 - _globals['_GETRECORDDATAWITHACCESSINFORESPONSE']._serialized_start=5744 - _globals['_GETRECORDDATAWITHACCESSINFORESPONSE']._serialized_end=5881 - _globals['_ISOBJECTSHAREADMIN']._serialized_start=5883 - _globals['_ISOBJECTSHAREADMIN']._serialized_end=5989 - _globals['_AMISHAREADMIN']._serialized_start=5991 - _globals['_AMISHAREADMIN']._serialized_end=6063 - _globals['_RECORDSHAREUPDATEREQUEST']._serialized_start=6066 - _globals['_RECORDSHAREUPDATEREQUEST']._serialized_end=6254 - _globals['_SHAREDRECORD']._serialized_start=6257 - _globals['_SHAREDRECORD']._serialized_end=6581 - _globals['_RECORDSHAREUPDATERESPONSE']._serialized_start=6584 - _globals['_RECORDSHAREUPDATERESPONSE']._serialized_end=6797 - _globals['_SHAREDRECORDSTATUS']._serialized_start=6799 - _globals['_SHAREDRECORDSTATUS']._serialized_end=6889 - _globals['_GETRECORDPERMISSIONSREQUEST']._serialized_start=6891 - _globals['_GETRECORDPERMISSIONSREQUEST']._serialized_end=6962 - _globals['_GETRECORDPERMISSIONSRESPONSE']._serialized_start=6964 - _globals['_GETRECORDPERMISSIONSRESPONSE']._serialized_end=7048 - _globals['_RECORDPERMISSION']._serialized_start=7050 - _globals['_RECORDPERMISSION']._serialized_end=7158 - _globals['_GETSHAREOBJECTSREQUEST']._serialized_start=7160 - _globals['_GETSHAREOBJECTSREQUEST']._serialized_end=7264 - _globals['_GETSHAREOBJECTSRESPONSE']._serialized_start=7267 - _globals['_GETSHAREOBJECTSRESPONSE']._serialized_end=7626 - _globals['_SHAREUSER']._serialized_start=7629 - _globals['_SHAREUSER']._serialized_end=7818 - _globals['_SHARETEAM']._serialized_start=7820 - _globals['_SHARETEAM']._serialized_end=7888 - _globals['_SHAREENTERPRISE']._serialized_start=7890 - _globals['_SHAREENTERPRISE']._serialized_end=7953 - _globals['_RECORDSONWERSHIPTRANSFERREQUEST']._serialized_start=7955 - _globals['_RECORDSONWERSHIPTRANSFERREQUEST']._serialized_end=8038 - _globals['_TRANSFERRECORD']._serialized_start=8040 - _globals['_TRANSFERRECORD']._serialized_end=8131 - _globals['_RECORDSONWERSHIPTRANSFERRESPONSE']._serialized_start=8133 - _globals['_RECORDSONWERSHIPTRANSFERRESPONSE']._serialized_end=8228 - _globals['_TRANSFERRECORDSTATUS']._serialized_start=8230 - _globals['_TRANSFERRECORDSTATUS']._serialized_end=8322 - _globals['_RECORDSUNSHAREREQUEST']._serialized_start=8324 - _globals['_RECORDSUNSHAREREQUEST']._serialized_end=8445 - _globals['_RECORDSUNSHARERESPONSE']._serialized_start=8448 - _globals['_RECORDSUNSHARERESPONSE']._serialized_end=8582 - _globals['_RECORDSUNSHAREFOLDER']._serialized_start=8584 - _globals['_RECORDSUNSHAREFOLDER']._serialized_end=8650 - _globals['_RECORDSUNSHAREUSER']._serialized_start=8652 - _globals['_RECORDSUNSHAREUSER']._serialized_end=8711 - _globals['_RECORDSUNSHAREFOLDERSTATUS']._serialized_start=8713 - _globals['_RECORDSUNSHAREFOLDERSTATUS']._serialized_end=8785 - _globals['_RECORDSUNSHAREUSERSTATUS']._serialized_start=8787 - _globals['_RECORDSUNSHAREUSERSTATUS']._serialized_end=8852 - _globals['_TIMEDACCESSCALLBACKPAYLOAD']._serialized_start=8854 - _globals['_TIMEDACCESSCALLBACKPAYLOAD']._serialized_end=8945 - _globals['_TIMELIMITEDACCESSREQUEST']._serialized_start=8948 - _globals['_TIMELIMITEDACCESSREQUEST']._serialized_end=9201 - _globals['_TIMELIMITEDACCESSSTATUS']._serialized_start=9203 - _globals['_TIMELIMITEDACCESSSTATUS']._serialized_end=9258 - _globals['_TIMELIMITEDACCESSRESPONSE']._serialized_start=9261 - _globals['_TIMELIMITEDACCESSRESPONSE']._serialized_end=9488 + _globals['_FOLDERRECORDKEY']._serialized_end=833 + _globals['_FOLDER']._serialized_start=835 + _globals['_FOLDER']._serialized_end=932 + _globals['_TEAM']._serialized_start=935 + _globals['_TEAM']._serialized_end=1084 + _globals['_RECORDSGETRESPONSE']._serialized_start=1087 + _globals['_RECORDSGETRESPONSE']._serialized_end=1259 + _globals['_RECORDLINK']._serialized_start=1261 + _globals['_RECORDLINK']._serialized_end=1313 + _globals['_RECORDAUDIT']._serialized_start=1315 + _globals['_RECORDAUDIT']._serialized_end=1359 + _globals['_SECURITYDATA']._serialized_start=1361 + _globals['_SECURITYDATA']._serialized_end=1389 + _globals['_SECURITYSCOREDATA']._serialized_start=1391 + _globals['_SECURITYSCOREDATA']._serialized_end=1424 + _globals['_RECORDADD']._serialized_start=1427 + _globals['_RECORDADD']._serialized_end=1815 + _globals['_RECORDSADDREQUEST']._serialized_start=1818 + _globals['_RECORDSADDREQUEST']._serialized_end=1951 + _globals['_RECORDUPDATE']._serialized_start=1954 + _globals['_RECORDUPDATE']._serialized_end=2288 + _globals['_RECORDSUPDATEREQUEST']._serialized_start=2291 + _globals['_RECORDSUPDATEREQUEST']._serialized_end=2430 + _globals['_RECORDFILEFORCONVERSION']._serialized_start=2433 + _globals['_RECORDFILEFORCONVERSION']._serialized_end=2575 + _globals['_RECORDFOLDERFORCONVERSION']._serialized_start=2577 + _globals['_RECORDFOLDERFORCONVERSION']._serialized_end=2651 + _globals['_RECORDCONVERTTOV3']._serialized_start=2654 + _globals['_RECORDCONVERTTOV3']._serialized_end=2928 + _globals['_RECORDSCONVERTTOV3REQUEST']._serialized_start=2930 + _globals['_RECORDSCONVERTTOV3REQUEST']._serialized_end=3023 + _globals['_RECORDSREMOVEREQUEST']._serialized_start=3025 + _globals['_RECORDSREMOVEREQUEST']._serialized_end=3064 + _globals['_RECORDREVERT']._serialized_start=3066 + _globals['_RECORDREVERT']._serialized_end=3128 + _globals['_RECORDSREVERTREQUEST']._serialized_start=3130 + _globals['_RECORDSREVERTREQUEST']._serialized_end=3192 + _globals['_RECORDLINKERROR']._serialized_start=3194 + _globals['_RECORDLINKERROR']._serialized_end=3293 + _globals['_RECORDMODIFYSTATUS']._serialized_start=3296 + _globals['_RECORDMODIFYSTATUS']._serialized_end=3445 + _globals['_RECORDSMODIFYRESPONSE']._serialized_start=3447 + _globals['_RECORDSMODIFYRESPONSE']._serialized_end=3534 + _globals['_RECORDADDAUDITDATA']._serialized_start=3536 + _globals['_RECORDADDAUDITDATA']._serialized_end=3625 + _globals['_ADDAUDITDATAREQUEST']._serialized_start=3627 + _globals['_ADDAUDITDATAREQUEST']._serialized_end=3694 + _globals['_FILE']._serialized_start=3696 + _globals['_FILE']._serialized_end=3812 + _globals['_FILESADDREQUEST']._serialized_start=3814 + _globals['_FILESADDREQUEST']._serialized_end=3882 + _globals['_FILEADDSTATUS']._serialized_start=3885 + _globals['_FILEADDSTATUS']._serialized_end=4052 + _globals['_FILESADDRESPONSE']._serialized_start=4054 + _globals['_FILESADDRESPONSE']._serialized_end=4129 + _globals['_FILESGETREQUEST']._serialized_start=4131 + _globals['_FILESGETREQUEST']._serialized_end=4233 + _globals['_FILEGETSTATUS']._serialized_start=4236 + _globals['_FILEGETSTATUS']._serialized_end=4398 + _globals['_FILESGETRESPONSE']._serialized_start=4400 + _globals['_FILESGETRESPONSE']._serialized_end=4457 + _globals['_APPLICATIONADDREQUEST']._serialized_start=4460 + _globals['_APPLICATIONADDREQUEST']._serialized_end=4601 + _globals['_GETRECORDDATAWITHACCESSINFOREQUEST']._serialized_start=4604 + _globals['_GETRECORDDATAWITHACCESSINFOREQUEST']._serialized_end=4740 + _globals['_USERPERMISSION']._serialized_start=4743 + _globals['_USERPERMISSION']._serialized_end=5005 + _globals['_SHAREDFOLDERPERMISSION']._serialized_start=5008 + _globals['_SHAREDFOLDERPERMISSION']._serialized_end=5224 + _globals['_RECORDDATA']._serialized_start=5227 + _globals['_RECORDDATA']._serialized_end=5587 + _globals['_RECORDDATAWITHACCESSINFO']._serialized_start=5590 + _globals['_RECORDDATAWITHACCESSINFO']._serialized_end=5790 + _globals['_GETRECORDDATAWITHACCESSINFORESPONSE']._serialized_start=5793 + _globals['_GETRECORDDATAWITHACCESSINFORESPONSE']._serialized_end=5930 + _globals['_ISOBJECTSHAREADMIN']._serialized_start=5932 + _globals['_ISOBJECTSHAREADMIN']._serialized_end=6038 + _globals['_AMISHAREADMIN']._serialized_start=6040 + _globals['_AMISHAREADMIN']._serialized_end=6112 + _globals['_RECORDSHAREUPDATEREQUEST']._serialized_start=6115 + _globals['_RECORDSHAREUPDATEREQUEST']._serialized_end=6303 + _globals['_SHAREDRECORD']._serialized_start=6306 + _globals['_SHAREDRECORD']._serialized_end=6630 + _globals['_RECORDSHAREUPDATERESPONSE']._serialized_start=6633 + _globals['_RECORDSHAREUPDATERESPONSE']._serialized_end=6846 + _globals['_SHAREDRECORDSTATUS']._serialized_start=6848 + _globals['_SHAREDRECORDSTATUS']._serialized_end=6938 + _globals['_GETRECORDPERMISSIONSREQUEST']._serialized_start=6940 + _globals['_GETRECORDPERMISSIONSREQUEST']._serialized_end=7011 + _globals['_GETRECORDPERMISSIONSRESPONSE']._serialized_start=7013 + _globals['_GETRECORDPERMISSIONSRESPONSE']._serialized_end=7097 + _globals['_RECORDPERMISSION']._serialized_start=7099 + _globals['_RECORDPERMISSION']._serialized_end=7207 + _globals['_GETSHAREOBJECTSREQUEST']._serialized_start=7209 + _globals['_GETSHAREOBJECTSREQUEST']._serialized_end=7313 + _globals['_GETSHAREOBJECTSRESPONSE']._serialized_start=7316 + _globals['_GETSHAREOBJECTSRESPONSE']._serialized_end=7675 + _globals['_SHAREUSER']._serialized_start=7678 + _globals['_SHAREUSER']._serialized_end=7867 + _globals['_SHARETEAM']._serialized_start=7869 + _globals['_SHARETEAM']._serialized_end=7937 + _globals['_SHAREENTERPRISE']._serialized_start=7939 + _globals['_SHAREENTERPRISE']._serialized_end=8002 + _globals['_RECORDSONWERSHIPTRANSFERREQUEST']._serialized_start=8004 + _globals['_RECORDSONWERSHIPTRANSFERREQUEST']._serialized_end=8087 + _globals['_TRANSFERRECORD']._serialized_start=8089 + _globals['_TRANSFERRECORD']._serialized_end=8180 + _globals['_RECORDSONWERSHIPTRANSFERRESPONSE']._serialized_start=8182 + _globals['_RECORDSONWERSHIPTRANSFERRESPONSE']._serialized_end=8277 + _globals['_TRANSFERRECORDSTATUS']._serialized_start=8279 + _globals['_TRANSFERRECORDSTATUS']._serialized_end=8371 + _globals['_RECORDSUNSHAREREQUEST']._serialized_start=8373 + _globals['_RECORDSUNSHAREREQUEST']._serialized_end=8494 + _globals['_RECORDSUNSHARERESPONSE']._serialized_start=8497 + _globals['_RECORDSUNSHARERESPONSE']._serialized_end=8631 + _globals['_RECORDSUNSHAREFOLDER']._serialized_start=8633 + _globals['_RECORDSUNSHAREFOLDER']._serialized_end=8699 + _globals['_RECORDSUNSHAREUSER']._serialized_start=8701 + _globals['_RECORDSUNSHAREUSER']._serialized_end=8760 + _globals['_RECORDSUNSHAREFOLDERSTATUS']._serialized_start=8762 + _globals['_RECORDSUNSHAREFOLDERSTATUS']._serialized_end=8834 + _globals['_RECORDSUNSHAREUSERSTATUS']._serialized_start=8836 + _globals['_RECORDSUNSHAREUSERSTATUS']._serialized_end=8901 + _globals['_TIMEDACCESSCALLBACKPAYLOAD']._serialized_start=8903 + _globals['_TIMEDACCESSCALLBACKPAYLOAD']._serialized_end=8994 + _globals['_TIMELIMITEDACCESSREQUEST']._serialized_start=8997 + _globals['_TIMELIMITEDACCESSREQUEST']._serialized_end=9250 + _globals['_TIMELIMITEDACCESSSTATUS']._serialized_start=9252 + _globals['_TIMELIMITEDACCESSSTATUS']._serialized_end=9307 + _globals['_TIMELIMITEDACCESSRESPONSE']._serialized_start=9310 + _globals['_TIMELIMITEDACCESSRESPONSE']._serialized_end=9537 # @@protoc_insertion_point(module_scope) diff --git a/keepercommander/proto/record_pb2.pyi b/keepercommander/proto/record_pb2.pyi index 19b58230f..aae6f7158 100644 --- a/keepercommander/proto/record_pb2.pyi +++ b/keepercommander/proto/record_pb2.pyi @@ -176,7 +176,7 @@ class RecordTypesRequest(_message.Message): user: bool enterprise: bool pam: bool - def __init__(self, standard: bool = ..., user: bool = ..., enterprise: bool = ..., pam: bool = ...) -> None: ... + def __init__(self, standard: _Optional[bool] = ..., user: _Optional[bool] = ..., enterprise: _Optional[bool] = ..., pam: _Optional[bool] = ...) -> None: ... class RecordTypesResponse(_message.Message): __slots__ = ("recordTypes", "standardCounter", "userCounter", "enterpriseCounter", "pamCounter") @@ -231,14 +231,16 @@ class Record(_message.Message): def __init__(self, record_uid: _Optional[bytes] = ..., record_key: _Optional[bytes] = ..., record_key_type: _Optional[_Union[RecordKeyType, str]] = ..., data: _Optional[bytes] = ..., extra: _Optional[bytes] = ..., version: _Optional[int] = ..., client_modified_time: _Optional[int] = ..., revision: _Optional[int] = ..., file_ids: _Optional[_Iterable[bytes]] = ...) -> None: ... class FolderRecordKey(_message.Message): - __slots__ = ("folder_uid", "record_uid", "record_key") + __slots__ = ("folder_uid", "record_uid", "record_key", "record_key_type") FOLDER_UID_FIELD_NUMBER: _ClassVar[int] RECORD_UID_FIELD_NUMBER: _ClassVar[int] RECORD_KEY_FIELD_NUMBER: _ClassVar[int] + RECORD_KEY_TYPE_FIELD_NUMBER: _ClassVar[int] folder_uid: bytes record_uid: bytes record_key: bytes - def __init__(self, folder_uid: _Optional[bytes] = ..., record_uid: _Optional[bytes] = ..., record_key: _Optional[bytes] = ...) -> None: ... + record_key_type: RecordKeyType + def __init__(self, folder_uid: _Optional[bytes] = ..., record_uid: _Optional[bytes] = ..., record_key: _Optional[bytes] = ..., record_key_type: _Optional[_Union[RecordKeyType, str]] = ...) -> None: ... class Folder(_message.Message): __slots__ = ("folder_uid", "folder_key", "folder_key_type") @@ -510,7 +512,7 @@ class File(_message.Message): fileSize: int thumbSize: int is_script: bool - def __init__(self, record_uid: _Optional[bytes] = ..., record_key: _Optional[bytes] = ..., data: _Optional[bytes] = ..., fileSize: _Optional[int] = ..., thumbSize: _Optional[int] = ..., is_script: bool = ...) -> None: ... + def __init__(self, record_uid: _Optional[bytes] = ..., record_key: _Optional[bytes] = ..., data: _Optional[bytes] = ..., fileSize: _Optional[int] = ..., thumbSize: _Optional[int] = ..., is_script: _Optional[bool] = ...) -> None: ... class FilesAddRequest(_message.Message): __slots__ = ("files", "client_time") @@ -552,7 +554,7 @@ class FilesGetRequest(_message.Message): record_uids: _containers.RepeatedScalarFieldContainer[bytes] for_thumbnails: bool emergency_access_account_owner: str - def __init__(self, record_uids: _Optional[_Iterable[bytes]] = ..., for_thumbnails: bool = ..., emergency_access_account_owner: _Optional[str] = ...) -> None: ... + def __init__(self, record_uids: _Optional[_Iterable[bytes]] = ..., for_thumbnails: _Optional[bool] = ..., emergency_access_account_owner: _Optional[str] = ...) -> None: ... class FileGetStatus(_message.Message): __slots__ = ("record_uid", "status", "url", "success_status_code", "fileKeyType") @@ -620,7 +622,7 @@ class UserPermission(_message.Message): accountUid: bytes timerNotificationType: TimerNotificationType rotateOnExpiration: bool - def __init__(self, username: _Optional[str] = ..., owner: bool = ..., shareAdmin: bool = ..., sharable: bool = ..., editable: bool = ..., awaitingApproval: bool = ..., expiration: _Optional[int] = ..., accountUid: _Optional[bytes] = ..., timerNotificationType: _Optional[_Union[TimerNotificationType, str]] = ..., rotateOnExpiration: bool = ...) -> None: ... + def __init__(self, username: _Optional[str] = ..., owner: _Optional[bool] = ..., shareAdmin: _Optional[bool] = ..., sharable: _Optional[bool] = ..., editable: _Optional[bool] = ..., awaitingApproval: _Optional[bool] = ..., expiration: _Optional[int] = ..., accountUid: _Optional[bytes] = ..., timerNotificationType: _Optional[_Union[TimerNotificationType, str]] = ..., rotateOnExpiration: _Optional[bool] = ...) -> None: ... class SharedFolderPermission(_message.Message): __slots__ = ("sharedFolderUid", "resharable", "editable", "revision", "expiration", "timerNotificationType", "rotateOnExpiration") @@ -638,7 +640,7 @@ class SharedFolderPermission(_message.Message): expiration: int timerNotificationType: TimerNotificationType rotateOnExpiration: bool - def __init__(self, sharedFolderUid: _Optional[bytes] = ..., resharable: bool = ..., editable: bool = ..., revision: _Optional[int] = ..., expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[TimerNotificationType, str]] = ..., rotateOnExpiration: bool = ...) -> None: ... + def __init__(self, sharedFolderUid: _Optional[bytes] = ..., resharable: _Optional[bool] = ..., editable: _Optional[bool] = ..., revision: _Optional[int] = ..., expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[TimerNotificationType, str]] = ..., rotateOnExpiration: _Optional[bool] = ...) -> None: ... class RecordData(_message.Message): __slots__ = ("revision", "version", "shared", "encryptedRecordData", "encryptedExtraData", "clientModifiedTime", "nonSharedData", "linkedRecordData", "fileId", "fileSize", "thumbnailSize", "recordKeyType", "recordKey", "recordUid") @@ -670,7 +672,7 @@ class RecordData(_message.Message): recordKeyType: RecordKeyType recordKey: bytes recordUid: bytes - def __init__(self, revision: _Optional[int] = ..., version: _Optional[int] = ..., shared: bool = ..., encryptedRecordData: _Optional[str] = ..., encryptedExtraData: _Optional[str] = ..., clientModifiedTime: _Optional[int] = ..., nonSharedData: _Optional[str] = ..., linkedRecordData: _Optional[_Iterable[_Union[RecordData, _Mapping]]] = ..., fileId: _Optional[_Iterable[bytes]] = ..., fileSize: _Optional[int] = ..., thumbnailSize: _Optional[int] = ..., recordKeyType: _Optional[_Union[RecordKeyType, str]] = ..., recordKey: _Optional[bytes] = ..., recordUid: _Optional[bytes] = ...) -> None: ... + def __init__(self, revision: _Optional[int] = ..., version: _Optional[int] = ..., shared: _Optional[bool] = ..., encryptedRecordData: _Optional[str] = ..., encryptedExtraData: _Optional[str] = ..., clientModifiedTime: _Optional[int] = ..., nonSharedData: _Optional[str] = ..., linkedRecordData: _Optional[_Iterable[_Union[RecordData, _Mapping]]] = ..., fileId: _Optional[_Iterable[bytes]] = ..., fileSize: _Optional[int] = ..., thumbnailSize: _Optional[int] = ..., recordKeyType: _Optional[_Union[RecordKeyType, str]] = ..., recordKey: _Optional[bytes] = ..., recordUid: _Optional[bytes] = ...) -> None: ... class RecordDataWithAccessInfo(_message.Message): __slots__ = ("recordUid", "recordData", "userPermission", "sharedFolderPermission") @@ -700,7 +702,7 @@ class IsObjectShareAdmin(_message.Message): uid: bytes isAdmin: bool objectType: CheckShareAdminObjectType - def __init__(self, uid: _Optional[bytes] = ..., isAdmin: bool = ..., objectType: _Optional[_Union[CheckShareAdminObjectType, str]] = ...) -> None: ... + def __init__(self, uid: _Optional[bytes] = ..., isAdmin: _Optional[bool] = ..., objectType: _Optional[_Union[CheckShareAdminObjectType, str]] = ...) -> None: ... class AmIShareAdmin(_message.Message): __slots__ = ("isObjectShareAdmin",) @@ -748,7 +750,7 @@ class SharedRecord(_message.Message): expiration: int timerNotificationType: TimerNotificationType rotateOnExpiration: bool - def __init__(self, toUsername: _Optional[str] = ..., recordUid: _Optional[bytes] = ..., recordKey: _Optional[bytes] = ..., sharedFolderUid: _Optional[bytes] = ..., teamUid: _Optional[bytes] = ..., editable: bool = ..., shareable: bool = ..., transfer: bool = ..., useEccKey: bool = ..., removeVaultData: bool = ..., expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[TimerNotificationType, str]] = ..., rotateOnExpiration: bool = ...) -> None: ... + def __init__(self, toUsername: _Optional[str] = ..., recordUid: _Optional[bytes] = ..., recordKey: _Optional[bytes] = ..., sharedFolderUid: _Optional[bytes] = ..., teamUid: _Optional[bytes] = ..., editable: _Optional[bool] = ..., shareable: _Optional[bool] = ..., transfer: _Optional[bool] = ..., useEccKey: _Optional[bool] = ..., removeVaultData: _Optional[bool] = ..., expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[TimerNotificationType, str]] = ..., rotateOnExpiration: _Optional[bool] = ...) -> None: ... class RecordShareUpdateResponse(_message.Message): __slots__ = ("addSharedRecordStatus", "updateSharedRecordStatus", "removeSharedRecordStatus") @@ -778,7 +780,7 @@ class GetRecordPermissionsRequest(_message.Message): ISSHAREADMIN_FIELD_NUMBER: _ClassVar[int] recordUids: _containers.RepeatedScalarFieldContainer[bytes] isShareAdmin: bool - def __init__(self, recordUids: _Optional[_Iterable[bytes]] = ..., isShareAdmin: bool = ...) -> None: ... + def __init__(self, recordUids: _Optional[_Iterable[bytes]] = ..., isShareAdmin: _Optional[bool] = ...) -> None: ... class GetRecordPermissionsResponse(_message.Message): __slots__ = ("recordPermissions",) @@ -798,7 +800,7 @@ class RecordPermission(_message.Message): canEdit: bool canShare: bool canTransfer: bool - def __init__(self, recordUid: _Optional[bytes] = ..., owner: bool = ..., canEdit: bool = ..., canShare: bool = ..., canTransfer: bool = ...) -> None: ... + def __init__(self, recordUid: _Optional[bytes] = ..., owner: _Optional[bool] = ..., canEdit: _Optional[bool] = ..., canShare: _Optional[bool] = ..., canTransfer: _Optional[bool] = ...) -> None: ... class GetShareObjectsRequest(_message.Message): __slots__ = ("startWith", "contains", "filtered", "sharedFolderUid") @@ -810,7 +812,7 @@ class GetShareObjectsRequest(_message.Message): contains: str filtered: bool sharedFolderUid: bytes - def __init__(self, startWith: _Optional[str] = ..., contains: _Optional[str] = ..., filtered: bool = ..., sharedFolderUid: _Optional[bytes] = ...) -> None: ... + def __init__(self, startWith: _Optional[str] = ..., contains: _Optional[str] = ..., filtered: _Optional[bool] = ..., sharedFolderUid: _Optional[bytes] = ...) -> None: ... class GetShareObjectsResponse(_message.Message): __slots__ = ("shareRelationships", "shareFamilyUsers", "shareEnterpriseUsers", "shareTeams", "shareMCTeams", "shareMCEnterpriseUsers", "shareEnterpriseNames") @@ -846,7 +848,7 @@ class ShareUser(_message.Message): isShareAdmin: bool isAdminOfSharedFolderOwner: bool userAccountUid: bytes - def __init__(self, username: _Optional[str] = ..., fullname: _Optional[str] = ..., enterpriseId: _Optional[int] = ..., status: _Optional[_Union[ShareStatus, str]] = ..., isShareAdmin: bool = ..., isAdminOfSharedFolderOwner: bool = ..., userAccountUid: _Optional[bytes] = ...) -> None: ... + def __init__(self, username: _Optional[str] = ..., fullname: _Optional[str] = ..., enterpriseId: _Optional[int] = ..., status: _Optional[_Union[ShareStatus, str]] = ..., isShareAdmin: _Optional[bool] = ..., isAdminOfSharedFolderOwner: _Optional[bool] = ..., userAccountUid: _Optional[bytes] = ...) -> None: ... class ShareTeam(_message.Message): __slots__ = ("teamname", "enterpriseId", "teamUid") @@ -882,7 +884,7 @@ class TransferRecord(_message.Message): recordUid: bytes recordKey: bytes useEccKey: bool - def __init__(self, username: _Optional[str] = ..., recordUid: _Optional[bytes] = ..., recordKey: _Optional[bytes] = ..., useEccKey: bool = ...) -> None: ... + def __init__(self, username: _Optional[str] = ..., recordUid: _Optional[bytes] = ..., recordKey: _Optional[bytes] = ..., useEccKey: _Optional[bool] = ...) -> None: ... class RecordsOnwershipTransferResponse(_message.Message): __slots__ = ("transferRecordStatus",) diff --git a/keepercommander/proto/record_sharing_pb2.pyi b/keepercommander/proto/record_sharing_pb2.pyi index c5f25e8db..18bd3db39 100644 --- a/keepercommander/proto/record_sharing_pb2.pyi +++ b/keepercommander/proto/record_sharing_pb2.pyi @@ -50,7 +50,7 @@ class Permissions(_message.Message): recordKey: bytes useEccKey: bool rules: _folder_pb2.RecordAccessData - def __init__(self, recipientUid: _Optional[bytes] = ..., recordUid: _Optional[bytes] = ..., recordKey: _Optional[bytes] = ..., useEccKey: bool = ..., rules: _Optional[_Union[_folder_pb2.RecordAccessData, _Mapping]] = ...) -> None: ... + def __init__(self, recipientUid: _Optional[bytes] = ..., recordUid: _Optional[bytes] = ..., recordKey: _Optional[bytes] = ..., useEccKey: _Optional[bool] = ..., rules: _Optional[_Union[_folder_pb2.RecordAccessData, _Mapping]] = ...) -> None: ... class Response(_message.Message): __slots__ = ("createdSharingStatus", "updatedSharingStatus", "revokedSharingStatus") @@ -92,4 +92,4 @@ class RecordSharingState(_message.Message): isDirectlyShared: bool isIndirectlyShared: bool isShared: bool - def __init__(self, recordUid: _Optional[bytes] = ..., isDirectlyShared: bool = ..., isIndirectlyShared: bool = ..., isShared: bool = ...) -> None: ... + def __init__(self, recordUid: _Optional[bytes] = ..., isDirectlyShared: _Optional[bool] = ..., isIndirectlyShared: _Optional[bool] = ..., isShared: _Optional[bool] = ...) -> None: ... diff --git a/keepercommander/proto/remove_pb2.py b/keepercommander/proto/remove_pb2.py index 3e2d50dd0..5cbc374a2 100644 --- a/keepercommander/proto/remove_pb2.py +++ b/keepercommander/proto/remove_pb2.py @@ -25,7 +25,7 @@ from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cremove.proto\x12\x10\x66older.v3.remove\x1a\x1cgoogle/api/annotations.proto\"v\n\rRecordRemoval\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_uid\x18\x02 \x01(\x0c\x12=\n\x0eoperation_type\x18\x03 \x01(\x0e\x32%.folder.v3.remove.RecordOperationType\"b\n\rFolderRemoval\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12=\n\x0eoperation_type\x18\x02 \x01(\x0e\x32%.folder.v3.remove.FolderOperationType\"\x93\x01\n\x13RemoveRecordRequest\x12.\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x1e.folder.v3.remove.RemoveAction\x12\x30\n\x07records\x18\x02 \x03(\x0b\x32\x1f.folder.v3.remove.RecordRemoval\x12\x1a\n\x12\x63onfirmation_token\x18\x03 \x01(\x0c\"\x93\x01\n\x13RemoveFolderRequest\x12.\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x1e.folder.v3.remove.RemoveAction\x12\x30\n\x07\x66olders\x18\x02 \x03(\x0b\x32\x1f.folder.v3.remove.FolderRemoval\x12\x1a\n\x12\x63onfirmation_token\x18\x03 \x01(\x0c\"\x8e\x01\n\x0eRemoveResponse\x12\x1a\n\x12\x63onfirmation_token\x18\x01 \x01(\x0c\x12\x18\n\x10token_expires_at\x18\x02 \x01(\x03\x12/\n\x07results\x18\x03 \x03(\x0b\x32\x1e.folder.v3.remove.RemoveResult\x12\x15\n\rerror_message\x18\x04 \x01(\t\"\xba\x01\n\x0cRemoveResult\x12\x10\n\x08item_uid\x18\x01 \x01(\x0c\x12\x12\n\nfolder_uid\x18\x02 \x01(\x0c\x12.\n\x06status\x18\x03 \x01(\x0e\x32\x1e.folder.v3.remove.RemoveStatus\x12(\n\x06impact\x18\x04 \x01(\x0b\x32\x18.folder.v3.remove.Impact\x12*\n\x05\x65rror\x18\x05 \x01(\x0b\x32\x1b.folder.v3.remove.ItemError\"\xb7\x01\n\x06Impact\x12\x15\n\rfolders_count\x18\x01 \x01(\x05\x12\x15\n\rrecords_count\x18\x02 \x01(\x05\x12\x1c\n\x14\x61\x66\x66\x65\x63ted_users_count\x18\x03 \x01(\x05\x12\x1c\n\x14\x61\x66\x66\x65\x63ted_teams_count\x18\x04 \x01(\x05\x12\x31\n\x0brecord_info\x18\x05 \x03(\x0b\x32\x1c.folder.v3.remove.RecordInfo\x12\x10\n\x08warnings\x18\x06 \x03(\t\"9\n\nRecordInfo\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x17\n\x0flocations_count\x18\x02 \x01(\x05\"M\n\tItemError\x12/\n\x04\x63ode\x18\x01 \x01(\x0e\x32!.folder.v3.remove.RemoveErrorCode\x12\x0f\n\x07message\x18\x02 \x01(\t\"\xa7\x01\n\x13RemovalTokenPayload\x12<\n\x11item_fingerprints\x18\x01 \x03(\x0b\x32!.folder.v3.remove.ItemFingerprint\x12\x0f\n\x07user_id\x18\x02 \x01(\x05\x12\x11\n\tdevice_id\x18\x03 \x01(\x03\x12\x13\n\x0bsession_uid\x18\x04 \x01(\x0c\x12\x19\n\x11\x65xpires_at_millis\x18\x05 \x01(\x03\"\x94\x01\n\x0fItemFingerprint\x12\x30\n\x06record\x18\x01 \x01(\x0b\x32\x1e.folder.v3.remove.RecordTargetH\x00\x12\x30\n\x06\x66older\x18\x02 \x01(\x0b\x32\x1e.folder.v3.remove.FolderTargetH\x00\x12\x13\n\x0b\x66ingerprint\x18\n \x01(\x0c\x42\x08\n\x06target\"u\n\x0cRecordTarget\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_uid\x18\x02 \x01(\x0c\x12=\n\x0eoperation_type\x18\x03 \x01(\x0e\x32%.folder.v3.remove.RecordOperationType\"a\n\x0c\x46olderTarget\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12=\n\x0eoperation_type\x18\x02 \x01(\x0e\x32%.folder.v3.remove.FolderOperationType*D\n\x0cRemoveAction\x12\x19\n\x15REMOVE_ACTION_PREVIEW\x10\x00\x12\x19\n\x15REMOVE_ACTION_CONFIRM\x10\x01*~\n\x13RecordOperationType\x12\x1c\n\x18RECORD_OPERATION_UNKNOWN\x10\x00\x12\x16\n\x12UNLINK_FROM_FOLDER\x10\x01\x12\x18\n\x14MOVE_TO_FOLDER_TRASH\x10\x02\x12\x17\n\x13MOVE_TO_OWNER_TRASH\x10\x03*\x91\x01\n\x13\x46olderOperationType\x12\x1c\n\x18\x46OLDER_OPERATION_UNKNOWN\x10\x00\x12\x1f\n\x1b\x46OLDER_MOVE_TO_FOLDER_TRASH\x10\x01\x12\x1e\n\x1a\x46OLDER_MOVE_TO_OWNER_TRASH\x10\x02\x12\x1b\n\x17\x46OLDER_DELETE_PERMANENT\x10\x03*\xcb\x01\n\x0fRemoveErrorCode\x12\x18\n\x14REMOVE_ERROR_UNKNOWN\x10\x00\x12\x1a\n\x16REMOVE_ERROR_NOT_FOUND\x10\x01\x12\x1e\n\x1aREMOVE_ERROR_ACCESS_DENIED\x10\x02\x12 \n\x1cREMOVE_ERROR_TRASHCAN_FOLDER\x10\x03\x12\x1c\n\x18REMOVE_ERROR_ROOT_FOLDER\x10\x04\x12\"\n\x1eREMOVE_ERROR_DESCENDANT_DENIED\x10\x05*\xec\x01\n\x0cRemoveStatus\x12\x19\n\x15REMOVE_STATUS_UNKNOWN\x10\x00\x12\x19\n\x15REMOVE_STATUS_SUCCESS\x10\x01\x12\x1f\n\x1bREMOVE_STATUS_STALE_PREVIEW\x10\x02\x12\x1f\n\x1bREMOVE_STATUS_TOKEN_EXPIRED\x10\x03\x12\x1f\n\x1bREMOVE_STATUS_TOKEN_INVALID\x10\x04\x12\x1f\n\x1bREMOVE_STATUS_ACCESS_DENIED\x10\x05\x12\"\n\x1eREMOVE_STATUS_VALIDATION_ERROR\x10\x06\x32\xad\x02\n\rRemoveService\x12\x8c\x01\n\x0cRemoveRecord\x12%.folder.v3.remove.RemoveRecordRequest\x1a .folder.v3.remove.RemoveResponse\"3\x82\xd3\xe4\x93\x02-\"(/api/rest/vault/folders/v3/remove_record:\x01*\x12\x8c\x01\n\x0cRemoveFolder\x12%.folder.v3.remove.RemoveFolderRequest\x1a .folder.v3.remove.RemoveResponse\"3\x82\xd3\xe4\x93\x02-\"(/api/rest/vault/folders/v3/remove_folder:\x01*B1\n-com.keepersecurity.proto.api.folder.v3.removeP\x01\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cremove.proto\x12\x10\x66older.v3.remove\x1a\x1cgoogle/api/annotations.proto\"v\n\rRecordRemoval\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_uid\x18\x02 \x01(\x0c\x12=\n\x0eoperation_type\x18\x03 \x01(\x0e\x32%.folder.v3.remove.RecordOperationType\"b\n\rFolderRemoval\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12=\n\x0eoperation_type\x18\x02 \x01(\x0e\x32%.folder.v3.remove.FolderOperationType\"\x93\x01\n\x13RemoveRecordRequest\x12.\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x1e.folder.v3.remove.RemoveAction\x12\x30\n\x07records\x18\x02 \x03(\x0b\x32\x1f.folder.v3.remove.RecordRemoval\x12\x1a\n\x12\x63onfirmation_token\x18\x03 \x01(\x0c\"\x93\x01\n\x13RemoveFolderRequest\x12.\n\x06\x61\x63tion\x18\x01 \x01(\x0e\x32\x1e.folder.v3.remove.RemoveAction\x12\x30\n\x07\x66olders\x18\x02 \x03(\x0b\x32\x1f.folder.v3.remove.FolderRemoval\x12\x1a\n\x12\x63onfirmation_token\x18\x03 \x01(\x0c\"\x8e\x01\n\x0eRemoveResponse\x12\x1a\n\x12\x63onfirmation_token\x18\x01 \x01(\x0c\x12\x18\n\x10token_expires_at\x18\x02 \x01(\x03\x12/\n\x07results\x18\x03 \x03(\x0b\x32\x1e.folder.v3.remove.RemoveResult\x12\x15\n\rerror_message\x18\x04 \x01(\t\"\xba\x01\n\x0cRemoveResult\x12\x10\n\x08item_uid\x18\x01 \x01(\x0c\x12\x12\n\nfolder_uid\x18\x02 \x01(\x0c\x12.\n\x06status\x18\x03 \x01(\x0e\x32\x1e.folder.v3.remove.RemoveStatus\x12(\n\x06impact\x18\x04 \x01(\x0b\x32\x18.folder.v3.remove.Impact\x12*\n\x05\x65rror\x18\x05 \x01(\x0b\x32\x1b.folder.v3.remove.ItemError\"\xb7\x01\n\x06Impact\x12\x15\n\rfolders_count\x18\x01 \x01(\x05\x12\x15\n\rrecords_count\x18\x02 \x01(\x05\x12\x1c\n\x14\x61\x66\x66\x65\x63ted_users_count\x18\x03 \x01(\x05\x12\x1c\n\x14\x61\x66\x66\x65\x63ted_teams_count\x18\x04 \x01(\x05\x12\x31\n\x0brecord_info\x18\x05 \x03(\x0b\x32\x1c.folder.v3.remove.RecordInfo\x12\x10\n\x08warnings\x18\x06 \x03(\t\"9\n\nRecordInfo\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x17\n\x0flocations_count\x18\x02 \x01(\x05\"M\n\tItemError\x12/\n\x04\x63ode\x18\x01 \x01(\x0e\x32!.folder.v3.remove.RemoveErrorCode\x12\x0f\n\x07message\x18\x02 \x01(\t\"\xa7\x01\n\x13RemovalTokenPayload\x12<\n\x11item_fingerprints\x18\x01 \x03(\x0b\x32!.folder.v3.remove.ItemFingerprint\x12\x0f\n\x07user_id\x18\x02 \x01(\x05\x12\x11\n\tdevice_id\x18\x03 \x01(\x03\x12\x13\n\x0bsession_uid\x18\x04 \x01(\x0c\x12\x19\n\x11\x65xpires_at_millis\x18\x05 \x01(\x03\"\x94\x01\n\x0fItemFingerprint\x12\x30\n\x06record\x18\x01 \x01(\x0b\x32\x1e.folder.v3.remove.RecordTargetH\x00\x12\x30\n\x06\x66older\x18\x02 \x01(\x0b\x32\x1e.folder.v3.remove.FolderTargetH\x00\x12\x13\n\x0b\x66ingerprint\x18\n \x01(\x0c\x42\x08\n\x06target\"u\n\x0cRecordTarget\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x12\n\nrecord_uid\x18\x02 \x01(\x0c\x12=\n\x0eoperation_type\x18\x03 \x01(\x0e\x32%.folder.v3.remove.RecordOperationType\"a\n\x0c\x46olderTarget\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12=\n\x0eoperation_type\x18\x02 \x01(\x0e\x32%.folder.v3.remove.FolderOperationType\"\x9f\x01\n\rRestoreResult\x12\x10\n\x08item_uid\x18\x01 \x01(\x0c\x12\x34\n\titem_type\x18\x02 \x01(\x0e\x32!.folder.v3.remove.RestoreItemType\x12/\n\x06status\x18\x03 \x01(\x0e\x32\x1f.folder.v3.remove.RestoreStatus\x12\x15\n\rerror_message\x18\x04 \x01(\t\"b\n\x17TrashcanRestoreResponse\x12\x30\n\x07results\x18\x01 \x03(\x0b\x32\x1f.folder.v3.remove.RestoreResult\x12\x15\n\rerror_message\x18\x02 \x01(\t\"\\\n\rRestoreRecord\x12\x12\n\nrecord_uid\x18\x01 \x01(\x0c\x12\x1c\n\x14\x65ncrypted_record_key\x18\x02 \x01(\x0c\x12\x19\n\x11source_folder_uid\x18\x03 \x01(\x0c\"A\n\rRestoreFolder\x12\x12\n\nfolder_uid\x18\x01 \x01(\x0c\x12\x1c\n\x14\x65ncrypted_folder_key\x18\x02 \x01(\x0c\"\x97\x01\n\x16TrashcanRestoreRequest\x12\x30\n\x07records\x18\x01 \x03(\x0b\x32\x1f.folder.v3.remove.RestoreRecord\x12\x30\n\x07\x66olders\x18\x02 \x03(\x0b\x32\x1f.folder.v3.remove.RestoreFolder\x12\x19\n\x11target_folder_uid\x18\x03 \x01(\x0c*D\n\x0cRemoveAction\x12\x19\n\x15REMOVE_ACTION_PREVIEW\x10\x00\x12\x19\n\x15REMOVE_ACTION_CONFIRM\x10\x01*~\n\x13RecordOperationType\x12\x1c\n\x18RECORD_OPERATION_UNKNOWN\x10\x00\x12\x16\n\x12UNLINK_FROM_FOLDER\x10\x01\x12\x18\n\x14MOVE_TO_FOLDER_TRASH\x10\x02\x12\x17\n\x13MOVE_TO_OWNER_TRASH\x10\x03*\x91\x01\n\x13\x46olderOperationType\x12\x1c\n\x18\x46OLDER_OPERATION_UNKNOWN\x10\x00\x12\x1f\n\x1b\x46OLDER_MOVE_TO_FOLDER_TRASH\x10\x01\x12\x1e\n\x1a\x46OLDER_MOVE_TO_OWNER_TRASH\x10\x02\x12\x1b\n\x17\x46OLDER_DELETE_PERMANENT\x10\x03*\xcb\x01\n\x0fRemoveErrorCode\x12\x18\n\x14REMOVE_ERROR_UNKNOWN\x10\x00\x12\x1a\n\x16REMOVE_ERROR_NOT_FOUND\x10\x01\x12\x1e\n\x1aREMOVE_ERROR_ACCESS_DENIED\x10\x02\x12 \n\x1cREMOVE_ERROR_TRASHCAN_FOLDER\x10\x03\x12\x1c\n\x18REMOVE_ERROR_ROOT_FOLDER\x10\x04\x12\"\n\x1eREMOVE_ERROR_DESCENDANT_DENIED\x10\x05*\xec\x01\n\x0cRemoveStatus\x12\x19\n\x15REMOVE_STATUS_UNKNOWN\x10\x00\x12\x19\n\x15REMOVE_STATUS_SUCCESS\x10\x01\x12\x1f\n\x1bREMOVE_STATUS_STALE_PREVIEW\x10\x02\x12\x1f\n\x1bREMOVE_STATUS_TOKEN_EXPIRED\x10\x03\x12\x1f\n\x1bREMOVE_STATUS_TOKEN_INVALID\x10\x04\x12\x1f\n\x1bREMOVE_STATUS_ACCESS_DENIED\x10\x05\x12\"\n\x1eREMOVE_STATUS_VALIDATION_ERROR\x10\x06*\xb7\x01\n\rRestoreStatus\x12\x1a\n\x16RESTORE_STATUS_UNKNOWN\x10\x00\x12\x0e\n\nRS_SUCCESS\x10\x01\x12\x16\n\x12RS_NOT_IN_TRASHCAN\x10\x02\x12\x14\n\x10RS_ACCESS_DENIED\x10\x03\x12\x1e\n\x1aRS_TARGET_FOLDER_NOT_FOUND\x10\x04\x12\x1f\n\x1bRS_ALREADY_EXISTS_IN_TARGET\x10\x05\x12\x0b\n\x07RS_FAIL\x10\x06*]\n\x0fRestoreItemType\x12\x18\n\x14RESTORE_ITEM_UNKNOWN\x10\x00\x12\x17\n\x13RESTORE_ITEM_RECORD\x10\x01\x12\x17\n\x13RESTORE_ITEM_FOLDER\x10\x02\x32\xce\x03\n\rRemoveService\x12\x8c\x01\n\x0cRemoveRecord\x12%.folder.v3.remove.RemoveRecordRequest\x1a .folder.v3.remove.RemoveResponse\"3\x82\xd3\xe4\x93\x02-\"(/api/rest/vault/folders/v3/remove_record:\x01*\x12\x8c\x01\n\x0cRemoveFolder\x12%.folder.v3.remove.RemoveFolderRequest\x1a .folder.v3.remove.RemoveResponse\"3\x82\xd3\xe4\x93\x02-\"(/api/rest/vault/folders/v3/remove_folder:\x01*\x12\x9e\x01\n\x0fTrashcanRestore\x12(.folder.v3.remove.TrashcanRestoreRequest\x1a).folder.v3.remove.TrashcanRestoreResponse\"6\x82\xd3\xe4\x93\x02\x30\"+/api/rest/vault/folders/v3/trashcan/restore:\x01*B1\n-com.keepersecurity.proto.api.folder.v3.removeP\x01\x62\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -37,16 +37,22 @@ _globals['_REMOVESERVICE'].methods_by_name['RemoveRecord']._serialized_options = b'\202\323\344\223\002-\"(/api/rest/vault/folders/v3/remove_record:\001*' _globals['_REMOVESERVICE'].methods_by_name['RemoveFolder']._loaded_options = None _globals['_REMOVESERVICE'].methods_by_name['RemoveFolder']._serialized_options = b'\202\323\344\223\002-\"(/api/rest/vault/folders/v3/remove_folder:\001*' - _globals['_REMOVEACTION']._serialized_start=1781 - _globals['_REMOVEACTION']._serialized_end=1849 - _globals['_RECORDOPERATIONTYPE']._serialized_start=1851 - _globals['_RECORDOPERATIONTYPE']._serialized_end=1977 - _globals['_FOLDEROPERATIONTYPE']._serialized_start=1980 - _globals['_FOLDEROPERATIONTYPE']._serialized_end=2125 - _globals['_REMOVEERRORCODE']._serialized_start=2128 - _globals['_REMOVEERRORCODE']._serialized_end=2331 - _globals['_REMOVESTATUS']._serialized_start=2334 - _globals['_REMOVESTATUS']._serialized_end=2570 + _globals['_REMOVESERVICE'].methods_by_name['TrashcanRestore']._loaded_options = None + _globals['_REMOVESERVICE'].methods_by_name['TrashcanRestore']._serialized_options = b'\202\323\344\223\0020\"+/api/rest/vault/folders/v3/trashcan/restore:\001*' + _globals['_REMOVEACTION']._serialized_start=2358 + _globals['_REMOVEACTION']._serialized_end=2426 + _globals['_RECORDOPERATIONTYPE']._serialized_start=2428 + _globals['_RECORDOPERATIONTYPE']._serialized_end=2554 + _globals['_FOLDEROPERATIONTYPE']._serialized_start=2557 + _globals['_FOLDEROPERATIONTYPE']._serialized_end=2702 + _globals['_REMOVEERRORCODE']._serialized_start=2705 + _globals['_REMOVEERRORCODE']._serialized_end=2908 + _globals['_REMOVESTATUS']._serialized_start=2911 + _globals['_REMOVESTATUS']._serialized_end=3147 + _globals['_RESTORESTATUS']._serialized_start=3150 + _globals['_RESTORESTATUS']._serialized_end=3333 + _globals['_RESTOREITEMTYPE']._serialized_start=3335 + _globals['_RESTOREITEMTYPE']._serialized_end=3428 _globals['_RECORDREMOVAL']._serialized_start=64 _globals['_RECORDREMOVAL']._serialized_end=182 _globals['_FOLDERREMOVAL']._serialized_start=184 @@ -73,6 +79,16 @@ _globals['_RECORDTARGET']._serialized_end=1680 _globals['_FOLDERTARGET']._serialized_start=1682 _globals['_FOLDERTARGET']._serialized_end=1779 - _globals['_REMOVESERVICE']._serialized_start=2573 - _globals['_REMOVESERVICE']._serialized_end=2874 + _globals['_RESTORERESULT']._serialized_start=1782 + _globals['_RESTORERESULT']._serialized_end=1941 + _globals['_TRASHCANRESTORERESPONSE']._serialized_start=1943 + _globals['_TRASHCANRESTORERESPONSE']._serialized_end=2041 + _globals['_RESTORERECORD']._serialized_start=2043 + _globals['_RESTORERECORD']._serialized_end=2135 + _globals['_RESTOREFOLDER']._serialized_start=2137 + _globals['_RESTOREFOLDER']._serialized_end=2202 + _globals['_TRASHCANRESTOREREQUEST']._serialized_start=2205 + _globals['_TRASHCANRESTOREREQUEST']._serialized_end=2356 + _globals['_REMOVESERVICE']._serialized_start=3431 + _globals['_REMOVESERVICE']._serialized_end=3893 # @@protoc_insertion_point(module_scope) diff --git a/keepercommander/proto/remove_pb2.pyi b/keepercommander/proto/remove_pb2.pyi index 093275ccb..bd21c9aee 100644 --- a/keepercommander/proto/remove_pb2.pyi +++ b/keepercommander/proto/remove_pb2.pyi @@ -44,6 +44,22 @@ class RemoveStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): REMOVE_STATUS_TOKEN_INVALID: _ClassVar[RemoveStatus] REMOVE_STATUS_ACCESS_DENIED: _ClassVar[RemoveStatus] REMOVE_STATUS_VALIDATION_ERROR: _ClassVar[RemoveStatus] + +class RestoreStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + RESTORE_STATUS_UNKNOWN: _ClassVar[RestoreStatus] + RS_SUCCESS: _ClassVar[RestoreStatus] + RS_NOT_IN_TRASHCAN: _ClassVar[RestoreStatus] + RS_ACCESS_DENIED: _ClassVar[RestoreStatus] + RS_TARGET_FOLDER_NOT_FOUND: _ClassVar[RestoreStatus] + RS_ALREADY_EXISTS_IN_TARGET: _ClassVar[RestoreStatus] + RS_FAIL: _ClassVar[RestoreStatus] + +class RestoreItemType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + RESTORE_ITEM_UNKNOWN: _ClassVar[RestoreItemType] + RESTORE_ITEM_RECORD: _ClassVar[RestoreItemType] + RESTORE_ITEM_FOLDER: _ClassVar[RestoreItemType] REMOVE_ACTION_PREVIEW: RemoveAction REMOVE_ACTION_CONFIRM: RemoveAction RECORD_OPERATION_UNKNOWN: RecordOperationType @@ -67,6 +83,16 @@ REMOVE_STATUS_TOKEN_EXPIRED: RemoveStatus REMOVE_STATUS_TOKEN_INVALID: RemoveStatus REMOVE_STATUS_ACCESS_DENIED: RemoveStatus REMOVE_STATUS_VALIDATION_ERROR: RemoveStatus +RESTORE_STATUS_UNKNOWN: RestoreStatus +RS_SUCCESS: RestoreStatus +RS_NOT_IN_TRASHCAN: RestoreStatus +RS_ACCESS_DENIED: RestoreStatus +RS_TARGET_FOLDER_NOT_FOUND: RestoreStatus +RS_ALREADY_EXISTS_IN_TARGET: RestoreStatus +RS_FAIL: RestoreStatus +RESTORE_ITEM_UNKNOWN: RestoreItemType +RESTORE_ITEM_RECORD: RestoreItemType +RESTORE_ITEM_FOLDER: RestoreItemType class RecordRemoval(_message.Message): __slots__ = ("folder_uid", "record_uid", "operation_type") @@ -205,3 +231,51 @@ class FolderTarget(_message.Message): folder_uid: bytes operation_type: FolderOperationType def __init__(self, folder_uid: _Optional[bytes] = ..., operation_type: _Optional[_Union[FolderOperationType, str]] = ...) -> None: ... + +class RestoreResult(_message.Message): + __slots__ = ("item_uid", "item_type", "status", "error_message") + ITEM_UID_FIELD_NUMBER: _ClassVar[int] + ITEM_TYPE_FIELD_NUMBER: _ClassVar[int] + STATUS_FIELD_NUMBER: _ClassVar[int] + ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int] + item_uid: bytes + item_type: RestoreItemType + status: RestoreStatus + error_message: str + def __init__(self, item_uid: _Optional[bytes] = ..., item_type: _Optional[_Union[RestoreItemType, str]] = ..., status: _Optional[_Union[RestoreStatus, str]] = ..., error_message: _Optional[str] = ...) -> None: ... + +class TrashcanRestoreResponse(_message.Message): + __slots__ = ("results", "error_message") + RESULTS_FIELD_NUMBER: _ClassVar[int] + ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int] + results: _containers.RepeatedCompositeFieldContainer[RestoreResult] + error_message: str + def __init__(self, results: _Optional[_Iterable[_Union[RestoreResult, _Mapping]]] = ..., error_message: _Optional[str] = ...) -> None: ... + +class RestoreRecord(_message.Message): + __slots__ = ("record_uid", "encrypted_record_key", "source_folder_uid") + RECORD_UID_FIELD_NUMBER: _ClassVar[int] + ENCRYPTED_RECORD_KEY_FIELD_NUMBER: _ClassVar[int] + SOURCE_FOLDER_UID_FIELD_NUMBER: _ClassVar[int] + record_uid: bytes + encrypted_record_key: bytes + source_folder_uid: bytes + def __init__(self, record_uid: _Optional[bytes] = ..., encrypted_record_key: _Optional[bytes] = ..., source_folder_uid: _Optional[bytes] = ...) -> None: ... + +class RestoreFolder(_message.Message): + __slots__ = ("folder_uid", "encrypted_folder_key") + FOLDER_UID_FIELD_NUMBER: _ClassVar[int] + ENCRYPTED_FOLDER_KEY_FIELD_NUMBER: _ClassVar[int] + folder_uid: bytes + encrypted_folder_key: bytes + def __init__(self, folder_uid: _Optional[bytes] = ..., encrypted_folder_key: _Optional[bytes] = ...) -> None: ... + +class TrashcanRestoreRequest(_message.Message): + __slots__ = ("records", "folders", "target_folder_uid") + RECORDS_FIELD_NUMBER: _ClassVar[int] + FOLDERS_FIELD_NUMBER: _ClassVar[int] + TARGET_FOLDER_UID_FIELD_NUMBER: _ClassVar[int] + records: _containers.RepeatedCompositeFieldContainer[RestoreRecord] + folders: _containers.RepeatedCompositeFieldContainer[RestoreFolder] + target_folder_uid: bytes + def __init__(self, records: _Optional[_Iterable[_Union[RestoreRecord, _Mapping]]] = ..., folders: _Optional[_Iterable[_Union[RestoreFolder, _Mapping]]] = ..., target_folder_uid: _Optional[bytes] = ...) -> None: ... diff --git a/keepercommander/proto/tla_pb2.pyi b/keepercommander/proto/tla_pb2.pyi index 08e7a2c3b..7075a1c31 100644 --- a/keepercommander/proto/tla_pb2.pyi +++ b/keepercommander/proto/tla_pb2.pyi @@ -22,4 +22,4 @@ class TLAProperties(_message.Message): expiration: int timerNotificationType: TimerNotificationType rotateOnExpiration: bool - def __init__(self, expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[TimerNotificationType, str]] = ..., rotateOnExpiration: bool = ...) -> None: ... + def __init__(self, expiration: _Optional[int] = ..., timerNotificationType: _Optional[_Union[TimerNotificationType, str]] = ..., rotateOnExpiration: _Optional[bool] = ...) -> None: ... diff --git a/keepercommander/sync_down.py b/keepercommander/sync_down.py index 85f7fca28..ad6759e1c 100644 --- a/keepercommander/sync_down.py +++ b/keepercommander/sync_down.py @@ -602,21 +602,9 @@ def convert_user_folder_shared_folder(ufsf): if len(response.recordRotations) > 0: # Stuff still uses record_rotation_cache; it cannot just be removed. + from . import vault_extensions for rr in response.recordRotations: - record_uid = utils.base64_url_encode(rr.recordUid) - rr_obj = { - 'record_uid': record_uid, - 'revision': rr.revision, - 'configuration_uid': utils.base64_url_encode(rr.configurationUid), - 'schedule': rr.schedule, - 'pwd_complexity': utils.base64_url_encode(rr.pwdComplexity), - 'disabled': rr.disabled, - 'resource_uid': utils.base64_url_encode(rr.resourceUid), - 'last_rotation': rr.lastRotation, - 'last_rotation_status': rr.lastRotationStatus, - } - params.record_rotation_cache[record_uid] = rr_obj - + vault_extensions.cache_record_rotation(params, rr) record_rotation_items.extend(response.recordRotations) params.sync_down_token = response.continuationToken diff --git a/keepercommander/vault_extensions.py b/keepercommander/vault_extensions.py index a1bd49034..8b3900d98 100644 --- a/keepercommander/vault_extensions.py +++ b/keepercommander/vault_extensions.py @@ -125,12 +125,31 @@ def record_has_rotation_configured(params, record_uid): return record_uid in (params.record_rotation_cache or {}) -def shared_folder_has_pam_user_with_rotation(params, shared_folder_uid): - # type: (KeeperParams, str) -> bool - """Return True if the shared folder contains at least one pamUser record with rotation configured. +def cache_record_rotation(params, rr): + # type: (KeeperParams, Any) -> str + """Mirror a RecordRotation proto into ``params.record_rotation_cache``. - Required precondition for the server to accept --rotate-on-expiration on a folder share. + Used by classic sync_down and Nested Share Folder sync (NSF rotations arrive + on ``keeperDriveData.recordRotationData``). """ + record_uid = utils.base64_url_encode(rr.recordUid) + params.record_rotation_cache[record_uid] = { + 'record_uid': record_uid, + 'revision': rr.revision, + 'configuration_uid': utils.base64_url_encode(rr.configurationUid), + 'schedule': rr.schedule, + 'pwd_complexity': utils.base64_url_encode(rr.pwdComplexity), + 'disabled': rr.disabled, + 'resource_uid': utils.base64_url_encode(rr.resourceUid), + 'last_rotation': rr.lastRotation, + 'last_rotation_status': rr.lastRotationStatus, + } + return record_uid + + +def shared_folder_has_pam_user_with_rotation(params, shared_folder_uid): + # type: (KeeperParams, str) -> bool + """True if the shared folder has a pamUser with rotation configured.""" sf = params.shared_folder_cache.get(shared_folder_uid) if not sf: return False @@ -144,6 +163,42 @@ def shared_folder_has_pam_user_with_rotation(params, shared_folder_uid): return False +def nested_share_record_is_pam_user_with_rotation(params, record_uid): + # type: (KeeperParams, str) -> bool + """True if an NSF record is pamUser with rotation configured.""" + rec_type = None + nsf_record_data = getattr(params, 'nested_share_record_data', {}) or {} + obj = nsf_record_data.get(record_uid) + if obj and isinstance(obj.get('data_json'), dict): + rec_type = obj['data_json'].get('type') + if rec_type is None: + record = vault.KeeperRecord.load(params, record_uid) + rec_type = getattr(record, 'record_type', None) if record is not None else None + return rec_type == 'pamUser' and record_has_rotation_configured(params, record_uid) + + +def nested_share_folder_has_pam_user_with_rotation(params, folder_uid): + # type: (KeeperParams, str) -> bool + """True if an NSF folder (or sub-folder) has a pamUser with rotation configured.""" + nsf_folders = getattr(params, 'nested_share_folders', {}) or {} + nsf_folder_records = getattr(params, 'nested_share_folder_records', {}) or {} + + visited = set() + stack = [folder_uid] + while stack: + fuid = stack.pop() + if fuid in visited: + continue + visited.add(fuid) + for record_uid in (nsf_folder_records.get(fuid) or set()): + if nested_share_record_is_pam_user_with_rotation(params, record_uid): + return True + for child_uid, child_obj in nsf_folders.items(): + if child_obj.get('parent_uid') == fuid and child_uid not in visited: + stack.append(child_uid) + return False + + def find_records(params, # type: KeeperParams search_str=None, # type: Optional[str] record_type=None, # type: Union[str, Iterable[str], None] diff --git a/tests/test_pam_privileged_cloud.py b/tests/test_pam_privileged_cloud.py index 1c840f32f..0acecaa02 100644 --- a/tests/test_pam_privileged_cloud.py +++ b/tests/test_pam_privileged_cloud.py @@ -4,6 +4,7 @@ import unittest from unittest.mock import MagicMock, patch +import keepercommander.commands.record # noqa: F401 from keepercommander.commands.pam.pam_dto import ( GatewayActionIdpInputs, GatewayActionIdpCreateUser, @@ -270,4 +271,4 @@ def test_group_has_add_remove_list(self): if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/unit-tests/pam/test_pam_nsf_config.py b/unit-tests/pam/test_pam_nsf_config.py new file mode 100644 index 000000000..aa75e930c --- /dev/null +++ b/unit-tests/pam/test_pam_nsf_config.py @@ -0,0 +1,509 @@ +import unittest +from unittest import mock + +import keepercommander.commands.record # noqa: F401 +from keepercommander import vault +from keepercommander.commands.discoveryrotation import ( + PAMConfigurationEditCommand, PAMConfigurationNewCommand, PAMConfigurationRemoveCommand, + PAMCreateRecordRotationCommand) +from keepercommander.commands.pam.vault_target import ( + create_pam_configuration_in_folder, create_record_in_folder, place_record_in_folder, + resolve_pam_folder_uid, records_in_folder) +from keepercommander.error import CommandError +from keepercommander.subfolder import NestedShareFolderNode, RootFolderNode, SharedFolderNode + + +def _make_params(): + params = mock.MagicMock() + params.folder_cache = {} + params.shared_folder_cache = {} + params.nested_share_folders = {} + params.current_folder = '' + params.root_folder = RootFolderNode() + params.environment_variables = {} + params.sync_data = False + return params + + +class TestPamVaultTarget(unittest.TestCase): + + @mock.patch('keepercommander.commands.pam.vault_target.api.sync_down') + @mock.patch('keepercommander.commands.pam.vault_target.move_record_v3') + @mock.patch('keepercommander.commands.pam.vault_target.FolderMoveCommand') + def test_place_record_uses_legacy_move_for_legacy_folder(self, mock_move_command, mock_nsf_move, mock_sync): + params = _make_params() + folder = SharedFolderNode() + folder.uid = 'legacy_folder' + params.folder_cache[folder.uid] = folder + + place_record_in_folder(params, 'record_uid', folder.uid, command='pam-config-new') + + mock_move_command.return_value.execute.assert_called_once_with( + params, src='record_uid', dst='legacy_folder', force=True) + mock_nsf_move.assert_not_called() + mock_sync.assert_not_called() + + @mock.patch('keepercommander.commands.pam.vault_target.api.sync_down') + @mock.patch('keepercommander.commands.pam.vault_target.move_record_v3') + @mock.patch('keepercommander.commands.pam.vault_target.FolderMoveCommand') + def test_place_record_uses_nsf_move_for_nsf_folder(self, mock_move_command, mock_nsf_move, mock_sync): + params = _make_params() + folder = NestedShareFolderNode() + folder.uid = 'nsf_folder' + params.folder_cache[folder.uid] = folder + + place_record_in_folder(params, 'record_uid', folder.uid, command='pam-config-new') + + mock_nsf_move.assert_called_once_with(params, 'record_uid', to_folder_uid='nsf_folder') + mock_sync.assert_called_once_with(params) + mock_move_command.assert_not_called() + + @mock.patch('keepercommander.commands.pam.vault_target.api.sync_down') + @mock.patch('keepercommander.commands.pam.vault_target.move_record_v3', + return_value={'success': False, 'message': 'denied'}) + def test_place_record_raises_when_nsf_move_fails(self, mock_nsf_move, mock_sync): + params = _make_params() + folder = NestedShareFolderNode() + folder.uid = 'nsf_folder' + params.folder_cache[folder.uid] = folder + + with self.assertRaises(CommandError): + place_record_in_folder(params, 'record_uid', folder.uid, command='pam-config-new') + mock_sync.assert_not_called() + + def test_place_record_rejects_missing_folder(self): + params = _make_params() + + with self.assertRaises(CommandError): + place_record_in_folder(params, 'record_uid', 'missing_folder', command='pam-config-new') + + @mock.patch('keepercommander.commands.pam.vault_target.record_management.add_record_to_folder') + def test_create_record_in_folder_uses_legacy_add_for_legacy_folder(self, mock_add_record): + params = _make_params() + folder = SharedFolderNode() + folder.uid = 'legacy_folder' + params.folder_cache[folder.uid] = folder + record = vault.TypedRecord() + + create_record_in_folder(params, record, folder.uid, command='pam-access-user-provision') + + mock_add_record.assert_called_once_with(params, record, 'legacy_folder') + + @mock.patch('keepercommander.commands.pam_import.nsf_helpers.api.sync_down') + @mock.patch('keepercommander.nested_share_folder.record_api.create_record_v3', + return_value={'success': True, 'record_uid': 'nsf_record_uid'}) + @mock.patch('keepercommander.vault_extensions.extract_typed_record_data', + return_value={'type': 'pamUser', 'title': 'Test', 'fields': [], 'custom': []}) + def test_create_record_in_folder_uses_v3_add_for_nsf_folder(self, _extract, mock_create, _sync): + params = _make_params() + params.nested_share_folders['nsf_folder'] = { + 'name': 'Project - Users', + 'parent_uid': 'app_uid', + 'folder_key_unencrypted': b'0' * 32, + } + folder = NestedShareFolderNode() + folder.uid = 'nsf_folder' + params.folder_cache[folder.uid] = folder + record = vault.TypedRecord() + + create_record_in_folder(params, record, folder.uid, command='pam-access-user-provision') + + mock_create.assert_called_once() + self.assertEqual(mock_create.call_args.kwargs['folder_uid'], 'nsf_folder') + self.assertEqual(record.record_uid, 'nsf_record_uid') + _sync.assert_called_once_with(params) + + def test_resolve_pam_folder_uid_finds_root_nsf_folder_by_name(self): + params = _make_params() + folder = NestedShareFolderNode() + folder.uid = 'nsf_folder' + folder.name = 'testpam' + params.folder_cache[folder.uid] = folder + params.root_folder.subfolders.append(folder.uid) + + self.assertEqual(resolve_pam_folder_uid(params, 'testpam'), 'nsf_folder') + + def test_resolve_pam_folder_uid_finds_nsf_cache_folder_by_name(self): + params = _make_params() + params.nested_share_folders['nsf_folder'] = {'name': 'testpam'} + + self.assertEqual(resolve_pam_folder_uid(params, 'testpam'), 'nsf_folder') + + def test_records_in_folder_merges_legacy_and_nsf_membership(self): + params = _make_params() + params.subfolder_record_cache = {'nsf_folder': {'legacy_rec_uid'}} + params.nested_share_folder_records = {'nsf_folder': {'nsf_rec_uid'}} + + self.assertEqual( + records_in_folder(params, 'nsf_folder'), + {'legacy_rec_uid', 'nsf_rec_uid'}, + ) + + @mock.patch('keepercommander.commands.pam_import.nsf_helpers.api.sync_down') + @mock.patch('keepercommander.commands.pam.config_helper.pam_configuration_create_record_nsf') + def test_create_pam_configuration_in_folder_uses_add_pam_configuration_for_nsf( + self, mock_create_nsf, mock_sync): + params = _make_params() + params.nested_share_folders['nsf_folder'] = {'name': 'Project - Users'} + folder = NestedShareFolderNode() + folder.uid = 'nsf_folder' + params.folder_cache[folder.uid] = folder + record = vault.TypedRecord(version=6) + + create_pam_configuration_in_folder(params, record, 'nsf_folder', command='pam-config-new') + + mock_create_nsf.assert_called_once_with(params, record, 'nsf_folder') + mock_sync.assert_called_once_with(params) + + @mock.patch('keepercommander.commands.pam.vault_target.place_record_in_folder') + @mock.patch('keepercommander.commands.pam.vault_target.api.sync_down') + @mock.patch('keepercommander.commands.pam.config_helper.pam_configuration_create_record_v6') + def test_create_pam_configuration_in_folder_uses_classic_api_for_legacy( + self, mock_create_v6, mock_sync, mock_place): + params = _make_params() + folder = SharedFolderNode() + folder.uid = 'legacy_folder' + params.folder_cache[folder.uid] = folder + record = vault.TypedRecord(version=6) + record.record_uid = 'config_uid' + + create_pam_configuration_in_folder(params, record, 'legacy_folder', command='pam-config-new') + + mock_create_v6.assert_called_once_with(params, record, 'legacy_folder') + mock_sync.assert_called_once_with(params) + mock_place.assert_called_once_with( + params, 'config_uid', 'legacy_folder', command='pam-config-new') + + +class TestPamConfigNewNsfPlacement(unittest.TestCase): + + def test_parse_pam_configuration_accepts_nsf_folder_uid(self): + params = _make_params() + folder = NestedShareFolderNode() + folder.uid = 'nsf_folder' + params.folder_cache[folder.uid] = folder + + record = vault.TypedRecord(version=6) + command = PAMConfigurationNewCommand() + command.parse_pam_configuration(params, record, shared_folder_uid='nsf_folder') + + field = record.get_typed_field('pamResources') + self.assertEqual(field.value[0]['folderUid'], 'nsf_folder') + + def test_parse_pam_configuration_accepts_nsf_folder_name(self): + params = _make_params() + folder = NestedShareFolderNode() + folder.uid = 'nsf_folder' + folder.name = 'testpam' + params.folder_cache[folder.uid] = folder + params.root_folder.subfolders.append(folder.uid) + + record = vault.TypedRecord(version=6) + command = PAMConfigurationNewCommand() + command.parse_pam_configuration(params, record, shared_folder_uid='testpam') + + field = record.get_typed_field('pamResources') + self.assertEqual(field.value[0]['folderUid'], 'nsf_folder') + + @mock.patch('keepercommander.commands.discoveryrotation.TunnelDAG') + @mock.patch('keepercommander.commands.discoveryrotation.get_keeper_tokens', + return_value=(b'encrypted_session', b'encrypted_key', b'transmission_key')) + @mock.patch('keepercommander.commands.discoveryrotation.create_pam_configuration_in_folder') + @mock.patch('keepercommander.commands.discoveryrotation.RecordEditMixin.get_record_type_fields', + return_value=[]) + def test_execute_creates_new_config_in_nsf_folder( + self, mock_record_fields, mock_create_config, mock_tokens, mock_dag): + params = _make_params() + params.nested_share_folders['nsf_folder'] = { + 'name': 'Project - Users', + 'parent_uid': 'app_uid', + 'folder_key_unencrypted': b'0' * 32, + } + folder = NestedShareFolderNode() + folder.uid = 'nsf_folder' + params.folder_cache[folder.uid] = folder + command = PAMConfigurationNewCommand() + + def parse_properties(_, record, **kwargs): + record.fields.append(vault.TypedField.new_field( + 'pamResources', {'folderUid': 'nsf_folder'})) + + def create_config(_, record, folder_uid, command='pam-config-new'): + record.record_uid = 'config_uid' + + mock_create_config.side_effect = create_config + with mock.patch.object(command, 'parse_properties', side_effect=parse_properties), \ + mock.patch.object(command, 'verify_required'): + result = command.execute(params, config_type='local', title='Config') + + self.assertEqual(result, 'config_uid') + mock_create_config.assert_called_once_with( + params, mock.ANY, 'nsf_folder', command='pam-config-new') + + @mock.patch('keepercommander.commands.discoveryrotation.TunnelDAG') + @mock.patch('keepercommander.commands.discoveryrotation.get_keeper_tokens', + return_value=(b'encrypted_session', b'encrypted_key', b'transmission_key')) + @mock.patch('keepercommander.commands.discoveryrotation.create_pam_configuration_in_folder') + @mock.patch('keepercommander.commands.discoveryrotation.RecordEditMixin.get_record_type_fields', + return_value=[]) + def test_execute_creates_new_config_in_legacy_folder( + self, mock_record_fields, mock_create_config, mock_tokens, mock_dag): + params = _make_params() + folder = SharedFolderNode() + folder.uid = 'legacy_folder' + params.folder_cache[folder.uid] = folder + command = PAMConfigurationNewCommand() + + def parse_properties(_, record, **kwargs): + record.fields.append(vault.TypedField.new_field( + 'pamResources', {'folderUid': 'legacy_folder'})) + + def create_config(_, record, folder_uid, command='pam-config-new'): + record.record_uid = 'config_uid' + + mock_create_config.side_effect = create_config + with mock.patch.object(command, 'parse_properties', side_effect=parse_properties), \ + mock.patch.object(command, 'verify_required'): + result = command.execute(params, config_type='local', title='Config') + + self.assertEqual(result, 'config_uid') + mock_create_config.assert_called_once_with( + params, mock.ANY, 'legacy_folder', command='pam-config-new') + + +class TestPamConfigEditNsfPlacement(unittest.TestCase): + + @mock.patch('keepercommander.commands.discoveryrotation.place_record_in_folder') + @mock.patch('keepercommander.commands.discoveryrotation.update_pam_record') + @mock.patch('keepercommander.commands.discoveryrotation.RecordEditMixin.get_record_type_fields', + return_value=[]) + @mock.patch('keepercommander.vault.KeeperRecord.load') + def test_execute_updates_and_places_edited_config_in_nsf_folder( + self, mock_load, mock_record_fields, mock_update_record, mock_place): + params = _make_params() + params.nested_share_folders['nsf_folder'] = { + 'name': 'Project - Users', + 'parent_uid': 'app_uid', + 'folder_key_unencrypted': b'0' * 32, + } + folder = NestedShareFolderNode() + folder.uid = 'nsf_folder' + params.folder_cache[folder.uid] = folder + params.record_cache = {'config_uid': {}} + command = PAMConfigurationEditCommand() + + configuration = vault.TypedRecord(version=6) + configuration.record_uid = 'config_uid' + configuration.type_name = 'pamNetworkConfiguration' + configuration.fields.append(vault.TypedField.new_field( + 'pamResources', {'folderUid': 'legacy_folder'})) + mock_load.return_value = configuration + + def parse_properties(_, record, **kwargs): + field = record.get_typed_field('pamResources') + field.value[0]['folderUid'] = 'nsf_folder' + + with mock.patch.object(command, 'parse_properties', side_effect=parse_properties), \ + mock.patch.object(command, 'verify_required'): + command.execute(params, uid='config_uid') + + mock_update_record.assert_called_once_with(params, configuration, command='pam-config-edit') + mock_place.assert_called_once_with( + params, 'config_uid', 'nsf_folder', command='pam-config-edit') + + @mock.patch('keepercommander.commands.discoveryrotation.place_record_in_folder') + @mock.patch('keepercommander.commands.discoveryrotation.update_pam_record') + @mock.patch('keepercommander.commands.discoveryrotation.RecordEditMixin.get_record_type_fields', + return_value=[]) + @mock.patch('keepercommander.vault.KeeperRecord.load') + def test_execute_places_edited_config_with_backend_aware_helper( + self, mock_load, mock_record_fields, mock_update_record, mock_place): + params = _make_params() + folder = SharedFolderNode() + folder.uid = 'legacy_folder' + params.folder_cache[folder.uid] = folder + params.record_cache = {'config_uid': {}} + command = PAMConfigurationEditCommand() + + configuration = vault.TypedRecord(version=6) + configuration.record_uid = 'config_uid' + configuration.type_name = 'pamNetworkConfiguration' + configuration.fields.append(vault.TypedField.new_field( + 'pamResources', {'folderUid': 'nsf_folder'})) + mock_load.return_value = configuration + + def parse_properties(_, record, **kwargs): + field = record.get_typed_field('pamResources') + field.value[0]['folderUid'] = 'legacy_folder' + + with mock.patch.object(command, 'parse_properties', side_effect=parse_properties), \ + mock.patch.object(command, 'verify_required'): + command.execute(params, uid='config_uid') + + mock_update_record.assert_called_once_with(params, configuration, command='pam-config-edit') + mock_place.assert_called_once_with( + params, 'config_uid', 'legacy_folder', command='pam-config-edit') + + +class TestPamConfigRemoveNsf(unittest.TestCase): + + @mock.patch('keepercommander.vault.KeeperRecord.load') + def test_resolve_pam_config_uid_finds_nsf_record_by_uid(self, mock_load): + params = _make_params() + params.record_cache = {} + params.nested_share_records = { + 'config_uid': {'record_uid': 'config_uid', 'version': 6}, + } + + configuration = vault.TypedRecord(version=6) + configuration.record_uid = 'config_uid' + configuration.type_name = 'pamNetworkConfiguration' + mock_load.return_value = configuration + + uid = PAMConfigurationRemoveCommand._resolve_pam_config_uid(params, 'config_uid') + self.assertEqual(uid, 'config_uid') + + @mock.patch('keepercommander.vault.KeeperRecord.load') + def test_resolve_pam_config_uid_finds_nsf_record_by_title(self, mock_load): + params = _make_params() + params.record_cache = {} + params.nested_share_records = { + 'config_uid': {'record_uid': 'config_uid', 'version': 6}, + } + params.nested_share_record_data = { + 'config_uid': { + 'data_json': { + 'title': 'PAM NSF Test Configuration', + 'type': 'pamNetworkConfiguration', + }, + }, + } + + configuration = vault.TypedRecord(version=6) + configuration.record_uid = 'config_uid' + configuration.type_name = 'pamNetworkConfiguration' + configuration.title = 'PAM NSF Test Configuration' + mock_load.return_value = configuration + + uid = PAMConfigurationRemoveCommand._resolve_pam_config_uid( + params, 'PAM NSF Test Configuration') + self.assertEqual(uid, 'config_uid') + + @mock.patch('keepercommander.commands.pam.config_helper.RecordRemoveCommand') + @mock.patch('keepercommander.commands.nested_share_folder.helpers.is_nested_share_record', + return_value=False) + def test_pam_configuration_remove_uses_legacy_remove_for_non_nsf_record( + self, _mock_is_nsf, mock_remove_cmd): + from keepercommander.commands.pam.config_helper import pam_configuration_remove + + params = _make_params() + params.record_cache = {'config_uid': {}} + params.nested_share_records = {} + + pam_configuration_remove(params, 'config_uid') + + mock_remove_cmd.return_value.execute.assert_called_once_with( + params, record='config_uid', force=True) + self.assertNotIn('config_uid', params.record_cache) + + @mock.patch('keepercommander.nested_share_folder.remove_record_v3', + return_value={'confirmed': True}) + @mock.patch('keepercommander.subfolder.find_folders', return_value=['nsf_folder']) + @mock.patch('keepercommander.commands.nested_share_folder.helpers.is_nested_share_record', + return_value=True) + def test_pam_configuration_remove_uses_nsf_remove_for_nsf_record( + self, _mock_is_nsf, mock_find_folders, mock_remove_v3): + from keepercommander.commands.pam.config_helper import pam_configuration_remove + + params = _make_params() + params.record_cache = {'config_uid': {}} + params.nested_share_records = {'config_uid': {'record_uid': 'config_uid', 'version': 6}} + + pam_configuration_remove(params, 'config_uid') + + mock_remove_v3.assert_called_once_with(params, [{ + 'record_uid': 'config_uid', + 'folder_uid': 'nsf_folder', + 'operation_type': 'owner-trash', + }], dry_run=False) + self.assertNotIn('config_uid', params.record_cache) + self.assertNotIn('config_uid', params.nested_share_records) + + @mock.patch('keepercommander.commands.discoveryrotation.pam_configuration_remove') + @mock.patch('keepercommander.commands.discoveryrotation.TunnelDAG') + @mock.patch('keepercommander.commands.discoveryrotation.get_keeper_tokens', + return_value=(b'encrypted_session', b'encrypted_key', b'transmission_key')) + @mock.patch('keepercommander.vault.KeeperRecord.load') + def test_execute_removes_nsf_config( + self, mock_load, mock_tokens, mock_dag, mock_remove): + params = _make_params() + params.record_cache = {} + params.nested_share_records = { + 'config_uid': {'record_uid': 'config_uid', 'version': 6}, + } + command = PAMConfigurationRemoveCommand() + + configuration = vault.TypedRecord(version=6) + configuration.record_uid = 'config_uid' + configuration.type_name = 'pamNetworkConfiguration' + mock_load.return_value = configuration + mock_dag.return_value.linking_dag.has_graph = False + + command.execute(params, uid='config_uid') + + mock_remove.assert_called_once_with(params, 'config_uid') + self.assertTrue(params.sync_data) + + +class TestPamRotationNsfFolder(unittest.TestCase): + + @mock.patch('keepercommander.commands.discoveryrotation.router_set_record_rotation_information') + @mock.patch('keepercommander.commands.discoveryrotation.TunnelDAG') + @mock.patch('keepercommander.commands.discoveryrotation.get_keeper_tokens', + return_value=(b'encrypted_session', b'encrypted_key', b'transmission_key')) + @mock.patch('keepercommander.commands.discoveryrotation.collect_pam_folder_uids', + return_value={'nsf_folder'}) + @mock.patch('keepercommander.commands.discoveryrotation.records_in_folder', + return_value={'nsf_pam_user_uid'}) + @mock.patch('keepercommander.vault.KeeperRecord.load') + def test_execute_with_nsf_folder_collects_nsf_records( + self, mock_load, mock_records_in_folder, mock_collect_folders, + mock_tokens, mock_dag, _mock_router_set): + from cryptography.hazmat.primitives.asymmetric import ec + + params = _make_params() + params.rest_context.server_key_id = 8 + params.session_token = 'base64_encoded_session_token' + params.record_rotation_cache = {} + params.subfolder_record_cache = {} + params.nested_share_folder_records = {'nsf_folder': {'nsf_pam_user_uid'}} + + pam_user = vault.TypedRecord(version=3) + pam_user.record_uid = 'nsf_pam_user_uid' + pam_user.type_name = 'pamMachine' + pam_user.title = 'PAM NSF Test Machine' + pam_user.record_key = b'\x00' * 32 + mock_load.return_value = pam_user + + mock_dag_instance = mock_dag.return_value + mock_dag_instance.linking_dag.has_graph = True + mock_dag_instance.resource_belongs_to_config.return_value = True + mock_dag_instance.record.record_uid = 'config_uid' + + config_record = vault.TypedRecord(version=6) + config_record.record_uid = 'config_uid' + config_record.type_name = 'pamNetworkConfiguration' + + command = PAMCreateRecordRotationCommand() + with mock.patch('keepercommander.rest_api.SERVER_PUBLIC_KEYS', + {8: ec.generate_private_key(ec.SECP256R1()).public_key()}), \ + mock.patch('keepercommander.vault_extensions.find_records', return_value=[config_record]), \ + mock.patch('keepercommander.commands.discoveryrotation.resolve_pam_record', + side_effect=lambda _p, ident, rec_type=None: config_record if ident == 'config_uid' else pam_user), \ + mock.patch('keepercommander.commands.discoveryrotation.router_set_record_rotation_information'): + command.execute(params, folder_name='M_SR5x7Q4cu9O0-RiLDN4A', force=True, on_demand=True, + config='config_uid') + + mock_collect_folders.assert_called_once_with(params, 'M_SR5x7Q4cu9O0-RiLDN4A') + mock_records_in_folder.assert_called_once_with(params, 'nsf_folder') + mock_load.assert_any_call(params, 'nsf_pam_user_uid') diff --git a/unit-tests/pam/test_pam_project_export.py b/unit-tests/pam/test_pam_project_export.py index 0f7900a5a..f12a37784 100644 --- a/unit-tests/pam/test_pam_project_export.py +++ b/unit-tests/pam/test_pam_project_export.py @@ -22,6 +22,8 @@ import unittest from unittest.mock import patch +import keepercommander.commands.record # noqa: F401 + from keepercommander import vault # ── record builders ──────────────────────────────────────────────────────── @@ -122,8 +124,9 @@ def setUp(self): self.params.record_cache = {uid: {} for uid in _RECORDS} def _execute(self, project_uid=CONFIG_UID, output=None): - """Run execute() with vault.KeeperRecord.load mocked.""" - with patch("keepercommander.vault.KeeperRecord.load", side_effect=_fake_load): + """Run execute() with load_pam_record mocked.""" + with patch("keepercommander.commands.pam_import.export.load_pam_record", + side_effect=_fake_load): with patch.object(self.cmd, "_get_allowed_settings", return_value=dict(_DEFAULT_ALLOWED)): kwargs = {"project_uid": project_uid} @@ -242,12 +245,14 @@ def test_output_flag_writes_file(self): # ── error handling ─────────────────────────────────────────── def test_missing_project_uid_returns_none(self): - with patch("keepercommander.vault.KeeperRecord.load", side_effect=_fake_load): + with patch("keepercommander.commands.pam_import.export.load_pam_record", + side_effect=_fake_load): result = self.cmd.execute(self.params, project_uid="", output=None) self.assertIsNone(result) def test_unknown_uid_returns_none(self): - with patch("keepercommander.vault.KeeperRecord.load", return_value=None): + with patch("keepercommander.commands.pam_import.export.load_pam_record", + return_value=None): result = self.cmd.execute(self.params, project_uid="unknown-uid", output=None) self.assertIsNone(result) @@ -256,7 +261,8 @@ def test_non_v6_record_returns_none(self): v3_rec.type_name = "pamMachine" v3_rec.title = "some" v3_rec.record_uid = "some-uid" - with patch("keepercommander.vault.KeeperRecord.load", return_value=v3_rec): + with patch("keepercommander.commands.pam_import.export.load_pam_record", + return_value=v3_rec): result = self.cmd.execute(self.params, project_uid="some-uid", output=None) self.assertIsNone(result) @@ -334,7 +340,8 @@ def setUp(self): def _execute(self): def _load(_p, uid): return self.records.get(uid) - with patch("keepercommander.vault.KeeperRecord.load", side_effect=_load): + with patch("keepercommander.commands.pam_import.export.load_pam_record", + side_effect=_load): with patch.object(self.cmd, "_get_allowed_settings", return_value=dict(_DEFAULT_ALLOWED)): return self.cmd.execute(self.params, project_uid=self.KCM_CFG) @@ -385,5 +392,86 @@ def test_uid_in_launch_credentials_accepted(self): self.assertEqual(users[0]["uid"], uid_22) +class TestPAMProjectExportNSF(unittest.TestCase): + """Export must resolve records stored only in NSF caches (not record_cache).""" + + NSF_CFG = "nsf-cfg-001" + NSF_MACHINE = "nsf-res-machine" + NSF_USER = "nsf-usr-admin" + + def setUp(self): + from keepercommander.commands.pam_import.export import PAMProjectExportCommand + self.cmd = PAMProjectExportCommand() + self.params = MagicMock() + self.params.record_cache = {} + self.params.nested_share_records = { + self.NSF_CFG: {"record_uid": self.NSF_CFG, "version": 6, "revision": 1}, + self.NSF_MACHINE: {"record_uid": self.NSF_MACHINE, "version": 3, "revision": 1}, + self.NSF_USER: {"record_uid": self.NSF_USER, "version": 3, "revision": 1}, + } + self.params.nested_share_record_data = { + self.NSF_CFG: { + "record_uid": self.NSF_CFG, + "data_json": { + "title": "NSF PAM Project", + "type": "pamNetworkConfiguration", + "fields": [{ + "type": "pamResources", + "value": [{ + "controllerUid": "gw-nsf", + "folderUid": "sf-nsf", + "resourceRef": [self.NSF_MACHINE], + }], + }], + }, + }, + self.NSF_MACHINE: { + "record_uid": self.NSF_MACHINE, + "data_json": { + "title": "NSF Linux Server", + "type": "pamMachine", + "fields": [{ + "type": "pamSettings", + "value": [{ + "connection": { + "userRecords": [self.NSF_USER], + "protocol": "ssh", + }, + }], + }], + }, + }, + self.NSF_USER: { + "record_uid": self.NSF_USER, + "data_json": { + "title": "NSF Admin", + "type": "pamUser", + "fields": [{"type": "login", "value": ["root"]}], + }, + }, + } + + def _execute(self): + with patch.object(self.cmd, "_get_allowed_settings", + return_value=dict(_DEFAULT_ALLOWED)): + return self.cmd.execute(self.params, project_uid=self.NSF_CFG) + + def test_nsf_config_export_succeeds(self): + parsed = json.loads(self._execute()) + self.assertEqual(parsed["project"], "NSF PAM Project") + self.assertEqual(parsed["pam_configuration"]["environment"], "local") + + def test_nsf_resources_and_users_exported(self): + parsed = json.loads(self._execute()) + self.assertEqual(len(parsed["pam_data"]["resources"]), 1) + res = parsed["pam_data"]["resources"][0] + self.assertEqual(res["uid"], self.NSF_MACHINE) + self.assertEqual(res["type"], "pamMachine") + self.assertEqual(len(res["users"]), 1) + self.assertEqual(res["users"][0]["uid"], self.NSF_USER) + self.assertEqual(len(parsed["pam_data"]["users"]), 1) + self.assertEqual(parsed["pam_data"]["users"][0]["login"], "root") + + if __name__ == "__main__": unittest.main() diff --git a/unit-tests/pam/test_pam_project_extend_nsf.py b/unit-tests/pam/test_pam_project_extend_nsf.py new file mode 100644 index 000000000..86dfa7478 --- /dev/null +++ b/unit-tests/pam/test_pam_project_extend_nsf.py @@ -0,0 +1,112 @@ +from types import SimpleNamespace +from unittest.mock import patch + +import keepercommander.commands.record # noqa: F401 + +from keepercommander.commands.pam_import.extend import PAMProjectExtendCommand +from keepercommander.subfolder import BaseFolderNode, NestedShareFolderNode, RootFolderNode + + +def _folder(uid, name, parent_uid=None): + folder = NestedShareFolderNode() + folder.uid = uid + folder.name = name + folder.parent_uid = parent_uid + folder.subfolders = [] + return folder + + +def _params(): + project = _folder('project_nsf', 'NSF Project') + users = _folder('users_nsf', 'NSF Project - Users', 'project_nsf') + resources = _folder('resources_nsf', 'NSF Project - Resources', 'project_nsf') + project.subfolders = ['users_nsf', 'resources_nsf'] + return SimpleNamespace( + data_key=b'1' * 32, + root_folder=RootFolderNode(), + folder_cache={ + 'project_nsf': project, + 'users_nsf': users, + 'resources_nsf': resources, + }, + subfolder_cache={}, + subfolder_record_cache={'users_nsf': {'config_uid'}}, + shared_folder_cache={}, + nested_share_folders={ + 'project_nsf': {'name': 'NSF Project', 'parent_uid': None}, + 'users_nsf': {'name': 'NSF Project - Users', 'parent_uid': 'project_nsf'}, + 'resources_nsf': {'name': 'NSF Project - Resources', 'parent_uid': 'project_nsf'}, + }, + environment_variables={}, + ) + + +def test_get_nsf_project_folders_from_config_folder_siblings(): + params = _params() + + folders = PAMProjectExtendCommand.get_nsf_project_folders(params, 'config_uid') + + assert {x['uid'] for x in folders} == {'users_nsf', 'resources_nsf'} + assert all(x['source'] == 'nested_share_folder' for x in folders) + + +def test_get_app_shared_folders_falls_back_to_nsf_project_folders(): + params = _params() + + with patch('keepercommander.commands.ksm.KSMCommand.get_app_info', + return_value=[]): + folders = PAMProjectExtendCommand().get_app_shared_folders(params, 'ksm_uid', 'config_uid') + + assert {x['uid'] for x in folders} == {'users_nsf', 'resources_nsf'} + + +def test_create_subfolder_uses_nsf_api_under_nsf_parent(): + params = _params() + + with patch('keepercommander.nested_share_folder.folder_api.create_folder_v3', + return_value={'success': True, 'folder_uid': 'child_nsf'}) as create_folder, \ + patch('keepercommander.commands.pam_import.extend.api.sync_down'): + uid = PAMProjectExtendCommand().create_subfolder(params, 'Child', 'users_nsf') + + assert uid == 'child_nsf' + create_folder.assert_called_once_with(params, 'Child', parent_uid='users_nsf') + + +def test_create_subfolder_uses_pre_generated_uid_for_nsf(): + params = _params() + + with patch('keepercommander.commands.pam_import.extend.create_nsf_subfolder', + return_value='pre_generated') as create_sub: + uid = PAMProjectExtendCommand().create_subfolder( + params, 'Child', 'users_nsf', folder_uid='pre_generated') + + assert uid == 'pre_generated' + create_sub.assert_called_once_with(params, 'Child', 'users_nsf', folder_uid='pre_generated') + + +def test_process_folders_creates_new_nsf_folder_paths(): + params = _params() + project = { + 'data': { + 'pam_data': { + 'users': [{'type': 'pamUser', 'title': 'Admin', 'login': 'admin', 'folder_path': 'NSF Project - Users/Admins'}], + 'resources': [], + } + }, + 'options': {'dry_run': False}, + 'ksm_shared_folders': [ + {'uid': 'users_nsf', 'name': 'NSF Project - Users', 'folder_tree': {}}, + {'uid': 'resources_nsf', 'name': 'NSF Project - Resources', 'folder_tree': {}}, + ], + 'folders': {}, + 'error_count': 0, + } + + with patch('keepercommander.commands.pam_import.extend.create_nsf_subfolder', + return_value='admins_nsf') as create_sub, \ + patch('keepercommander.commands.pam_import.extend.api.sync_down'): + folders = PAMProjectExtendCommand().process_folders(params, project) + + create_sub.assert_called_once() + assert folders['path_to_folder_uid']['NSF Project - Users/Admins'] == 'admins_nsf' + assert project['error_count'] == 0 diff --git a/unit-tests/pam/test_pam_project_extend_nsf_helpers.py b/unit-tests/pam/test_pam_project_extend_nsf_helpers.py new file mode 100644 index 000000000..1fd3299d9 --- /dev/null +++ b/unit-tests/pam/test_pam_project_extend_nsf_helpers.py @@ -0,0 +1,114 @@ +# _ __ +# | |/ /___ ___ _ __ ___ _ _ ® +# | ' → calls add_client.""" diff --git a/unit-tests/test_nested_share_folder.py b/unit-tests/test_nested_share_folder.py index f946d8b07..a022fb2a0 100644 --- a/unit-tests/test_nested_share_folder.py +++ b/unit-tests/test_nested_share_folder.py @@ -110,11 +110,32 @@ def test_parse_expiration_iso_date(self): def test_parse_expiration_relative(self): from keepercommander.commands.nested_share_folder.helpers import parse_expiration - for unit in ('30d', '24h', '30mi', '6mo', '1y'): + for unit in ('30d', '24h', '30mi', '6mo', '1y', '1mi'): result = parse_expiration(None, unit, 'test') self.assertIsInstance(result, int) self.assertGreater(result, int(time.time() * 1000)) + def test_parse_expiration_one_minute_uses_frozen_now(self): + """``1mi`` must not race against a second clock read (classic share fix).""" + from keepercommander.commands.nested_share_folder.helpers import parse_expiration + result = parse_expiration(None, '1mi', 'test') + self.assertIsInstance(result, int) + self.assertGreater(result, int(time.time() * 1000) + 55_000) + + def test_validate_rotate_on_expiration(self): + from keepercommander.commands.nested_share_folder.helpers import ( + validate_rotate_on_expiration) + + validate_rotate_on_expiration('nsf-share-record', 'grant', 1_900_000_000_000) + with self.assertRaises(CommandError) as ctx: + validate_rotate_on_expiration('nsf-share-record', 'revoke', 1_900_000_000_000) + self.assertIn('only valid when granting', str(ctx.exception)) + with self.assertRaises(CommandError) as ctx: + validate_rotate_on_expiration('nsf-share-folder', 'grant', -1) + self.assertIn('positive', str(ctx.exception)) + with self.assertRaises(CommandError): + validate_rotate_on_expiration('nsf-share-folder', 'grant', None) + def test_parse_expiration_invalid(self): from keepercommander.commands.nested_share_folder.helpers import parse_expiration with self.assertRaises(CommandError): @@ -373,6 +394,33 @@ def test_list_with_data(self): cmd.execute(params, folders=True) cmd.execute(params, records=True) + def test_list_roe_eligible_filters_folders(self): + from keepercommander.commands.nested_share_folder import NestedShareFolderListCommand + eligible_uid, eligible_obj = _make_folder(name='Eligible') + plain_uid, plain_obj = _make_folder(name='Plain') + pam_uid, pam_obj = _make_record(title='PAM User') + params = _make_params( + nested_share_folders={ + eligible_uid: eligible_obj, + plain_uid: plain_obj, + }, + nested_share_folder_records={ + eligible_uid: {pam_uid}, + plain_uid: set(), + }, + nested_share_records={pam_uid: pam_obj}, + nested_share_record_data={ + pam_uid: {'data_json': {'title': 'PAM User', 'type': 'pamUser'}}, + }, + record_rotation_cache={pam_uid: {'record_uid': pam_uid}}, + ) + cmd = NestedShareFolderListCommand() + with mock.patch('keepercommander.commands.base.dump_report_data') as dump: + cmd.execute(params, roe_eligible=True) + rows = dump.call_args[0][0] + uids = {row[1] for row in rows} + self.assertEqual(uids, {eligible_uid}) + class TestNestedShareFolderRecordCommands(TestCase): @@ -869,6 +917,95 @@ def test_share_folder_invite_message_uses_command_prefix(self, mock_grant): self.assertIn('nsf-share-folder: Share invitation has been sent', output) self.assertNotIn("User '", output) + def test_share_record_roe_rejects_non_grant(self): + from keepercommander.commands.nested_share_folder import NestedShareRecordShareCommand + ruid, robj = _make_record() + cmd = NestedShareRecordShareCommand() + with self.assertRaises(CommandError) as ctx: + cmd.execute(_make_params(nested_share_records={ruid: robj}), + record=ruid, email=['user@example.com'], + action='revoke', expire_in='1mi', rotate_on_expiration=True) + self.assertIn('only valid when granting', str(ctx.exception)) + + def test_share_record_roe_rejects_ineligible_record(self): + from keepercommander.commands.nested_share_folder import NestedShareRecordShareCommand + ruid, robj = _make_record() + params = _make_params( + nested_share_records={ruid: robj}, + nested_share_record_data={ruid: {'data_json': {'type': 'login'}}}, + record_rotation_cache={}, + ) + cmd = NestedShareRecordShareCommand() + with self.assertRaises(CommandError) as ctx: + cmd.execute(params, record=ruid, email=['user@example.com'], + action='grant', role='viewer', expire_in='1d', + rotate_on_expiration=True) + self.assertIn('pamUser', str(ctx.exception)) + + @patch('keepercommander.nested_share_folder.record_api.share_record_v3') + def test_share_record_roe_passes_flag(self, mock_share): + import keepercommander.nested_share_folder as nsf + from keepercommander.commands.nested_share_folder import NestedShareRecordShareCommand + + nsf.__dict__.pop('share_record_v3', None) + ruid, robj = _make_record() + mock_share.return_value = { + 'success': True, 'message': '', + 'results': [{'record_uid': ruid, 'success': True, 'message': '', 'pending': False}], + } + params = _make_params( + nested_share_records={ruid: robj}, + nested_share_record_data={ruid: {'data_json': {'type': 'pamUser'}}}, + record_rotation_cache={ruid: {'record_uid': ruid}}, + ) + cmd = NestedShareRecordShareCommand() + with mock.patch('builtins.print'), \ + mock.patch.object(NestedShareRecordShareCommand, '_get_direct_user_share', + return_value=None): + cmd.execute(params, record=ruid, email=['user@example.com'], + action='grant', role='viewer', expire_in='1d', + rotate_on_expiration=True) + self.assertTrue(mock_share.call_args.kwargs.get('rotate_on_expiration')) + + def test_share_folder_roe_rejects_folder_without_pam_user(self): + from keepercommander.commands.nested_share_folder import NestedShareFolderShareCommand + fuid, fobj = _make_folder() + params = _make_params( + nested_share_folders={fuid: fobj}, + nested_share_folder_records={fuid: set()}, + ) + cmd = NestedShareFolderShareCommand() + with self.assertRaises(CommandError) as ctx: + cmd.execute(params, folder=[fuid], user=['user@example.com'], + action='grant', role='viewer', expire_in='1d', + rotate_on_expiration=True) + self.assertIn('pamUser', str(ctx.exception)) + + @patch('keepercommander.nested_share_folder.folder_api.grant_folder_access_v3') + def test_share_folder_roe_passes_flag(self, mock_grant): + import keepercommander.nested_share_folder as nsf + from keepercommander.commands.nested_share_folder import NestedShareFolderShareCommand + + nsf.__dict__.pop('grant_folder_access_v3', None) + fuid, fobj = _make_folder() + ruid, robj = _make_record() + mock_grant.return_value = { + 'success': True, 'message': 'ok', 'folder_uid': fuid, + 'user_uid': 'user@example.com', 'access_type': 'AT_USER', + } + params = _make_params( + nested_share_folders={fuid: fobj}, + nested_share_folder_records={fuid: {ruid}}, + nested_share_records={ruid: robj}, + nested_share_record_data={ruid: {'data_json': {'type': 'pamUser'}}}, + record_rotation_cache={ruid: {'record_uid': ruid}}, + ) + cmd = NestedShareFolderShareCommand() + cmd.execute(params, folder=[fuid], user=['user@example.com'], + action='grant', role='viewer', expire_in='1d', + rotate_on_expiration=True) + self.assertTrue(mock_grant.call_args.kwargs.get('rotate_on_expiration')) + class TestNestedShareFolderFolderApi(TestCase): @@ -958,7 +1095,7 @@ def test_grant_folder_access_update_passes_expiration( mock_update.assert_called_once_with( mock.ANY, fuid, email, role='content-manager', as_team=False, - expiration_timestamp=expiration) + expiration_timestamp=expiration, rotate_on_expiration=False) @patch('keepercommander.nested_share_folder.folder_api.update_folder_access_v3') @patch('keepercommander.nested_share_folder.folder_api._check_existing_access') @@ -984,7 +1121,7 @@ def test_grant_folder_access_same_role_updates_expiration( mock_update.assert_called_once_with( mock.ANY, fuid, email, role='viewer', as_team=False, - expiration_timestamp=expiration) + expiration_timestamp=expiration, rotate_on_expiration=False) @patch('keepercommander.nested_share_folder.folder_api.folder_access_update_v3') @@ -1226,6 +1363,39 @@ def test_update_record_share_v3_recreate_when_setting_expiration( self.assertEqual(perm.rules.tlaProperties.expiration, expiration) self.assertEqual(perm.rules.tlaProperties.timerNotificationType, tla_pb2.NOTIFY_OWNER) + @patch('keepercommander.sync_down.sync_down') + @patch('keepercommander.nested_share_folder.record_api.api.communicate_rest') + @patch('keepercommander.nested_share_folder.record_api.encrypt_for_recipient') + @patch('keepercommander.nested_share_folder.record_api.get_user_public_key') + @patch('keepercommander.nested_share_folder.record_api.get_record_from_cache') + def test_update_record_share_v3_recreate_sets_roe( + self, mock_get_record, mock_get_public_key, + mock_encrypt, mock_communicate, mock_sync_down): + from keepercommander.nested_share_folder.record_api import update_record_share_v3 + from keepercommander.proto import tla_pb2 + + ruid, robj = _make_record() + email = 'user@example.com' + uid_bytes = utils.base64_url_decode(utils.generate_uid()) + mock_get_record.return_value = robj + mock_get_public_key.return_value = (Mock(), False, uid_bytes, False) + mock_encrypt.return_value = b'enc-key' + mock_response = Mock() + mock_response.revokedSharingStatus = [_make_sharing_status(ruid, uid_bytes)] + mock_response.createdSharingStatus = [_make_sharing_status(ruid, uid_bytes)] + mock_communicate.side_effect = [mock_response, mock_response] + + expiration = 1_900_000_000_000 + update_record_share_v3( + _make_params(nested_share_records={ruid: robj}), + ruid, email, access_role_type=1, expiration_timestamp=expiration, + rotate_on_expiration=True) + + create_rq = mock_communicate.call_args_list[1][0][1] + perm = create_rq.createSharingPermissions[0] + self.assertTrue(perm.rules.tlaProperties.rotateOnExpiration) + self.assertEqual(perm.rules.tlaProperties.timerNotificationType, tla_pb2.NOTIFY_OWNER) + @patch('keepercommander.sync_down.sync_down') @patch('keepercommander.nested_share_folder.record_api.api.communicate_rest') @patch('keepercommander.nested_share_folder.record_api.encrypt_for_recipient') @@ -1265,6 +1435,12 @@ def test_is_record_share_update_noop(self): existing, 2, 1_900_001_000_000)) self.assertTrue(is_record_share_update_noop( {'access_role_type': 2}, 2, -1)) + # Applying ROE to a share that does not already have it is not a no-op. + self.assertFalse(is_record_share_update_noop( + existing, 2, 1_900_000_000_500, rotate_on_expiration=True)) + self.assertTrue(is_record_share_update_noop( + {**existing, 'tla_rotate_on_expiration': True}, + 2, 1_900_000_000_500, rotate_on_expiration=True)) @patch('keepercommander.nested_share_folder.record_api.api.communicate_rest') def test_get_record_accesses_v3_reads_tla_expiration(self, mock_communicate):