Exemple #1
0
def _sync_pws(datapath, force, dec_gpg, enc_gpg):
    accounts = get_all_passwords(datapath)

    git = Git(datapath)
    with GitTransaction(git):
        num = 0
        if git.has_origin():
            git.rebase_origin_master()
        for (host, user, path) in accounts.iterate():
            # There are three cases where the file needs to be reencrypted:
            #   1. The force flag is set
            #   2. The file is encrypted to a key that is no longer available,
            #      or expected as a recipient
            #   3. The list of recipients do not match the expected recipient list
            (rec_fps, rec_not_found) = enc_gpg.get_file_recipients(path)
            if force or rec_not_found or sorted(rec_fps) != sorted(
                    enc_gpg.get_recipient_fps()):
                debug('Need to reencrypt {}'.format(path))
                encpw = enc_gpg.encrypt(dec_gpg.decrypt_file(path))
                write_and_add(git, path, encpw, True)
                num += 1

        if num > 0:
            uids = ''.join(
                ['    - {}\n'.format(x) for x in enc_gpg.get_recipient_uids()])
            git.commit(
                "Synchronized and reencrypted {} passwords to {} recipient{}{}\n\n{}\n\n{}"
                .format(num, enc_gpg.get_num_recipients(),
                        's' if enc_gpg.get_num_recipients() > 1 else '',
                        ' (forced)' if force else '', uids, get_version()))
            if git.has_origin():
                git.push_master()
    return num
Exemple #2
0
 def do_rm(pwfile, host, user):
     git = Git(datapath)
     with GitTransaction(git):
         if git.has_origin():
             git.rebase_origin_master()
         git.rm(pwfile)
         git.commit("{}/{}: remove\n\n{}".format(host, user, get_version()))
         if git.has_origin():
             git.push_master()
Exemple #3
0
def do_add(datapath, path, host, user, encpw, exist_ok):
    git = Git(datapath)
    with GitTransaction(git):
        if git.has_origin():
            git.rebase_origin_master()
        write_and_add(git, path, encpw, exist_ok)
        git.commit("{}/{}: {}\n\n{}".format(host, user,
                                            'replace' if exist_ok else 'add',
                                            get_version()))
        if git.has_origin():
            git.push_master()
Exemple #4
0
def init_git(cfg, args):
    datapath = cfg['global']['datapath']
    if os.path.isdir(os.path.join(datapath, ".git")):
        sys.exit(
            '{} is already a git repo! Not reinitializing to avoid losing data.'
            .format(datapath))

    os.makedirs(datapath, exist_ok=True)
    Git.create_repo(datapath, bare=False)
    fn = os.path.join(datapath, '.gitignore')
    with open(fn, 'x') as f:
        f.write('lock\n')
    git = Git(datapath)
    git.add('.gitignore')
    git.commit('Initial')
    print('Password storage git repo initialized in {}'.format(datapath))
Exemple #5
0
    def test_rebase(self):
        new_path = os.path.join(self.tempdir, "new")
        self.git.clone_to(new_path)
        git1 = Git(new_path)
        self.create_file(os.path.join(new_path, "one"))
        git1.add("one")
        git1.commit("message1")
        git1.push_master()
        self.assertTrue(os.path.isfile(os.path.join(new_path, "one")))

        newnew_path = os.path.join(self.tempdir, "newnew")
        self.git.clone_to(newnew_path)
        git2 = Git(newnew_path)
        self.create_file(os.path.join(newnew_path, "two"))
        git2.add("two")
        git2.commit("message2")
        git2.push_master()

        self.assertTrue(os.path.isfile(os.path.join(new_path, "one")))
        self.assertFalse(os.path.isfile(os.path.join(new_path, "two")))
        git1.rebase_origin_master()
        self.assertTrue(os.path.isfile(os.path.join(new_path, "one")))
        self.assertTrue(os.path.isfile(os.path.join(new_path, "two")))
Exemple #6
0
    def test_transaction_fail(self):
        new_path = os.path.join(self.tempdir, "new")
        self.git.clone_to(new_path)
        ngit = Git(new_path, silent=True)

        with self.assertRaises(subprocess.CalledProcessError):
            with GitTransaction(ngit):
                self.create_file(os.path.join(self.clone_path, "one"))
                self.create_file(os.path.join(new_path, "two"))
                self.gitclone.add("one")
                ngit.add("two")
                self.gitclone.commit("message1")
                ngit.commit("message2")

                # gitclone.push_master() should succeed but ngit.push_master() should
                # fail because their histories have diverged. When it fails,
                # the ngit commit should be reset to what it was
                self.assertTrue(
                    os.path.isfile(os.path.join(self.clone_path, "one")))
                self.assertTrue(os.path.isfile(os.path.join(new_path, "two")))
                self.gitclone.push_master()

                self.assertTrue(
                    os.path.isfile(os.path.join(self.clone_path, "one")))
                self.assertTrue(os.path.isfile(os.path.join(new_path, "two")))
                ngit.push_master()

                # This line should never be execued as git2.push_master()
                # should break the with block
                self.assertTrue(False)

        self.assertTrue(os.path.isfile(os.path.join(self.clone_path, "one")))
        self.assertFalse(os.path.isfile(os.path.join(new_path, "two")))

        # There should be no tags left since the transaction was aborted
        self.assertEqual(self.git.run_git(["tag"]), '')
        self.assertEqual(self.gitclone.run_git(["tag"]), '')
