예제 #1
0
파일: api.py 프로젝트: m-wells/Commander
def get_record(params,record_uid):    
    """Return the referenced record"""
    record_uid = record_uid.strip()

    if not record_uid:
        print('No record UID provided')
        return

    if not params.record_cache:
        print('No record cache.  Sync down first.')
        return

    if not record_uid in params.record_cache:
        print('Record UID not found.')
        return

    cached_rec = params.record_cache[record_uid]

    if params.debug: print('Cached Rec: ' + str(cached_rec))
    data = json.loads(cached_rec['data'].decode('utf-8')) 

    rec = Record(record_uid)
    rec.load(data,cached_rec['revision'])

    return rec
예제 #2
0
def parse_record_json(json):
    record = Record()
    record.folder = json['folder']
    record.title = json['title']
    record.login = json['login']
    record.password = json['password']
    record.login_url = json['login_url']
    record.notes = json['notes']
    record.custom_fields = json['custom_fields']
    return record
예제 #3
0
def parse_line(line):
    fields = line.split('\t')
    record = Record()
    record.folder = fields[0]
    record.title = fields[1]
    record.login = fields[2]
    record.password = fields[3]
    record.login_url = fields[4]
    record.notes = fields[5].replace('\\\\n', '\n')
    record.custom_fields = [{'name': fields[i], 'value': fields[i + 1], 'type': 'text'} for i in
                            range(6, len(fields) - 1, 2)]
    return record
예제 #4
0
    def test_audit_log_splunk_properties_success(self):
        splunk = aram.AuditLogSplunkExport()
        props = {}
        record = Record()

        with mock.patch('builtins.print'), mock.patch(
                'builtins.input') as mock_input, mock.patch(
                    'requests.post') as mock_post:
            resp1 = mock.Mock()
            resp1.status_code = 401
            resp1.json.return_value = {'code': 2}
            resp2 = mock.Mock()
            resp2.status_code = 400
            resp2.json.return_value = {'code': 6}
            mock_input.side_effect = [
                'www.splunk.com', 'Splunk Token',
                KeyboardInterrupt()
            ]
            mock_post.side_effect = [resp1, resp2, Exception()]
            splunk.get_properties(record, props)
            self.assertIn('hec_url', props)
            self.assertIn('token', props)
            self.assertEqual(props['hec_url'], record.login_url)
            self.assertEqual(props['token'], record.password)
            self.assertTrue(splunk.store_record)
예제 #5
0
def parse_json(json):
    record = Record()
    record.folder = json['folder']
    record.title = json['title']
    record.login = json['login']
    record.password = json['password']
    record.login_url = json['login_url']
    record.notes = json['notes']
    record.custom_fields = json['custom_fields']
    return record
예제 #6
0
파일: api.py 프로젝트: m-wells/Commander
def add_record(params):
    """ Create a new record with passed-in data or interactively.
        The shared folder UID is also optional 
    """
    record = Record()
    if not record.title:
        while not record.title:
            record.title = input("... Title (req'd): ")
        record.folder = input("... Folder: ")
        record.login = input("... Login: "******"... Password: "******"... Login URL: ")
        record.notes = input("... Notes: ")
        while True:
            custom_dict = {}
            custom_dict['name'] = input("... Custom Field Name : ") 
            if not custom_dict['name']:
                break

            custom_dict['value'] = input("... Custom Field Value : ") 
            custom_dict['type'] = 'text' 
            record.custom_fields.append(custom_dict)

    new_record = prepare_record(params, record)
    request = make_request(params, 'record_update')
    request['add_records'] = [new_record]

    response_json = communicate(params, request)

    if response_json['result'] == 'success':
        new_revision = 0
        if 'add_records' in response_json:
            for info in response_json['add_records']:
                if info['record_uid'] == record.record_uid:
                    if info['status'] == 'success':
                        # all records in the transaction get the
                        # same revision.  this just checks 100% success
                        new_revision = response_json['revision']

        if new_revision == 0:
            print('Error: Revision not updated')
            return False

        if new_revision == new_record['revision']:
            print('Error: Revision did not change')
            return False

        print('New record successful for record_uid=' + \
            str(new_record['record_uid']) + ', revision=' + \
            str(new_record['revision']), ', new_revision=' + \
            str(new_revision))

        new_record['revision'] = new_revision

        # sync down the data which updates the caches
        sync_down(params)

        return True
