Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion keepercommander/importer/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ def _cyberark_skip_arg(value):

apply_membership_parser = argparse.ArgumentParser(prog='apply-membership', description='Loads shared folder membership from JSON file')
apply_membership_parser.add_argument('--full-sync', dest='full_sync', action='store_true', help='Update and remove membership also.')
apply_membership_parser.add_argument('--unsafe', dest='unsafe', action='store_true', help='Combined with --full-sync. Will remove yourself from folders where you have no permission.')
apply_membership_parser.add_argument('name', type=str, nargs='?', help='Input file name. "shared_folder_membership.json" if omitted.')
apply_membership_parser.error = raise_parse_exception
apply_membership_parser.exit = suppress_exit
Expand Down Expand Up @@ -547,8 +548,9 @@ def execute(self, params, **kwargs):
teams.append(obj)

full_sync = kwargs.get('full_sync') is True
unsafe = kwargs.get('unsafe') is True
if len(shared_folders) > 0:
imp_exp.import_user_permissions(params, shared_folders, full_sync)
imp_exp.import_user_permissions(params, shared_folders, full_sync, unsafe)

if len(teams) > 0:
imp_exp.import_teams(params, teams, full_sync)
Expand Down
63 changes: 40 additions & 23 deletions keepercommander/importer/imp_exp.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ def import_teams(params, teams, full_sync=False): # type: (KeeperParams, List[

def import_user_permissions(params,
shared_folders,
full_sync=False): # type: (KeeperParams, List[ImportSharedFolder], bool) -> None
full_sync=False, unsafe=False): # type: (KeeperParams, List[ImportSharedFolder], bool) -> None
if not shared_folders:
return

Expand Down Expand Up @@ -654,7 +654,7 @@ def import_user_permissions(params,

folders = [x for x in folders if x.uid in params.shared_folder_cache]
if folders:
permissions = prepare_folder_permission(params, folders, full_sync)
permissions = prepare_folder_permission(params, folders, full_sync, unsafe)
if permissions:
teams_added = 0
users_added = 0
Expand Down Expand Up @@ -1889,32 +1889,46 @@ def prepare_folder_add(params, folders, records, manage_users, manage_records, c
is_last = True

if digest not in folder_hash:
folder_uid = api.generate_record_uid()
folder_type = 'shared_folder' if is_last else 'user_folder'
existing_by_uid = None
if is_last:
sf_uid = getattr(fol, 'uid', None)
if sf_uid and sf_uid in params.shared_folder_cache and sf_uid in params.folder_cache:
# The import file names an existing shared folder by uid.
# Reuse it in place (no new folder, no move) so any
# records that reference this path resolve to it.
shared_folder_key = params.shared_folder_cache[sf_uid]['shared_folder_key_unencrypted']
existing_by_uid = sf_uid, 'shared_folder', shared_folder_key

if existing_by_uid is not None:
folder_uid, folder_type, folder_key = existing_by_uid
folder_hash[digest] = existing_by_uid
else:
folder_uid = api.generate_record_uid()
folder_type = 'shared_folder' if is_last else 'user_folder'

fol_req = folder_pb2.FolderRequest()
fol_req.folderUid = base64.urlsafe_b64decode(folder_uid + '==')
fol_req.folderType = 2 if folder_type == 'shared_folder' else 1
fol_req = folder_pb2.FolderRequest()
fol_req.folderUid = base64.urlsafe_b64decode(folder_uid + '==')
fol_req.folderType = 2 if folder_type == 'shared_folder' else 1

if parent_uid:
fol_req.parentFolderUid = base64.urlsafe_b64decode(parent_uid + '==')
if parent_uid:
fol_req.parentFolderUid = base64.urlsafe_b64decode(parent_uid + '==')

folder_key = utils.generate_aes_key()
fol_req.encryptedFolderKey = crypto.encrypt_aes_v1(folder_key, params.data_key)
folder_key = utils.generate_aes_key()
fol_req.encryptedFolderKey = crypto.encrypt_aes_v1(folder_key, params.data_key)

data = {'name': comp}
fol_req.folderData = crypto.encrypt_aes_v1(json.dumps(data).encode('utf-8'), folder_key)
data = {'name': comp}
fol_req.folderData = crypto.encrypt_aes_v1(json.dumps(data).encode('utf-8'), folder_key)

if folder_type == 'shared_folder':
fol_req.sharedFolderFields.encryptedFolderName = \
crypto.encrypt_aes_v1(comp.encode('utf-8'), folder_key)
fol_req.sharedFolderFields.manageUsers = fol.manage_users or manage_users
fol_req.sharedFolderFields.manageRecords = fol.manage_records or manage_records
fol_req.sharedFolderFields.canEdit = fol.can_edit or can_edit
fol_req.sharedFolderFields.canShare = fol.can_share or can_share
if folder_type == 'shared_folder':
fol_req.sharedFolderFields.encryptedFolderName = \
crypto.encrypt_aes_v1(comp.encode('utf-8'), folder_key)
fol_req.sharedFolderFields.manageUsers = fol.manage_users or manage_users
fol_req.sharedFolderFields.manageRecords = fol.manage_records or manage_records
fol_req.sharedFolderFields.canEdit = fol.can_edit or can_edit
fol_req.sharedFolderFields.canShare = fol.can_share or can_share

folder_add.append(fol_req)
folder_hash[digest] = folder_uid, folder_type, folder_key if folder_type == 'shared_folder' else None
folder_add.append(fol_req)
folder_hash[digest] = folder_uid, folder_type, folder_key if folder_type == 'shared_folder' else None
else:
folder_uid, folder_type, folder_key = folder_hash[digest]
if is_last:
Expand Down Expand Up @@ -2572,7 +2586,7 @@ def prepare_record_link(params, records):
return record_links


def prepare_folder_permission(params, folders, full_sync):
def prepare_folder_permission(params, folders, full_sync, unsafe=False):
# type: (KeeperParams, List[ImportSharedFolder], bool) -> list
"""Prepare a list of API interactions for changes to folder permissions."""
shared_folder_lookup = {}
Expand Down Expand Up @@ -2668,6 +2682,9 @@ def prepare_folder_permission(params, folders, full_sync):
existing_users.update((x['username'] for x in shared_folder['users']))
if params.user in existing_users:
existing_users.remove(params.user)
if unsafe:
# Set user to end of array to be removed last
existing_users.add(params.user)
keep_teams = set()
keep_users = set()

Expand Down