Prepares the Record() object to be sent to the Keeper Cloud API by serializing and encrypting it in the proper JSON format used for transmission. If the record has no UID, one is generated and the encrypted record key is sent to the server. If the record is in a sh
(params, record)
| 673 | |
| 674 | |
| 675 | def prepare_record_v3(params, record): # type: (KeeperParams, Record) -> Optional[Tuple[dict, Optional[bytes]]] |
| 676 | """ Prepares the Record() object to be sent to the Keeper Cloud API |
| 677 | by serializing and encrypting it in the proper JSON format used for |
| 678 | transmission. If the record has no UID, one is generated and the |
| 679 | encrypted record key is sent to the server. If the record is in a |
| 680 | shared folder, must send shared folder UID for edit permission. |
| 681 | """ |
| 682 | if not record.record_uid: |
| 683 | logging.debug('Generated Record UID: %s', record.record_uid) |
| 684 | record.record_uid = generate_record_uid() |
| 685 | |
| 686 | record_object = { |
| 687 | 'record_uid': record.record_uid, |
| 688 | 'client_modified_time': current_milli_time() |
| 689 | } |
| 690 | |
| 691 | audit_data = None |
| 692 | data = '' |
| 693 | if record.record_uid in params.record_cache: |
| 694 | path = resolve_record_write_path(params, record.record_uid) |
| 695 | if path: |
| 696 | record_object.update(path) |
| 697 | else: |
| 698 | share_admins = get_share_admins_for_record(params, record.record_uid) |
| 699 | if not share_admins or params.user not in share_admins: |
| 700 | logging.error('You do not have edit permissions on this record') |
| 701 | return None |
| 702 | record_object['record_uid'] = record.record_uid |
| 703 | |
| 704 | rec = params.record_cache[record.record_uid] |
| 705 | |
| 706 | data = rec['data_unencrypted'].decode('utf-8') if isinstance(rec['data_unencrypted'], bytes) else rec['data_unencrypted'] |
| 707 | try: |
| 708 | if params.enterprise_ec_key: |
| 709 | d = json.loads(data) |
| 710 | rt_name = d.get('type') or '' |
| 711 | fields = itertools.chain(d.get('fields') or [], (d.get('custom') or [])) |
| 712 | url_field = next((u.get('value') for u in fields if u.get('type') == 'url' and u.get('value')), None) |
| 713 | url = '' |
| 714 | if url_field and isinstance(url_field, list): |
| 715 | url = utils.url_strip(url_field[0]) |
| 716 | |
| 717 | adata = { |
| 718 | 'title': d.get('title', ''), |
| 719 | 'record_type': rt_name, |
| 720 | } |
| 721 | if url: |
| 722 | adata['url'] = url # url will only be supplied if there is one on the record |
| 723 | audit_data = crypto.encrypt_ec(json.dumps(adata).encode('utf-8'), params.enterprise_ec_key) |
| 724 | |
| 725 | except Exception as e: |
| 726 | logging.error(bcolors.FAIL + 'Invalid record type! Error: ' + str(e) + bcolors.ENDC) |
| 727 | return None |
| 728 | |
| 729 | data = pad_aes_gcm(data) |
| 730 | |
| 731 | unencrypted_key = rec['record_key_unencrypted'] |
| 732 | record_object['revision'] = rec['revision'] |
no test coverage detected