示例#1
0
 async def reset(self, vault: Vault):
     with store.session() as session:
         session.add(vault)
         vault.revision_count = 0
         vault.file_count = 0
         vault.user_count = 0
         session.commit()
示例#2
0
文件: vault.py 项目: syncrypt/client
 async def reset(self, vault: Vault):
     with store.session() as session:
         session.add(vault)
         vault.revision_count = 0
         vault.file_count = 0
         vault.user_count = 0
         session.commit()
示例#3
0
    async def clone(self, vault_id, local_directory, async_init: bool = False):
        backend = await self.open_backend()

        logger.info('Retrieving encrypted key for vault %s (Fingerprint: %s)',
                vault_id, format_fingerprint(self.identity.get_fingerprint()))
        auth_token, package_info = await \
                backend.get_user_vault_key(self.identity.get_fingerprint(), vault_id)

        # decrypt package
        export_pipe = Once(package_info) \
            >> DecryptRSA_PKCS1_OAEP(self.identity.private_key)

        decrypted_package_info = await export_pipe.readall()

        original_vault = self.get_vault_by_path(local_directory)
        if original_vault:
            if original_vault.config.id == vault_id:
                logger.warning('Same vault already exists in the given location, continuing...')
                vault = original_vault
            else:
                raise VaultAlreadyExists(original_vault.folder)
        else:
            # There is no vault present, but we want to make sure that this folder is nonexistent or
            # empty:
            if os.path.exists(local_directory) and not is_empty(local_directory):
                raise FolderExistsAndIsNotEmpty(local_directory)

            vault = Vault.from_package_info(decrypted_package_info, local_directory, auth_token)

        if not async_init:
            await self.pull_vault(vault, full=True)

        await self.add_vault(vault, async_init=async_init)

        return vault
示例#4
0
    async def post_obj(self, request):
        async def pull_and_watch(vault):
            await self.app.pull_vault(vault)
            # TODO No wait here!
            #await self.app.watch(vault)

        async def init_and_push(vault):
            await self.app.open_or_init(vault)
            await self.app.pull_vault(vault)
            await self.app.push_vault(vault)

        content = await request.content.read()
        request_dict = json.loads(content.decode())

        if not 'folder' in request_dict or not request_dict['folder']:
            raise ValueError("Invalid value for parameter: 'folder'")

        if 'id' in request_dict:
            vault = await self.app.clone(request_dict['id'],
                                         request_dict['folder'],
                                         async_init=True)
        elif 'import_package' in request_dict:
            raise NotImplementedError()
            #vault = await self.app.import_package(
            #        request_dict['import_package'], request_dict['folder'])
            #self.app.save_vault_dir_in_config(vault)
            #asyncio.get_event_loop().create_task(pull_and_watch(vault))
        else:
            vault = await self.app.add_vault(Vault(request_dict['folder']),
                                             async_init=True,
                                             async_push=True)
        return vault
示例#5
0
async def empty_vault(working_dir):
    "Return an uninitialized, empty vault"

    vault_folder = os.path.join(working_dir, "testvault")
    if os.path.exists(vault_folder):
        shutil.rmtree(vault_folder)
    os.makedirs(vault_folder)
    return Vault(vault_folder)
示例#6
0
async def test_vault(working_dir):
    "Return a vault that is a clone of the test vault"

    source_folder = os.path.join('tests', 'testlocalvault/')
    vault_folder = os.path.join(working_dir, "testvault")
    if os.path.exists(vault_folder):
        shutil.rmtree(vault_folder)
    shutil.copytree(source_folder, vault_folder)
    return Vault(vault_folder)
示例#7
0
async def test_remove_file(local_app, local_vault, working_dir):
    other_vault_path = os.path.join(working_dir, "othervault")

    # remove "other vault" folder first
    if os.path.exists(other_vault_path):
        shutil.rmtree(other_vault_path)

    app = local_app
    await app.initialize()
    await app.open_or_init(local_vault)
    await app.push()  # init all vaults

    pre_rev = local_vault.revision
    await app.remove_file(local_vault,
                          os.path.join(local_vault.folder, "hello.txt"))
    assert pre_rev != local_vault.revision
    await app.remove_file(local_vault,
                          os.path.join(local_vault.folder, "random250k"))
    assert pre_rev != local_vault.revision

    # now we will clone the initialized vault by copying the vault config
    shutil.copytree(
        os.path.join(local_vault.folder, ".vault"),
        os.path.join(other_vault_path, ".vault"),
    )
    other_vault = Vault(other_vault_path)
    with other_vault.config.update_context():
        other_vault.config.unset("vault.revision")

    await app.open_or_init(other_vault)
    await app.add_vault(other_vault)

    await app.pull_vault(other_vault)

    files_in_new_vault = len(glob(os.path.join(other_vault_path, "*")))
    assert files_in_new_vault == 6
    assertSameFilesInFolder(local_vault.folder, other_vault_path)

    keys = UserVaultKeyManager(app)
    # We have one valid key for both vaults
    assert len(keys.list_for_vault(other_vault)) == 1
    assert len(keys.list_for_vault(local_vault)) == 1

    key = keys.list_for_vault(local_vault)[0]
    other_key = keys.list_for_vault(other_vault)[0]

    assert key.fingerprint == other_key.fingerprint
    assert key.fingerprint != local_vault.identity.get_fingerprint()
    assert key.fingerprint == app.identity.get_fingerprint()
