Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release #1321

Merged
merged 4 commits into from
Nov 8, 2024
Merged

Release #1321

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
15 changes: 11 additions & 4 deletions examples/add_user_to_shared_folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,17 @@
if isinstance(manage_records, bool):
arq.manageRecords = folder_pb2.BOOLEAN_TRUE if manage_records else folder_pb2.BOOLEAN_FALSE
public_keys = my_params.key_cache.get(user)
if public_keys and public_keys.rsa:
user_rsa_key = crypto.load_rsa_public_key(public_keys.rsa)
arq.sharedFolderKey = crypto.encrypt_rsa(shared_folder_key, user_rsa_key)
rq.sharedFolderAddUser.append(arq)
if public_keys:
if public_keys.ec:
user_ec_key = crypto.load_ec_public_key(public_keys.ec)
arq.typedSharedFolderKey.encryptedKey = crypto.encrypt_ec(shared_folder_key, user_ec_key)
arq.typedSharedFolderKey.encryptedKeyType = folder_pb2.encrypted_by_public_key_ecc
rq.sharedFolderAddUser.append(arq)
elif not my_params.forbid_rsa and public_keys.rsa:
user_rsa_key = crypto.load_rsa_public_key(public_keys.rsa)
arq.typedSharedFolderKey.encryptedKey = crypto.encrypt_rsa(shared_folder_key, user_rsa_key)
arq.typedSharedFolderKey.encryptedKeyType = folder_pb2.encrypted_by_public_key
rq.sharedFolderAddUser.append(arq)
else:
logging.warning('Add user "%s": User public key is not available', user)

Expand Down
2 changes: 1 addition & 1 deletion keepercommander/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
# Contact: [email protected]
#

__version__ = '16.11.17'
__version__ = '16.11.18'
66 changes: 49 additions & 17 deletions keepercommander/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def login(params, new_login=False, login_ui=None):
flow.login(params, new_device=True)


def accept_account_transfer_consent(params):
def accept_account_transfer_consent(params): # type: (KeeperParams) -> bool
share_account_by = params.get_share_account_timestamp()
print(constants.ACCOUNT_TRANSFER_MSG.format(share_account_by.strftime('%a, %b %d %Y')))

Expand All @@ -81,21 +81,45 @@ def accept_account_transfer_consent(params):
answer = input('Do you accept Account Transfer policy? {}: '.format(input_options))
answer = answer.lower()
if answer.lower() == 'accept':
for role in params.settings['share_account_to']:
encoded_public = utils.base64_url_decode(role['public_key'])
public_key = crypto.load_rsa_public_key(encoded_public)
transfer_key = crypto.encrypt_rsa(params.data_key, public_key)
request = {
'command': 'share_account',
'to_role_id': role['role_id'],
'transfer_key': utils.base64_url_encode(transfer_key)
}
communicate(params, request)
return True
ok = True
requests = []
if 'share_account_to' in params.settings:
for role in params.settings['share_account_to']:
request = {
'command': 'share_account',
'to_role_id': role['role_id'],
}
if not params.forbid_rsa and 'public_key' in role:
encoded_public = utils.base64_url_decode(role['public_key'])
public_key = crypto.load_rsa_public_key(encoded_public)
transfer_key = crypto.encrypt_rsa(params.data_key, public_key)
request['transfer_key'] = utils.base64_url_encode(transfer_key)

requests.append(request)
responses = execute_batch(params, requests)
if isinstance(responses, list):
for response in responses:
if response['result_code'] != 'success':
logging.warning('Account Transfer policy acceptance error: %s',
response.get('message') or response['result_code'])
ok = False
if ok and params.forbid_rsa and params.enterprise_ec_key:
try:
share_data_key_with_enterprise(params)
except Exception as e:
logging.warning('Account Transfer policy acceptance error: %s', e)
ok = False
return ok
else:
return False


def share_data_key_with_enterprise(params): # type: (KeeperParams) -> None
rq = enterprise_pb2.EnterpriseUserDataKey()
rq.userEncryptedDataKey = crypto.encrypt_ec(params.data_key, params.enterprise_ec_key)
communicate_rest(params, rq, 'enterprise/set_enterprise_user_data_key')