예제 #7
0
def parse_line(line):
    fields = line.split('\t')
    record = Record()
    record.folder = fields[0]
    record.title = fields[1]
    record.login = fields[2]
    record.password = fields[3]
    record.login_url = fields[4]
    record.notes = fields[5].replace('\\\\n', '\n')
    record.custom_fields = [{'name': fields[i], 'value': fields[i + 1], 'type': 'text'} for i in
                            range(6, len(fields) - 1, 2)]
    return record
 def test_audit_log_splunk_properties_cancel(self):
     splunk = enterprise.AuditLogSplunkExport()
     props = {}
     record = Record()
     with mock.patch('builtins.print'), mock.patch('builtins.input') as mock_input, mock.patch('requests.post') as mock_post:
         resp1 = mock.Mock()
         resp1.status_code = 404
         mock_input.side_effect = ['www.splunk.com', KeyboardInterrupt()]
         mock_post.side_effect = [resp1, Exception()]
         with self.assertRaises(KeyboardInterrupt):
             splunk.get_properties(record, props)
예제 #9
0
def sample_record():
    record = Record()
    record.folder = "folder"
    record.title = "title"
    record.login = "******"
    record.password = "******"
    record.login_url = "login_url"
    record.notes = "line1\nline2\nline3"
    record.custom_fields = [
        {"name": "cf1", "value": "cf1val", "type": "text"},
        {"name": "cf2", "value": "cf2val", "type": "text"},
    ]
    return record
예제 #10
0
def sample_record():
    record = Record()
    record.folder = 'folder'
    record.title = 'title'
    record.login = '******'
    record.password = '******'
    record.login_url = 'login_url'
    record.notes = 'line1\nline2\nline3'
    record.custom_fields = [{
        'name': 'cf1',
        'value': 'cf1val',
        'type': 'text'
    }, {
        'name': 'cf2',
        'value': 'cf2val',
        'type': 'text'
    }]
    return record
예제 #11
0
from keepercommander.record import Record
from keepercommander.params import KeeperParams
from keepercommander import display, api

my_params = KeeperParams()

while not my_params.user:
    my_params.user = getpass.getpass(prompt='User(Email): ', stream=None)