示例#8
0
async def test_local_metadata(local_app, local_vault, working_dir):
    other_vault_path = os.path.join(working_dir, "othervault")

    # remove "other vault" folder first
    if os.path.exists(other_vault_path):
        shutil.rmtree(other_vault_path)

    app = local_app
    await app.initialize()
    await app.open_or_init(local_vault)
    await trio.sleep(1)
    assert local_vault.revision_count == 3

    # now we will clone the initialized vault by copying the vault config
    shutil.copytree(
        os.path.join(local_vault.folder, ".vault"),
        os.path.join(other_vault_path, ".vault"),
    )
    other_vault = Vault(other_vault_path)
    with other_vault.config.update_context():
        other_vault.config.unset("vault.revision")

    await app.open_or_init(other_vault)
    await app.add_vault(other_vault)

    await app.pull_vault(other_vault)
    assert other_vault.revision_count == 3

    files_in_new_vault = len(glob(os.path.join(other_vault_path, "*")))
    assert files_in_new_vault == 0

    # Now we change the name of the original vault
    with local_vault.config.update_context():
        other_vault.config.set("vault.name", "abc")

    # Upload metadata with the new name to the server
    revision = await local_vault.backend.set_vault_metadata(app.identity)
    await app.revisions.apply(revision, local_vault)

    original_count = other_vault.revision_count

    # Pull the new vault again to retrieve the change in metadata
    await app.pull_vault(other_vault)

    assert other_vault.revision_count == original_count + 1

    assert local_vault.config.get("vault.name") == other_vault.config.get(
        "vault.name")
示例#9
0
    async def import_package(self, filename, target_folder, pull_vault=False):

        if os.path.exists(target_folder) and not is_empty(target_folder):
            raise FolderExistsAndIsNotEmpty(target_folder)

        with ZipFile(filename, 'r') as myzip:
            myzip.extractall(target_folder)

        logger.info('Importing vault into "%s"', target_folder)

        vault = Vault(target_folder)
        if not vault.config.id:
            raise InvalidVaultPackage()

        await self.open_or_init(vault)

        if pull_vault:
            await self.pull_vault(vault)
        return vault
示例#10
0
    async def initialize(self):
        await self.identity.init()

        if self.vault_dirs is None:
            self.vault_dirs = self.config.vault_dirs

        # Load cached vault information from config file
        config_vaults = []
        with store.session() as session:
            for vault_dir in self.vault_dirs:
                abs_vault_dir = os.path.normpath(os.path.abspath(vault_dir))
                try:
                    vault = session.query(Vault).filter(Vault.folder==abs_vault_dir).one()
                except NoResultFound:
                    vault = Vault(abs_vault_dir)
                    session.add(vault)
                config_vaults.append(vault)

        for vault in config_vaults:
            await self.start_vault(vault)
示例#11
0
    async def clone_local(self, clone_target):
        import shutil
        import os

        vault = self.vaults[0]

        await self.push()

        if not os.path.exists(clone_target):
            os.makedirs(clone_target)

        vault_cfg = os.path.join(clone_target, '.vault')
        if not os.path.exists(vault_cfg):
            os.makedirs(vault_cfg)

        for f in ('config', 'id_rsa', 'id_rsa.pub'):
            shutil.copyfile(os.path.join(vault.folder, '.vault', f), os.path.join(vault_cfg, f))

        logger.info("Cloned %s to %s" % (vault.folder, os.path.abspath(clone_target)))

        await self.add_vault(Vault(clone_target))

        await self.pull()
示例#12
0
    async def clone(self, vault_id, local_directory):
        backend = await self.open_backend()

        logger.info('Retrieving encrypted key for vault %s (Fingerprint: %s)',
                vault_id, format_fingerprint(self.identity.get_fingerprint()))
        auth_token, package_info = await \
                backend.get_user_vault_key(self.identity.get_fingerprint(), vault_id)

        await backend.close()

        # decrypt package
        export_pipe = Once(package_info) \
            >> DecryptRSA_PKCS1_OAEP(self.identity.private_key)

        decrypted_package_info = await export_pipe.readall()

        original_vault = self.get_vault_by_path(local_directory)
        if original_vault:
            if original_vault.config.id == vault_id:
                logger.warning('Same vault already exists in the given location, continuing...')
                vault = original_vault
            else:
                raise VaultAlreadyExists(original_vault.folder)
        else:
            # There is no vault present, but we want to make sure that this folder is nonexistent or
            # empty:
            if os.path.exists(local_directory) and not is_empty(local_directory):
                raise FolderExistsAndIsNotEmpty(local_directory)

            vault = Vault.from_package_info(decrypted_package_info, local_directory, auth_token)

        await self.add_vault(vault)

        await self.pull_vault(vault, full=True)

        return vault