def get_record_data_json_bytes(data): # type: (dict) -> bytes
"""Get serialized and utf-8 encoded record data with padding"""
data_str = json.dumps(data)
Expand Down Expand Up @@ -342,14 +366,22 @@ def load_team_keys(params, team_uids): # type: (KeeperParams, List[str]
try:
aes = b''
rsa = b''
ec = b''
encrypted_key = utils.base64_url_decode(tk['key'])
if tk['type'] == 1:
key_type = tk['type']
if key_type == 1:
aes = crypto.decrypt_aes_v1(encrypted_key, params.data_key)
elif tk['type'] == 2:
aes = crypto.decrypt_rsa(tk['key'], params.rsa_key2)
elif tk['type'] == 3:
elif key_type == 2:
aes = crypto.decrypt_rsa(encrypted_key, params.rsa_key2)
elif key_type == 3:
aes = crypto.decrypt_aes_v2(encrypted_key, params.data_key)
elif key_type == 4:
aes = crypto.decrypt_ec(encrypted_key, params.ecc_key)
elif key_type == -1:
ec = encrypted_key
elif key_type == -3:
rsa = encrypted_key
params.key_cache[team_uid] = PublicKeys(rsa=rsa, aes=aes)
params.key_cache[team_uid] = PublicKeys(rsa=rsa, aes=aes, ec=ec)
except Exception as e:
logging.debug(e)

Expand Down
9 changes: 7 additions & 2 deletions keepercommander/breachwatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from .commands.helpers.enterprise import user_has_privilege, is_addon_enabled
from .constants import KEEPER_PUBLIC_HOSTS
from . import api, crypto, utils, rest_api, vault
from .proto import breachwatch_pb2, client_pb2, APIRequest_pb2
from .proto import breachwatch_pb2, client_pb2, APIRequest_pb2, enterprise_pb2
from .error import KeeperApiError, CommandError
from .params import KeeperParams
from .vault import KeeperRecord
Expand Down Expand Up @@ -211,7 +211,11 @@ def prepare_security_data():
sec_data.uid = utils.base64_url_decode(record.record_uid)
if record_pw:
rec_sd = prepare_security_data()
sec_data.data = crypto.encrypt_rsa(json.dumps(rec_sd).encode('utf-8'), params.enterprise_rsa_key)
data = json.dumps(rec_sd).encode('utf-8')
if params.forbid_rsa:
sec_data.data = crypto.encrypt_ec(data, params.enterprise_ec_key)
else:
sec_data.data = crypto.encrypt_rsa(data, params.enterprise_rsa_key)

return sec_data

Expand Down Expand Up @@ -248,6 +252,7 @@ def skip_update():
update_rq = APIRequest_pb2.SecurityDataRequest()
rec_sec_data = calculate_security_data()
update_rq.recordSecurityData.append(rec_sec_data)
update_rq.encryptionType = enterprise_pb2.KT_ENCRYPTED_BY_PUBLIC_KEY_ECC if params.forbid_rsa else enterprise_pb2.KT_ENCRYPTED_BY_PUBLIC_KEY
api.communicate_rest(params, update_rq, 'enterprise/update_security_data')

@staticmethod
Expand Down
43 changes: 21 additions & 22 deletions keepercommander/commands/aram.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,34 @@
import base64
import copy
import datetime
import os
import time
import json
import gzip
import hashlib
import hmac
import json
import logging
import os
import platform
import re
import socket
import ssl
import sys
import time
from functools import partial

from typing import Optional, List, Union, Dict, Set, Any, Tuple
from urllib.parse import urlparse

import requests
import socket
import ssl
import hashlib
import hmac

from urllib.parse import urlparse

