def reencrypt(self): # Reencrypt files for path, entry in self.entries.items(): if entry: file = yield File.load(**entry) yield file.reencrypt() new_vlob = file.get_vlob() self.entries[path] = new_vlob for index, entry in enumerate(self.dustbin): entry = deepcopy(entry) path = entry['path'] removed_date = entry['removed_date'] for key in ['path', 'removed_date']: del entry[key] file = yield File.load(**entry) yield file.reencrypt() new_vlob = file.get_vlob() new_vlob['path'] = path new_vlob['removed_date'] = removed_date self.dustbin[index] = new_vlob # Reencrypt manifest blob = yield self.dumps() self.encryptor = generate_sym_key() encrypted_blob = self.encryptor.encrypt(blob.encode()) encrypted_blob = to_jsonb64(encrypted_blob) new_vlob = yield Effect(EVlobCreate(encrypted_blob)) self.id = new_vlob['id'] self.read_trust_seed = new_vlob['read_trust_seed'] self.write_trust_seed = new_vlob['write_trust_seed'] self.version = 0
def test_load_file(self, file): vlob_id = '1234' other_vlob_id = '5678' read_trust_seed = '42' version = 1 # Load from open files file2 = perform_sequence( [], File.load(vlob_id, to_jsonb64(b'<dummy-key-00000000000000000001>'), read_trust_seed, '43')) assert file == file2 File.files = {} # Test reloading commited and not commited file for synchronizer_vlob_list in [[vlob_id, other_vlob_id], [other_vlob_id]]: key = to_jsonb64(b'<dummy-key-00000000000000000001>') sequence = [ (EVlobRead(vlob_id, read_trust_seed, None), const({ 'id': vlob_id, 'blob': 'foo', 'version': version })), (EVlobList(), const(synchronizer_vlob_list)), ] file = perform_sequence( sequence, File.load(vlob_id, key, read_trust_seed, '43')) assert file.dirty is (vlob_id in synchronizer_vlob_list) assert file.version == (version - 1 if file.dirty else version) File.files = {}
def commit(self, recursive=True): is_dirty = yield self.is_dirty() if self.version != 0 and not is_dirty: return # Update manifest with new group vlobs vlob_list = yield Effect(EVlobList()) if recursive: for group_manifest in self.group_manifests.values(): new_vlob = yield group_manifest.commit() if new_vlob and new_vlob is not True: old_vlob = group_manifest.get_vlob() new_vlob['key'] = old_vlob['key'] group_manifest.update_vlob(new_vlob) # Update manifest entries with new file vlobs (dustbin entries are already commited) for entry in self.entries.values(): if entry and entry['id'] in vlob_list: file = yield File.load(entry['id'], entry['key'], entry['read_trust_seed'], entry['write_trust_seed']) new_vlob = yield file.commit() if new_vlob and new_vlob is not True: entry['id'] = new_vlob['id'] entry['read_trust_seed'] = new_vlob['read_trust_seed'] entry['write_trust_seed'] = new_vlob['write_trust_seed'] # Commit manifest blob = yield self.dumps() encrypted_blob = self.encryptor.pub_key.encrypt(blob.encode()) encrypted_blob = to_jsonb64(encrypted_blob) yield Effect(EUserVlobUpdate(self.version + 1, encrypted_blob)) self.original_manifest = ejson_loads(blob) synchronized = yield Effect(EUserVlobSynchronize()) if synchronized: self.version += 1
def commit(self): is_dirty = yield self.is_dirty() if self.version != 0 and not is_dirty: return # Update manifest entries with new file vlobs (dustbin entries are already commited) vlob_list = yield Effect(EVlobList()) for entry in self.entries.values(): if entry and entry['id'] in vlob_list: file = yield File.load(entry['id'], entry['key'], entry['read_trust_seed'], entry['write_trust_seed']) new_vlob = yield file.commit() if new_vlob and new_vlob is not True: entry['id'] = new_vlob['id'] entry['read_trust_seed'] = new_vlob['read_trust_seed'] entry['write_trust_seed'] = new_vlob['write_trust_seed'] # Commit manifest blob = yield self.dumps() encrypted_blob = self.encryptor.encrypt(blob.encode()) encrypted_blob = to_jsonb64(encrypted_blob) yield Effect(EVlobUpdate(self.id, self.write_trust_seed, self.version + 1, encrypted_blob)) self.original_manifest = ejson_loads(blob) new_vlob = yield Effect(EVlobSynchronize(self.id)) if new_vlob: if new_vlob is not True: self.id = new_vlob['id'] self.read_trust_seed = new_vlob['read_trust_seed'] self.write_trust_seed = new_vlob['write_trust_seed'] new_vlob = self.get_vlob() self.version += 1 return new_vlob
def reencrypt_file(self, path): path = '/' + path.strip('/') try: entry = self.entries[path] except KeyError: raise ManifestNotFound('File not found.') file = yield File.load(**entry) yield file.reencrypt() self.entries[path] = file.get_vlob()
def perform_file_create(self, intent): file = yield File.create() vlob = file.get_vlob() user_manifest = yield self._get_manifest() try: user_manifest.add_file(intent.path, vlob) except (ManifestError, ManifestNotFound) as ex: yield file.discard() raise ex
def reload(self, reset=False): vlob = yield Effect(EUserVlobRead()) if not vlob['blob']: raise ManifestNotFound('User manifest not found.') blob = from_jsonb64(vlob['blob']) content = self.encryptor.decrypt(blob) if not reset and vlob['version'] <= self.version: return new_manifest = ejson_loads(content.decode()) backup_new_manifest = deepcopy(new_manifest) consistency = yield self.check_consistency(new_manifest) if not consistency: raise ManifestError('not_consistent', 'User manifest not consistent.') if not reset: diff = yield self.diff_versions() new_manifest = self.patch(new_manifest, diff) self.entries = new_manifest['entries'] self.dustbin = new_manifest['dustbin'] self.version = vlob['version'] self.group_manifests = {} for group, group_vlob in new_manifest['groups'].items(): self.import_group_vlob(group, group_vlob) self.original_manifest = backup_new_manifest versions = new_manifest['versions'] file_vlob = None for vlob_id, version in sorted(versions.items()): for entry in self.entries.values(): if entry and entry['id'] == vlob_id: file_vlob = entry break if not file_vlob: for entry in self.dustbin: if entry['id'] == vlob_id: file_vlob = {'id': entry['id'], 'read_trust_seed': entry['read_trust_seed'], 'write_trust_seed': entry['write_trust_seed'], 'key': entry['key']} break if file_vlob: file_vlob = None file = yield File.load(entry['id'], entry['key'], entry['read_trust_seed'], entry['write_trust_seed']) try: yield file.restore(version) except FileError: pass
def _get_file(self, path, group=None): try: properties = yield self._get_properties(path=path, group=group) except FileNotFound: try: properties = yield self._get_properties(path=path, dustbin=True, group=group) except FileNotFound: raise FileNotFound('Vlob not found.') if not properties: raise FileNotFound('Vlob not found.') file = yield File.load(properties['id'], properties['key'], properties['read_trust_seed'], properties['write_trust_seed']) return file
def reload(self, reset=False): # Subscribe to events # yield Effect(EConnectEvent('on_vlob_updated', self.id, self.handler)) # TODO call vlob = yield Effect(EVlobRead(self.id, self.read_trust_seed)) blob = from_jsonb64(vlob['blob']) content = self.encryptor.decrypt(blob) if not reset and vlob['version'] <= self.version: return new_manifest = ejson_loads(content.decode()) backup_new_manifest = deepcopy(new_manifest) consistency = yield self.check_consistency(new_manifest) if not consistency: raise ManifestError('not_consistent', 'Group manifest not consistent.') if not reset: diff = yield self.diff_versions() new_manifest = self.patch(new_manifest, diff) self.entries = new_manifest['entries'] self.dustbin = new_manifest['dustbin'] self.version = vlob['version'] self.original_manifest = backup_new_manifest versions = new_manifest['versions'] file_vlob = None for vlob_id, version in sorted(versions.items()): for entry in self.entries.values(): if entry and entry['id'] == vlob_id: file_vlob = entry break if not file_vlob: for entry in self.dustbin: if entry['id'] == vlob_id: file_vlob = {'id': entry['id'], 'read_trust_seed': entry['read_trust_seed'], 'write_trust_seed': entry['write_trust_seed'], 'key': entry['key']} break if file_vlob: file_vlob = None file = yield File.load(entry['id'], entry['key'], entry['read_trust_seed'], entry['write_trust_seed']) try: yield file.restore(version) except FileError: pass
def stat(self, path): path = '/' + path.strip('/') if path != '/' and path not in self.entries: raise ManifestNotFound('Folder or file not found.') entry = self.entries[path] if entry: file = yield File.load(**entry) stat = yield file.stat() return stat else: # Skip mtime and size given that they are too complicated to provide for folder # TODO time except mtime children = {} for entry in self.entries: if (entry != path and entry.startswith(path) and entry.count('/', len(path) + 1) == 0): children[os.path.basename(entry)] = deepcopy(self.entries[entry]) return { 'type': 'folder', 'children': sorted(list(children.keys())) }
def delete(self, path): path = '/' + path.strip('/') deleted_paths = [] for entry in self.entries: if entry == path or entry.startswith(path + '/') or path == '/': deleted_paths.append(entry) for path in deleted_paths: entry = self.entries[path] if entry: file = yield File.load(entry['id'], entry['key'], entry['read_trust_seed'], entry['write_trust_seed']) discarded = yield file.discard() # TODO discard or not? if not discarded: dustbin_entry = {'removed_date': datetime.utcnow().isoformat(), 'path': path} dustbin_entry.update(entry) self.dustbin.append(dustbin_entry) if path != '/': del self.entries[path] if not deleted_paths: raise ManifestNotFound('File or directory not found.')
def file(mock_crypto_passthrough): block_id = '4567' blob = [{ 'blocks': [{ 'block': block_id, 'digest': digest(b''), 'size': 0 }], 'key': to_jsonb64(b'<dummy-key-00000000000000000001>') }] blob = ejson_dumps(blob).encode() blob = to_jsonb64(blob) sequence = [ (EBlockCreate(''), const(block_id)), (EVlobCreate(blob), const({ 'id': '1234', 'read_trust_seed': '42', 'write_trust_seed': '43' })), ] return perform_sequence(sequence, File.create())