示例#13
0
 def get_vault_by_path(self, path):
     vault = Vault(path)
     if os.path.exists(vault.config_path):
         return vault
     return None
示例#14
0
    async def apply(self, revision: Revision, vault: Vault):
        if inspect(vault).session:
            raise ValueError('Vault object is bound to a session')

        revision.assert_valid()

        # 1. Check preconditions for this to be a valid revision (current revision must be parent)
        if vault.revision != revision.parent_id:
            raise UnexpectedParentInRevision("Expected parent to be {0}, but is {1}"\
                    .format(revision.parent_id, vault.revision))

        smokesignal.emit('pre_apply_revision', vault=vault, revision=revision)

        with store.session() as session:
            # 2. Check if signing user's key is in the user vault key list
            if revision.operation != RevisionOp.CreateVault:
                signer_key = self.app.user_vault_keys.find_key(
                    vault, revision.user_fingerprint)
                if not signer_key:
                    raise InvalidRevision(
                        "Key {0} is not allowed to generate revisions for vault {1}"
                        .format(revision.user_fingerprint, vault))
            else:
                # CreateVault is the only operation that is allowed to provide its own key
                signer_key = UserVaultKey(
                    vault_id=vault.id,
                    user_id=revision.user_id,
                    fingerprint=revision.user_fingerprint,
                    public_key=revision.user_public_key,
                )

            # 3. Verify revision signature
            revision.verify(signer_key.get_identity(self.app.config))

            # 4. Based on the revision type, perform an action to our state of the vault
            logger.debug(
                "Applying %s (%s) to %s",
                revision.operation,
                revision.revision_id,
                vault.id,
            )

            if revision.operation == RevisionOp.CreateVault:
                session.add(vault)
                session.add(signer_key)
                session.add(
                    VaultUser(vault_id=vault.id, user_id=revision.user_id))
                session.commit()
            elif revision.operation == RevisionOp.Upload:
                try:
                    bundle = await self.app.bundles.get_bundle_by_hash(
                        vault, revision.file_hash)
                    session.delete(bundle)
                except FileNotFoundError:
                    pass
                bundle = await self.create_bundle_from_revision(
                    revision, vault)
                session.add(bundle)
                session.commit()
                revision.path = bundle.relpath
            elif revision.operation == RevisionOp.SetMetadata:
                await vault.write_encrypted_metadata(
                    Once(revision.revision_metadata))
            elif revision.operation == RevisionOp.RemoveFile:
                bundle = await self.app.bundles.get_bundle_by_hash(
                    vault, revision.file_hash)
                session.delete(bundle)
                session.commit()
                revision.path = bundle.relpath
            elif revision.operation == RevisionOp.AddUser:
                self.app.vault_users.add(vault, revision.user_id)
            elif revision.operation == RevisionOp.RemoveUser:
                self.app.vault_users.remove(vault, revision.user_id)
            elif revision.operation == RevisionOp.AddUserKey:
                new_identity = Identity.from_key(revision.user_public_key,
                                                 self.app.config)
                self.app.user_vault_keys.add(vault, revision.user_id,
                                             new_identity)
            elif revision.operation == RevisionOp.RemoveUserKey:
                new_identity = Identity.from_key(revision.user_public_key,
                                                 self.app.config)
                self.app.user_vault_keys.remove(vault, revision.user_id,
                                                new_identity)
            else:
                raise NotImplementedError(revision.operation)

            # 5. Store the revision in config and db
            revision.local_vault_id = vault.id
            revision.creator_id = signer_key.user_id
            session.add(revision)
            session.commit()
            vault.revision_count = (session.query(Revision).filter(
                Revision.local_vault_id == vault.id).count())
            if revision.operation in (RevisionOp.Upload,
                                      RevisionOp.RemoveFile):
                vault.file_count = (session.query(Bundle).filter(
                    Bundle.vault_id == vault.id).count())
            if revision.operation in (RevisionOp.CreateVault,
                                      RevisionOp.AddUser,
                                      RevisionOp.RemoveUser):
                vault.user_count = (session.query(VaultUser).filter(
                    VaultUser.vault_id == vault.id).count())
            vault.modification_date = revision.created_at
            logger.debug(
                "Vault state revision_count=%s file_count=%s user_count=%s",
                vault.revision_count, vault.file_count, vault.user_count)
            # vault.revision = revision.id
            session.add(vault)
            vault.update_revision(revision)
            session.commit()

        smokesignal.emit('post_apply_revision', vault=vault, revision=revision)