from .transfer_account import EnterpriseTransferUserCommand
from ..display import bcolors
from .helpers import audit_report
from .enterprise_common import EnterpriseCommand
from .base import user_choice, suppress_exit, raise_parse_exception, dump_report_data, Command, field_to_title
from .enterprise_common import EnterpriseCommand
from .helpers import audit_report
from .transfer_account import EnterpriseTransferUserCommand
from .. import api, vault, record_management
from ..constants import EMAIL_PATTERN
from ..display import bcolors
from ..error import CommandError
from ..params import KeeperParams
from ..proto import enterprise_pb2
from ..constants import EMAIL_PATTERN
from ..sox import sox_data, get_prelim_data, is_compliance_reporting_enabled, get_sox_database_name, \
get_compliance_data, get_node_id
from ..sox.sox_data import RebuildTask
Expand Down Expand Up @@ -713,7 +711,7 @@ def convert_event(self, props, event):
def export_events(self, props, events):
url = "https://{0}.ods.opinsights.azure.com/api/logs?api-version=2016-04-01".format(props['wsid'])
data = json.dumps(events)
dt = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
dt = datetime.datetime.now(datetime.timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
shared_key = self.build_shared_key(props['wsid'], props['wskey'], len(data), dt)
headers = {
"Authorization": "SharedKey {0}".format(shared_key),
Expand Down Expand Up @@ -1170,7 +1168,7 @@ def convert_value(field, value, **kwargs):
if isinstance(value, str):
return value
if isinstance(value, (int, float)):
dt = datetime.datetime.utcfromtimestamp(int(value)).replace(tzinfo=datetime.timezone.utc).astimezone(tz=None)
dt = datetime.datetime.fromtimestamp(int(value), tz=datetime.timezone.utc)
rt = kwargs.get('report_type') or ''
if rt in {'day', 'week'}:
dt = dt.date()
Expand All @@ -1180,7 +1178,7 @@ def convert_value(field, value, **kwargs):
dt = dt.strftime('%Y-%m-%d @%H:00')
return dt
elif field in {"first_created", "last_created"}:
return datetime.datetime.utcfromtimestamp(int(value)).replace(tzinfo=datetime.timezone.utc).astimezone(tz=None)
return datetime.datetime.fromtimestamp(int(value), tz=datetime.timezone.utc)
return value

DimensionCache = {}
Expand Down Expand Up @@ -1342,7 +1340,7 @@ def filter_rows(rows, search_pattern):
rq['timezone'] = tt[0]
else:
now = time.time()
utc_offset = datetime.datetime.fromtimestamp(now) - datetime.datetime.utcfromtimestamp(now)
utc_offset = datetime.datetime.fromtimestamp(now) - datetime.datetime.fromtimestamp(now, ts=datetime.timezone.utc)
hours = (utc_offset.days * 24) + int(utc_offset.seconds / 60 / 60)
rq['timezone'] = hours

Expand Down Expand Up @@ -1993,10 +1991,11 @@ def transfer_accounts(from_users, to_user, dryrun=False):
if dryrun:
cmd_status = 'dry run'
else:
pub_key = self.get_public_key(params, target)
if pub_key:
api.load_user_public_keys(params, [target], False)
target_pub_keys = params.key_cache.get(target)
if target_pub_keys:
for email in [u.get('username') for u in from_users]:
result = EnterpriseTransferUserCommand.transfer_user_account(params, email, target, pub_key)
result = EnterpriseTransferUserCommand.transfer_user_account(params, email, target, target_pub_keys)
if result:
affected += 1

Expand Down
2 changes: 1 addition & 1 deletion keepercommander/commands/automator.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ def execute(self, params, **kwargs): # type: (KeeperParams, **any) -> any
encrypted_ec_private_key = crypto.encrypt_ec(ec_private_key, automator_public_key)
rq.encryptedEccEnterprisePrivateKey = encrypted_ec_private_key

if 'rsa_encrypted_private_key' in keys:
if not params.forbid_rsa and 'rsa_encrypted_private_key' in keys:
encrypted_rsa_private_key = utils.base64_url_decode(keys['rsa_encrypted_private_key'])
rsa_private_key = crypto.decrypt_aes_v2(encrypted_rsa_private_key, params.enterprise['unencrypted_tree_key'])
encrypted_rsa_private_key = crypto.encrypt_ec(rsa_private_key, automator_public_key)
Expand Down
4 changes: 4 additions & 0 deletions keepercommander/commands/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ def register_enterprise_commands(commands, aliases, command_info):
from . import enterprise_reports
enterprise_reports.register_commands(commands)
enterprise_reports.register_command_info(aliases, command_info)
from .risk_management import RiskManagementReportCommand
commands['risk-management'] = RiskManagementReportCommand()
command_info['risk-management'] = 'Risk Management Reports'
aliases['rmd'] = 'risk-management'


def register_msp_commands(commands, aliases, command_info):
Expand Down
17 changes: 0 additions & 17 deletions keepercommander/commands/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,6 @@ def execute(self, params, **kwargs):

print('\n'.join(f' {k} {v}' for k, v in record_names.items()))
else:
rq = {
'command': 'sync_down',
'revision': 0,
'include': ['non_shared_data', 'explicit']
}
rs = api.communicate(params, rq)
nsd = {x['record_uid']: x['data'] for x in rs.get('non_shared_data', [])}

records = []
for record_uid in record_uids:
convert_result = ConvertCommand.convert_to_record_type_data(record_uid, params, type_info)
Expand Down Expand Up @@ -251,15 +243,6 @@ def execute(self, params, **kwargs):
rc.record_file.append(rf)
rc.data = crypto.encrypt_aes_v2(api.get_record_data_json_bytes(v3_data), record_key)

# Non shared data
if record_uid in nsd:
try:
non_shared_data = utils.base64_url_decode(nsd[record_uid])
non_shared_data = crypto.decrypt_aes_v1(non_shared_data, params.data_key)
rc.non_shared_data = crypto.encrypt_aes_v2(non_shared_data, params.data_key)
except Exception as e:
logging.debug('Non shared data conversion failed for record %s: ', record_uid, e)

# Get share folder of the record so that we can convert the Record Folder Key
shared_folders = find_parent_top_folder(params, record_uid)

Expand Down
Loading
Loading