while not my_params.password:
    my_params.password = getpass.getpass(prompt='Master Password: '******'Test Record'
r.login = '******'

# generate a 32-char random password
r.password = ''.join(random.SystemRandom().choice(string.printable) for _ in range(32)) 

if api.add_record(my_params, r):
    print('Added record UID='+r.record_uid) 

# Delete the record 
if r.record_uid:
    api.delete_record(my_params, r.record_uid)


예제 #12
0
from keepercommander.params import KeeperParams
from keepercommander.shared_folder import SharedFolder
from keepercommander import display, api

params = KeeperParams()

# Inputs - hard coded for demo purposes
params.user = '******'
params.password = '******'
shared_folder_uid = 'your_shared_folder_uid'

# Login and sync
api.sync_down(params)

# Create a new record with some random password
record = Record()
record.title = 'Test Record'
record.login = '******'
record.login_url = 'https://google.com'
record.notes = 'Here are some notes.'
record.password = ''.join(random.SystemRandom().choice(string.printable)
                          for _ in range(32))

# Add the record to your vault
if api.add_record(params, record):
    print('Added record UID=' + record.record_uid)
else:
    print('Error: Unable to add record')
    sys.exit()

# Get existing shared folder from the cache
예제 #13
0
파일: api.py 프로젝트: m-wells/Commander
def rotate_password(params, record_uid):
    """ Rotate the password for the specified record UID """

    record_uid = record_uid.strip()

    if not record_uid:
        print('No record UID provided')
        return False

    if not params.record_cache:
        print('No record cache.  Sync down first.')
        return False

    if not record_uid in params.record_cache:
        print('Record UID not found.')
        return False

    # get the record object
    cached_rec = params.record_cache[record_uid]

    # extract data and extra from record
    if 'data' in cached_rec:
        data = json.loads(cached_rec['data'].decode('utf-8')) 
    else: data = {}

    if 'extra' in cached_rec:
        extra = json.loads(cached_rec['extra'].decode('utf-8')) 
    else: extra = {}

    # check for edit permissions
    can_edit = False
    if 'can_edit' in cached_rec:
        if params.debug: print('Edit permissions found in record')
        can_edit = True

    # If record permission not there, check shared folders
    found_shared_folder_uid = ''
    if can_edit == False:
        for shared_folder_uid in params.shared_folder_cache:
            shared_folder = params.shared_folder_cache[shared_folder_uid]
            sf_key = shared_folder['shared_folder_key']
            if 'records' in shared_folder:
                sf_records = shared_folder['records']
                for sf_record in sf_records:
                    if 'record_uid' in sf_record:
                        if sf_record['record_uid'] == record_uid:
                            found_shared_folder_uid = shared_folder_uid
                            if 'can_edit' in sf_record:
                                can_edit = True
                                if params.debug: 
                                    print('Edit permissions found in folder')
                                break

    if not can_edit:
        print('You do not have permissions to edit this record.')
        return False

    if not params.server:
        raise CommunicationError('No server provided')

    if not params.user:
        raise CommunicationError('No username provided')

    # save previous password
    if params.debug: print('Data: ' + str(data))
    if params.debug: print('Extra: ' + str(extra))

    # generate friendly datestamp
    modified_time = int(round(time.time()))
    modified_time_milli = modified_time * 1000 
    datestamp = datetime.datetime.fromtimestamp(
        modified_time).strftime('%Y-%m-%d %H:%M:%S')

    # Backup old password in a custom field
    custom_dict = {}
    custom_dict['name'] = 'cmdr:Rotation @ '+str(datestamp)
    custom_dict['value'] = data['secret2']
    custom_dict['type'] = 'text' 

    # serialize this dict
    serialized = json.dumps(custom_dict)

    # load as json
    custom_dict_json = json.loads(serialized)

    # Append to the current structure
    data['custom'].append(custom_dict_json)
    
    if params.debug: 
        print('Old password: '******'secret2']))

    # load the data into a record object for convenience
    record_object = Record()
    record_object.load(data)

    new_password = generator.generate()

    # generate a new password with any specified rules
    rules = record_object.get("cmdr:rules")
    if rules:
        new_password = generator.generateFromRules(rules)

    # execute rotation plugin associated with this record
    plugin_name = record_object.get("cmdr:plugin")
    if plugin_name:
        print("Rotating with plugin " + str(plugin_name))
        plugin = plugin_manager.get_plugin(plugin_name)
        if plugin:
            success =  plugin.rotate(record_object, new_password)

            if success:
                if params.debug: 
                    print('Password rotation on target system is successful.')
            else:
                print('Password rotation failed')
                return False
        else:
            return False

    # Proceed with Keeper password rotation
    data['secret2'] = new_password 

    if params.debug: 
        print('New password: '******'secret2']))

    if params.debug: 
        print('New record data: ' + str(data))

    # Update the record cache with the cleartext data
    if params.debug: print('data is ' + str(isinstance(data, dict)))
    if params.debug: print('params.record_cache is ' + \
        str(isinstance(params.record_cache, dict)))

    # convert dict back to json then encode it 
    params.record_cache[record_uid]['data'] = json.dumps(data).encode()

    if params.debug: 
        print('New record: ' + str(params.record_cache[record_uid]))
        print('Data: ' + str(data))
        print('Extra: ' + str(extra))

    # Convert the data and extra dictionary to string object
    # with double quotes instead of single quotes
    data_serialized = json.dumps(data)
    extra_serialized = json.dumps(extra)

    if params.debug: print('data_serialized: ' + str(data_serialized))
    if params.debug: print('extra_serialized: ' + str(extra_serialized))

    # encrypt data and extra
    if not 'record_key_unencrypted' in params.record_cache[record_uid]:
        if plugin_name: 
            print('Plugin updated password to: ' + new_password)
        raise CryptoError('No record_key_unencrypted found for ' + record_uid)

    if not 'record_key' in params.record_cache[record_uid]:
        if plugin_name: 
            print('Plugin updated password to: ' + new_password)
        raise CryptoError('No record_key found for ' + record_uid)

    record_key_unencrypted = \
        params.record_cache[record_uid]['record_key_unencrypted']
    iv = os.urandom(16)
    cipher = AES.new(record_key_unencrypted, AES.MODE_CBC, iv)
    encrypted_data = iv + cipher.encrypt(pad(data_serialized))

    iv = os.urandom(16)
    cipher = AES.new(record_key_unencrypted, AES.MODE_CBC, iv)
    encrypted_extra = iv + cipher.encrypt(pad(extra_serialized))

    if params.debug: print('encrypted_data: ' + str(encrypted_data))
    if params.debug: print('encrypted_extra: ' + str(encrypted_extra))

    # note: decode() converts bytestream (b') to string
    encoded_data = base64.urlsafe_b64encode(encrypted_data).decode()
    encoded_extra = base64.urlsafe_b64encode(encrypted_extra).decode()

    if params.debug: print('encoded_data: ' + str(encoded_data))
    if params.debug: print('encoded_extra: ' + str(encoded_extra))

    # build a record object
    new_record = {}
    new_record['record_uid'] = record_uid
    new_record['version'] = 2 
    new_record['data'] = encoded_data
    new_record['extra'] = encoded_extra
    new_record['client_modified_time'] = modified_time_milli
    new_record['revision'] = params.record_cache[record_uid]['revision']
    if found_shared_folder_uid:
        new_record['shared_folder_uid'] = found_shared_folder_uid

    if 'udata' in params.record_cache[record_uid]:
        new_record['udata'] = params.record_cache[record_uid]['udata']
        
    if params.debug: print('new_record: ' + str(new_record))

    # create updated records
    update_records = []
    update_records.append(new_record)

    def make_json(params, update_records):
        return {
               'client_time':current_milli_time(),
               'device_id':'Commander', 
               'device_name':'Commander', 
               'command':'record_update', 
               'update_records':update_records,
               'protocol_version':1, 
               'client_version':CLIENT_VERSION,
               '2fa_token':params.mfa_token,
               '2fa_type':params.mfa_type, 
               'session_token':params.session_token, 
               'username':params.user
        }
        
    if not params.session_token:
        try:
            login(params)
        except:
            if plugin_name: 
                print('Plugin updated password to: ' + new_password)
            raise
            
    payload = make_json(params, update_records)

    if params.debug: print('payload: ' + str(payload))
    
    try:
        r = requests.post(params.server, json=payload)
    except:
        if plugin_name: 
            print('Plugin updated password to: ' + new_password)
        raise CommunicationError(sys.exc_info()[0])

    response_json = r.json()

    if params.debug:
        debug_response(params, payload, r)

    if response_json['result_code'] == 'auth_failed':
        if params.debug: print('Re-authorizing.')

        try:
            login(params)
        except:
            if plugin_name: 
                print('Plugin updated password to: ' + new_password)
            raise

        payload = make_json(params, update_records)

        try:
            r = requests.post(params.server, json=payload)
        except:
            print('Comm error during re-auth')
            if plugin_name: 
                print('Plugin updated password to: ' + new_password)
            raise CommunicationError(sys.exc_info()[0])
    
        response_json = r.json()
    
        if params.debug:
            debug_response(params, payload, r)

    if response_json['result'] == 'success':
        new_revision = 0
        if 'update_records' in response_json:
            for info in response_json['update_records']:
                if info['record_uid'] == record_uid:
                    if info['status'] == 'success':
                        # all records in the transaction get the 
                        # same revision.  this just checks 100% success
                        new_revision = response_json['revision']
             
        if new_revision == 0:
            print('Error: Revision not updated')
            if plugin_name: 
                print('Plugin updated password to: ' + new_password)
            return False

        if new_revision == new_record['revision']:
            print('Error: Revision did not change')
            if plugin_name: 
                print('Plugin updated password to: ' + new_password)
            return False

        print('Rotation successful for record_uid=' + \
            str(new_record['record_uid']) + ', revision=' + \
            str(new_record['revision']), ', new_revision=' + \
            str(new_revision))

        # update local cache
        params.record_cache[record_uid]['revision'] = new_revision

    else :
        if response_json['result_code']:
            if plugin_name: 
                print('Plugin updated password to: ' + new_password)
            raise CommunicationError('Unexpected problem: ' + \
                response_json['result_code'])

    return True