Exemple #7
0
class TestGit(unittest.TestCase):
    def setUp(self):
        debug.set_debug(False)
        self.tempdir = tempfile.mkdtemp()
        self.orig_cwd = os.getcwd()
        os.chdir(self.tempdir)
        self.repopath = os.path.join(self.tempdir, "origin")
        Git.create_repo(self.repopath, bare=True)
        self.git = Git(self.repopath)

        self.clone_path = os.path.join(self.tempdir, "clone")
        self.git.clone_to(self.clone_path)
        self.gitclone = Git(self.clone_path)
        self.create_file(os.path.join(self.clone_path, "initial"))
        self.gitclone.add("initial")
        self.gitclone.commit("message")
        self.gitclone.push_master()

    def tearDown(self):
        os.chdir(self.orig_cwd)
        shutil.rmtree(self.tempdir)

    def create_file(self, path):
        with open(path, 'xb') as f:
            f.write(os.urandom(1024))

    def test_get_head(self):
        # get_head() validates the output so we only need to make sure no
        # exception is raised when running it. It would be better to have a git
        # repo with a previously known hash here but that's probably overkill.
        self.git.get_head()

    def test_rebase(self):
        new_path = os.path.join(self.tempdir, "new")
        self.git.clone_to(new_path)
        git1 = Git(new_path)
        self.create_file(os.path.join(new_path, "one"))
        git1.add("one")
        git1.commit("message1")
        git1.push_master()
        self.assertTrue(os.path.isfile(os.path.join(new_path, "one")))

        newnew_path = os.path.join(self.tempdir, "newnew")
        self.git.clone_to(newnew_path)
        git2 = Git(newnew_path)
        self.create_file(os.path.join(newnew_path, "two"))
        git2.add("two")
        git2.commit("message2")
        git2.push_master()

        self.assertTrue(os.path.isfile(os.path.join(new_path, "one")))
        self.assertFalse(os.path.isfile(os.path.join(new_path, "two")))
        git1.rebase_origin_master()
        self.assertTrue(os.path.isfile(os.path.join(new_path, "one")))
        self.assertTrue(os.path.isfile(os.path.join(new_path, "two")))

    def test_transaction_success(self):
        fpath = os.path.join(self.clone_path, "one")
        with GitTransaction(self.gitclone):
            self.create_file(fpath)
            self.gitclone.add("one")
            self.gitclone.commit("message1")
            self.assertTrue(os.path.isfile(fpath))
            self.gitclone.push_master()
        self.assertTrue(os.path.isfile(fpath))

        # There should be no tags left since the transaction was successful
        self.assertEqual(self.git.run_git(["tag"]), '')
        self.assertEqual(self.gitclone.run_git(["tag"]), '')

    def test_transaction_fail(self):
        new_path = os.path.join(self.tempdir, "new")
        self.git.clone_to(new_path)
        ngit = Git(new_path, silent=True)

        with self.assertRaises(subprocess.CalledProcessError):
            with GitTransaction(ngit):
                self.create_file(os.path.join(self.clone_path, "one"))
                self.create_file(os.path.join(new_path, "two"))
                self.gitclone.add("one")
                ngit.add("two")
                self.gitclone.commit("message1")
                ngit.commit("message2")

                # gitclone.push_master() should succeed but ngit.push_master() should
                # fail because their histories have diverged. When it fails,
                # the ngit commit should be reset to what it was
                self.assertTrue(
                    os.path.isfile(os.path.join(self.clone_path, "one")))
                self.assertTrue(os.path.isfile(os.path.join(new_path, "two")))
                self.gitclone.push_master()

                self.assertTrue(
                    os.path.isfile(os.path.join(self.clone_path, "one")))
                self.assertTrue(os.path.isfile(os.path.join(new_path, "two")))
                ngit.push_master()

                # This line should never be execued as git2.push_master()
                # should break the with block
                self.assertTrue(False)

        self.assertTrue(os.path.isfile(os.path.join(self.clone_path, "one")))
        self.assertFalse(os.path.isfile(os.path.join(new_path, "two")))

        # There should be no tags left since the transaction was aborted
        self.assertEqual(self.git.run_git(["tag"]), '')
        self.assertEqual(self.gitclone.run_git(["tag"]), '')

    def test_has_origin(self):
        self.assertFalse(self.git.has_origin())
        self.assertTrue(self.gitclone.has_origin())