def perform_vlob_synchronize(self, intent): if intent.id in self.vlobs: vlob = self.vlobs[intent.id] try: self.vlob_cache[(intent.id, vlob['version'])] = vlob except ValueError: pass # Value too large if cache is disabled new_vlob = None if vlob['version'] == 1: new_vlob = yield Effect(EBackendVlobCreate(vlob['blob'].encode())) new_trust_seed = new_vlob.read_trust_seed try: self.vlob_cache[(intent.id, vlob['version'])]['read_trust_seed'] = new_trust_seed except KeyError: pass else: yield Effect(EBackendVlobUpdate( intent.id, self.vlobs[intent.id]['write_trust_seed'], self.vlobs[intent.id]['version'], vlob['blob'].encode())) # TODO encode is correct? del self.vlobs[intent.id] if new_vlob: return {'id': new_vlob.id, 'read_trust_seed': new_vlob.read_trust_seed, 'write_trust_seed': new_vlob.write_trust_seed} else: return True return False
def perform_user_vlob_update(self, intent): id = yield Effect(EGetAuthenticatedUser()) vlobs = self.vlobs[id] if len(vlobs) != intent.version - 1: raise UserVlobError('Wrong blob version.') vlobs.append( UserVlobAtom(id=id, version=intent.version, blob=intent.blob)) yield Effect(EEvent('user_vlob_updated', id))
def perform_identity_signup(self, intent): private_key = generate_asym_key(intent.key_size) cipherkey = private_key.export(intent.password) pubkey = private_key.pub_key.export() # Saving the cipherkey first prevent us from registering a public key # then crashing without the corresponding private key saved somewhere # TODO: handle compute the hash here instead of in BackendCipherkeyAdd ? yield Effect( EBackendCipherKeyAdd(intent.id, intent.password, cipherkey)) yield Effect(EBackendIdentityRegister(intent.id, pubkey))
def perform_identity_unload(self, intent): from parsec.core.backend import EBackendReset from parsec.core.block import EBlockReset if not self.identity: raise IdentityNotLoadedError('Identity not loaded') # TODO: make block&backend reset event triggered yield Effect(EBlockReset()) yield Effect(EBackendReset()) yield Effect(EEvent('identity_unloaded', None)) self.identity = None
def restore(self, version=None): if version is None: version = self.get_version() - 1 if version < 1 or version >= self.get_version(): raise FileError('bad_version', 'Bad version number.') yield self.discard() vlob = yield Effect(EVlobRead(self.id, self.read_trust_seed, version)) yield Effect(EVlobUpdate(self.id, self.write_trust_seed, self.version + 1, vlob['blob'])) self.dirty = True
def discard(self): already_synchronized = False self.modifications = [] block_ids = yield self.get_blocks() for block_id in block_ids: try: yield Effect(EBlockDelete(block_id)) except BlockNotFound: already_synchronized = True try: yield Effect(EVlobDelete(self.id)) except VlobNotFound: already_synchronized = True self.dirty = False return not already_synchronized
def perform_pubkey_get(intent): msg = {'id': intent.id} ret = yield Effect(BackendCmd('pubkey_get', msg)) status = ret['status'] if status != 'ok': raise exception_from_status(status)(ret['label']) return PubKey(intent.id, from_jsonb64(ret['key']))
def perform_group_read(intent): msg = {'name': intent.name} ret = yield Effect(BackendCmd('group_read', msg)) status = ret['status'] if status != 'ok': raise exception_from_status(status)(ret['label']) return Group(intent.name, ret['admins'], ret['users'])
def perform_vlob_read(self, intent): if (intent.id in self.vlobs and (not intent.version or intent.version == self.vlobs[intent.id]['version'])): # TDOO: remove this mystic 42 if self.vlobs[intent.id]['read_trust_seed'] == '42': self.vlobs[intent.id]['read_trust_seed'] = intent.trust_seed assert intent.trust_seed == self.vlobs[intent.id]['read_trust_seed'] return {'id': intent.id, 'blob': self.vlobs[intent.id]['blob'], 'version': self.vlobs[intent.id]['version']} else: if intent.version is not None: try: cached_vlob = self.vlob_cache[(intent.id, intent.version)] assert intent.trust_seed == cached_vlob['read_trust_seed'] vlob = {'id': intent.id, 'blob': cached_vlob['blob'], 'version': intent.version} return vlob except KeyError: pass # cache miss vlob = yield Effect(EBackendVlobRead(intent.id, intent.trust_seed, intent.version)) vlob = {'id': vlob.id, 'blob': vlob.blob.decode(), 'version': vlob.version} try: cached_vlob = {'id': intent.id, 'read_trust_seed': intent.trust_seed, 'version': intent.version, 'blob': vlob['blob']} self.vlob_cache[(intent.id, intent.version)] = cached_vlob except ValueError: pass # Value too large if cache is disabled return vlob
def stat(self): version = self.get_version() vlob = yield Effect(EVlobRead(self.id, self.read_trust_seed, version)) encrypted_blob = vlob['blob'] encrypted_blob = from_jsonb64(encrypted_blob) blob = self.encryptor.decrypt(encrypted_blob) blob = ejson_loads(blob.decode()) size = 0 for blocks_and_key in blob: for block in blocks_and_key['blocks']: size += block['size'] for modification in self.modifications: if modification[0] == self.write: end_offset = modification[2] + len(modification[1]) if size < end_offset: size = end_offset elif modification[0] == self.truncate: if size > modification[1]: size = modification[1] else: raise NotImplementedError() # TODO don't provide atime field if we don't know it? # TODO real date return { 'id': self.id, 'type': 'file', 'created': '2012-01-01T00:00:00', 'updated': '2012-01-01T00:00:00', 'size': size, 'version': vlob['version'] }
def api_identity_info(msg): UnknownCheckedSchema().load(msg) try: identity = yield Effect(EIdentityGet()) return {'status': 'ok', 'loaded': True, 'id': identity.id} except IdentityNotLoadedError: return {'status': 'ok', 'loaded': False, 'id': None}
async def periodic_synchronization(self, app): # TODO: find a better way to do this than using asyncio_perform... while True: await asyncio.sleep(self.synchronization_idle_interval) if (arrow.utcnow().timestamp - self.last_modified.timestamp > self.synchronization_idle_interval): await asyncio_perform( app.components.get_dispatcher(), Effect(fs.ESynchronize()))
def api_user_vlob_read(msg): msg = cmd_READ_Schema().load(msg) atom = yield Effect(EUserVlobRead(**msg)) return { 'status': 'ok', 'blob': to_jsonb64(atom.blob), 'version': atom.version }
def commit(self): yield self.flush() block_ids = yield self.get_blocks() for block_id in block_ids: yield Effect(EBlockSynchronize(block_id)) new_vlob = yield Effect(EVlobSynchronize(self.id)) if new_vlob: if new_vlob is not True: del File.files[self.id] 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() File.files[self.id] = self self.version += 1 self.dirty = False return new_vlob
def reencrypt(self): yield self.flush() version = self.get_version() old_vlob = yield Effect(EVlobRead(self.id, self.read_trust_seed, version)) old_blob = old_vlob['blob'] old_encrypted_blob = from_jsonb64(old_blob) new_blob = self.encryptor.decrypt(old_encrypted_blob) self.encryptor = generate_sym_key() new_encrypted_blob = self.encryptor.encrypt(new_blob) new_encrypted_blob = to_jsonb64(new_encrypted_blob) new_vlob = yield Effect(EVlobCreate(new_encrypted_blob)) del File.files[self.id] self.id = new_vlob['id'] self.read_trust_seed = new_vlob['read_trust_seed'] self.write_trust_seed = new_vlob['write_trust_seed'] File.files[self.id] = self self.dirty = True
def perform_user_vlob_read(intent): msg = {} if intent.version is not None: msg['version'] = intent.version ret = yield Effect(BackendCmd('user_vlob_read', msg)) status = ret['status'] if status != 'ok': raise exception_from_status(status)(ret['label']) return UserVlobAtom(ret['version'], from_jsonb64(ret['blob']))
def api_group_read(msg): msg = cmd_READ_Schema().load(msg) group = yield Effect(EGroupRead(**msg)) return { 'status': 'ok', 'name': group.name, 'admins': list(group.admins), 'users': list(group.users) }
def load(cls, id, key, read_trust_seed, write_trust_seed, version=None): if id in File.files: return File.files[id] self = File() self.id = id self.read_trust_seed = read_trust_seed self.write_trust_seed = write_trust_seed self.encryptor = load_sym_key(from_jsonb64(key)) vlob = yield Effect(EVlobRead(self.id, self.read_trust_seed, version)) self.version = vlob['version'] self.dirty = False vlob_list = yield Effect(EVlobList()) if vlob['id'] in vlob_list: self.dirty = True self.version -= 1 self.modifications = [] File.files[self.id] = self return self