예제 #14
0
def do_command(params):
    if (params.command == 'q'):
        return False

    elif (params.command == 'l'):
        if (len(params.record_cache) == 0):
            print('No records')
        else:
            results = api.search_records(params, '')
            display.formatted_records(results)

    elif (params.command == 'lsf'):
        if (len(params.shared_folder_cache) == 0):
            print('No shared folders')
        else:
            results = api.search_shared_folders(params, '')
            display.formatted_shared_folders(results)

    elif (params.command == 'lt'):
        if (len(params.team_cache) == 0):
            print('No teams')
        else:
            results = api.search_teams(params, '')
            display.formatted_teams(results)

    elif (params.command[:2] == 'g '):
        if (api.is_shared_folder(params, params.command[2:])):
            sf = api.get_shared_folder(params, params.command[2:])
            if sf:
                sf.display()
        elif (api.is_team(params, params.command[2:])):
            team = api.get_team(params, params.command[2:])
            if team:
                team.display()
        else:
            r = api.get_record(params, params.command[2:])
            if r:
                r.display()

    elif (params.command[:2] == 'r '):
        api.rotate_password(params, params.command[2:])

    elif (params.command[:2] == 'd '):
        api.delete_record(params, params.command[2:])

    elif (params.command == 'c'):
        print(chr(27) + "[2J")

    elif (params.command[:2] == 's '):
        results = api.search_records(params, params.command[2:])
        display.formatted_records(results)

    elif (params.command[:2] == 'b '):
        results = api.search_records(params, params.command[2:])
        for r in results:
            api.rotate_password(params, r.record_uid)

    elif (params.command[:3] == 'an '):
        api.append_notes(params, params.command[3:])

    elif (params.command == 'd'):
        api.sync_down(params)

    elif (params.command == 'a'):
        record = Record()
        while not record.title:
            record.title = input("... Title (req'd): ")
        record.folder = input("... Folder: ")
        record.login = input("... Login: "******"... Password: "******"... Login URL: ")
        record.notes = input("... Notes: ")
        while True:
            custom_dict = {}
            custom_dict['name'] = input("... Custom Field Name : ")
            if not custom_dict['name']:
                break

            custom_dict['value'] = input("... Custom Field Value : ")
            custom_dict['type'] = 'text'
            record.custom_fields.append(custom_dict)

        api.add_record(params, record)

    elif (params.command == 'h'):
        display.formatted_history(stack)

    elif (params.command == 'debug'):
        if params.debug:
            params.debug = False
            print('Debug OFF')
        else:
            params.debug = True
            print('Debug ON')

    elif params.command == '':
        pass

    else:
        print('\n\nShell Commands:\n')
        print('  d         ... download & decrypt data')
        print('  l         ... list folders and record titles')
        print('  lsf       ... list shared folders')
        print('  lt        ... list teams')
        print('  s <regex> ... search with regular expression')
        print('  g <uid>   ... get record or shared folder details for uid')
        print('  r <uid>   ... rotate password for uid')
        print(
            '  b <regex> ... rotate password for matches of regular expression'
        )
        print('  a         ... add a new record interactively')
        print('  an <uid>  ... append some notes to the specified record')
        print('  c         ... clear the screen')
        print('  h         ... show command history')
        print('  q         ... quit')
        print('')

    if params.command:
        if params.command != 'h':
            stack.append(params.command)
            stack.reverse()

    return True