示例#15
0
    async def apply(self, revision: Revision, vault: Vault):
        if inspect(vault).session:
            raise ValueError('Vault object is bound to a session')

        revision.assert_valid()

        # 1. Check preconditions for this to be a valid revision (current revision must be parent)
        if vault.revision != revision.parent_id:
            raise UnexpectedParentInRevision("Expected parent to be {0}, but is {1}"\
                    .format(revision.parent_id, vault.revision))

        smokesignal.emit('pre_apply_revision', vault=vault, revision=revision)

        with store.session() as session:
            # 2. Check if signing user's key is in the user vault key list
            if revision.operation != RevisionOp.CreateVault:
                signer_key = self.app.user_vault_keys.find_key(
                    vault, revision.user_fingerprint
                )
                if not signer_key:
                    raise InvalidRevision(
                        "Key {0} is not allowed to generate revisions for vault {1}"
                            .format(revision.user_fingerprint, vault)
                    )
            else:
                # CreateVault is the only operation that is allowed to provide its own key
                signer_key = UserVaultKey(
                    vault_id=vault.id,
                    user_id=revision.user_id,
                    fingerprint=revision.user_fingerprint,
                    public_key=revision.user_public_key,
                )

            # 3. Verify revision signature
            revision.verify(signer_key.get_identity(self.app.config))

            # 4. Based on the revision type, perform an action to our state of the vault
            logger.debug(
                "Applying %s (%s) to %s",
                revision.operation,
                revision.revision_id,
                vault.id,
            )

            if revision.operation == RevisionOp.CreateVault:
                session.add(vault)
                session.add(signer_key)
                session.add(VaultUser(vault_id=vault.id, user_id=revision.user_id))
                session.commit()
            elif revision.operation == RevisionOp.Upload:
                try:
                    bundle = await self.app.bundles.get_bundle_by_hash(vault, revision.file_hash)
                    session.delete(bundle)
                except FileNotFoundError:
                    pass
                bundle = await self.create_bundle_from_revision(revision, vault)
                session.add(bundle)
                session.commit()
                revision.path = bundle.relpath
            elif revision.operation == RevisionOp.SetMetadata:
                await vault.write_encrypted_metadata(Once(revision.revision_metadata))
            elif revision.operation == RevisionOp.RemoveFile:
                bundle = await self.app.bundles.get_bundle_by_hash(vault, revision.file_hash)
                session.delete(bundle)
                session.commit()
                revision.path = bundle.relpath
            elif revision.operation == RevisionOp.AddUser:
                self.app.vault_users.add(vault, revision.user_id)
            elif revision.operation == RevisionOp.RemoveUser:
                self.app.vault_users.remove(vault, revision.user_id)
            elif revision.operation == RevisionOp.AddUserKey:
                new_identity = Identity.from_key(revision.user_public_key, self.app.config)
                self.app.user_vault_keys.add(vault, revision.user_id, new_identity)
            elif revision.operation == RevisionOp.RemoveUserKey:
                new_identity = Identity.from_key(revision.user_public_key, self.app.config)
                self.app.user_vault_keys.remove(vault, revision.user_id, new_identity)
            else:
                raise NotImplementedError(revision.operation)

            # 5. Store the revision in config and db
            revision.local_vault_id = vault.id
            revision.creator_id = signer_key.user_id
            session.add(revision)
            session.commit()
            vault.revision_count = (
                session.query(Revision)
                .filter(Revision.local_vault_id == vault.id)
                .count()
            )
            if revision.operation in (RevisionOp.Upload, RevisionOp.RemoveFile):
                vault.file_count = (
                    session.query(Bundle)
                    .filter(Bundle.vault_id == vault.id)
                    .count()
                )
            if revision.operation in (RevisionOp.CreateVault, RevisionOp.AddUser, RevisionOp.RemoveUser):
                vault.user_count = (
                    session.query(VaultUser)
                    .filter(VaultUser.vault_id == vault.id)
                    .count()
                )
            vault.modification_date = revision.created_at
            logger.debug("Vault state revision_count=%s file_count=%s user_count=%s",
                    vault.revision_count, vault.file_count, vault.user_count)
            # vault.revision = revision.id
            session.add(vault)
            vault.update_revision(revision)
            session.commit()

        smokesignal.emit('post_apply_revision', vault=vault, revision=revision)
示例#16
0
async def test_non_existent_vault(local_app):
    app = local_app
    await app.add_vault(Vault('non-existent'))
    assert len(app.vaults) == 1
    assert app.vaults[0].state == VaultState.FAILURE