예제 #1
0
def encrypt(request):
    """
        Encrypt all files and write lock encryption file
    """
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = PasswordForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            mypasskeeper = Passkeeper(directory=settings.PASSKEEPER_PATH)
            mypasskeeper.encrypt(
                                 commit_message="Update encrypted files through \
frontkeeper",
                                 passphrase=form.cleaned_data['password'])
            mypasskeeper.cleanup_ini(force_remove=True)
            f = open(settings.PASSKEEPER_ENCRYPT_STATE_FILE, 'w+')
            f.write("")
            f.close()

    # if a GET (or any other method) we'll create a blank form
    else:
        form = PasswordForm()

    if os.path.exists(settings.PASSKEEPER_ENCRYPT_STATE_FILE):
        state = 'Encrypted /!\/!\/!\ It\'s already encrypted /!\/!\/!\ '
        return render(request, 'encrypt-disabled.html',
                      context={'form': form, 'state': state})
    else:
        state = 'Decrypted, you can encrypt'
    return render(request, 'encrypt.html',
                  context={'form': form, 'state': state})
예제 #2
0
def search(request):
    """
        Display the search form to find a patern in ini file
    """
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = SearchForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            # ...
            # redirect to a new URL:
            mypasskeeper = Passkeeper(directory=settings.PASSKEEPER_PATH)
            (config, match) = mypasskeeper.search(
                              pattern=form.cleaned_data['search'])
            matching = {}
            for section in match:
                matching[section] = config.items(section)
            return render(request, 'result.html',
                          context=({'matching': matching}))

    # if a GET (or any other method) we'll create a blank form
    else:
        form = SearchForm()
    if os.path.exists(settings.PASSKEEPER_ENCRYPT_STATE_FILE):
        state = 'Encrypted /!\/!\/!\ Decrypt first to be able to make \
search /!\/!\/!\ '
        return render(request, 'search-disabled.html',
                      context={'form': form, 'state': state})
    else:
        state = 'Decrypted, Make your search'

    return render(request, 'search.html',
                  context={'form': form, 'state': state})
예제 #3
0
def decrypt(request):
    """
        Display the formular to decrypt passkeeper files
        Remove encryption lock file
    """
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = PasswordForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            mypasskeeper = Passkeeper(directory=settings.PASSKEEPER_PATH)
            decryption = mypasskeeper.decrypt(
                         passphrase=form.cleaned_data['password'])
            if decryption:
                os.remove(settings.PASSKEEPER_ENCRYPT_STATE_FILE)

    # if a GET (or any other method) we'll create a blank form
    else:
        form = PasswordForm()

    if os.path.exists(settings.PASSKEEPER_ENCRYPT_STATE_FILE):
        state = 'Encrypted, you can decrypt'
    else:
        state = 'Decrypted /!\/!\/!\ No need to do it again /!\/!\/!\ '
        return render(request, 'decrypt-disabled.html',
                      context={'form': form, 'state': state})
    return render(request, 'decrypt.html',
                  context={'form': form, 'state': state})
예제 #4
0
def init(request):
    """ 
        Display the init form
        Init the passkeeper git and add default ini / raw files
    """
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = PasswordForm(request.POST)
        if form.is_valid():
            init_logger()
            mypasskeeper = Passkeeper(directory=settings.PASSKEEPER_PATH)
            mypasskeeper.init_dir(passphrase=form.cleaned_data['password'])
            f = open(settings.PASSKEEPER_ENCRYPT_STATE_FILE, 'w+')
            f.write("")
            f.close()
    # if a GET (or any other method) we'll create a blank form
    else:
        if settings.DISABLE_INIT != 'True':
            form = PasswordForm()
            if os.path.exists(settings.PASSKEEPER_ENCRYPT_STATE_FILE):
                state = 'Encrypted or clean /!\/!\/!\ you will erase \
passwords if existing /!\/!\/!\ '
            else:
                state = 'Decrypted /!\/!\/!\ No need to init /!\/!\/!\ '

            return render(request, 'init.html',
                          context={'form': form, 'state': state})
    return render(request, 'init-disabled.html')
예제 #5
0
def flush(request):
    """
        Flush all log and git history
        To have more security
    """
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = SubmitForm(request.POST)
        mypasskeeper = Passkeeper(directory=settings.PASSKEEPER_PATH)
        with open("log/frontkeeper.views.flush.log", "w"):
            pass
        mypasskeeper.flush_history()
        with open("log/frontkeeper.views.decrypt.log", "w"):
            pass
        with open("log/frontkeeper.views.edit.log", "w"):
            pass
        with open("log/frontkeeper.views.encrypt.log", "w"):
            pass
        with open("log/frontkeeper.views.new.log", "w"):
            pass
        with open("log/frontkeeper.views.init.log", "w"):
            pass

    # if a GET (or any other method) we'll create a blank form
    else:
        form = EmptyForm()
    if os.path.exists(settings.PASSKEEPER_ENCRYPT_STATE_FILE):
        state = 'Encrypted'
    else:
        state = 'Decrypted /!\/!\/!\  Don\'t forget to encrypt \
before leaving /!\/!\/!\ '
    return render(request, 'flush.html',
                  context={'form': form, 'state': state})
예제 #6
0
 def setUp(self, mock_git):
     super(PasskeeperTestCase, self).setUp()
     self.mock_git = mock_git
     self.pk = Passkeeper('foo')
예제 #7
0
class PasskeeperTestCase(test_base.TestCase):
    @patch('passkeeper.Git')
    def setUp(self, mock_git):
        super(PasskeeperTestCase, self).setUp()
        self.mock_git = mock_git
        self.pk = Passkeeper('foo')

    def tearDown(self):
        super(PasskeeperTestCase, self).tearDown()
        del self.pk
        del self.mock_git

    def test_constructor(self):
        self.mock_git.assert_called_once_with('foo')
        self.assertEquals(self.pk.directory, 'foo')
        self.assertEquals(self.pk.encrypted_dir, 'encrypted')

    @patch('passkeeper.Passkeeper.remove_old_encrypted_files')
    @patch('passkeeper.Passkeeper.cleanup')
    @patch('passkeeper.Passkeeper.encrypt')
    @patch('passkeeper.create_dir')
    def test_init_dir(self, mock_create_dir, mock_encrypt, mock_cleanup,
                      remove_old_encrypted_files):
        self.mock_git.reset_mock()
        with patch('__builtin__.open', mock_open(), create=True) as file_mock:
            file_handle = file_mock()
            self.pk.init_dir(passphrase='secret')

        calls = [call().init(), call().add_gitignore(['*.ini', '/*.raw'])]
        self.mock_git.assert_has_calls(calls)

        calls = [call('foo'), call('foo/default.raw')]
        mock_create_dir.assert_has_calls(calls)

        file_mock.assert_any_call('foo/default.ini', 'w')
        file_mock.assert_any_call('foo/default.raw/ssh_id.rsa', 'w')

        self.assertEquals(True, file_handle.write.called)

        remove_old_encrypted_files.assert_called_once_with(force_remove=True)

        mock_encrypt.assert_called_once_with(passphrase='secret')
        mock_cleanup.assert_called_once_with()

    @patch('passkeeper.run_cmd')
    @patch('passkeeper.os.listdir')
    @patch('passkeeper.os.path.isfile')
    def test_cleanup(self, mock_isfile, mock_listdir, mock_cmd):
        # One ignored file and one valid file
        mock_listdir.return_value = ['ignored', 'bar.ini']
        mock_isfile.return_value = True
        self.pk.cleanup()

        mock_cmd.assert_called_once_with('shred --remove foo/bar.ini')

        # Test with bad filepath. Do nothing
        mock_cmd.reset_mock()
        mock_listdir.return_value = ['bar.ini']
        mock_isfile.return_value = False
        self.pk.cleanup()

        self.assertEquals(mock_cmd.call_count, 0)

    @patch('passkeeper.raw_input')
    @patch('passkeeper.run_cmd')
    @patch('passkeeper.os.listdir')
    @patch('passkeeper.os.path.isfile')
    def test_remove_old_encrypted_files(self, mock_isfile, mock_listdir,
                                        mock_cmd, mock_raw_input):
        # One file and 3 in encrypted so delete one.
        # Basicly the script will remove 2 file.
        # But we will cancel one of them
        #  * bar keep
        #  * foo delete canceled
        #  * bli deleted

        mock_raw_input.side_effect = ['n', 'y']
        # listdir is used by walk
        mock_listdir.return_value = [
            'bar.ini.passkeeper', 'foo.ini.passkeeper',
            'dir/bli.ini.passkeeper'
        ]
        mock_isfile.side_effect = [True, False, False]
        self.pk.remove_old_encrypted_files(force_remove=False)

        mock_cmd.assert_called_once_with(
            'shred foo/encrypted/dir/bli.ini.passkeeper')
        calls = [
            call().force_remove(['encrypted/dir/bli.ini.passkeeper']),
            call().commit('Remove file encrypted/dir/bli.ini.passkeeper')
        ]
        self.mock_git.assert_has_calls(calls)

        # Same test with force remove.
        # Never ask confirmation, just delete both files
        mock_cmd.reset_mock()
        mock_raw_input.reset_mock()
        mock_isfile.side_effect = [True, False, False]

        self.pk.remove_old_encrypted_files(force_remove=True)

        self.assertEquals(2, mock_cmd.call_count)
        self.assertEquals(0, mock_raw_input.call_count)

    @patch('passkeeper.decrypt')
    @patch('passkeeper.os.listdir')
    @patch('passkeeper.os.path.isfile')
    def test_decrypt(self, mock_isfile, mock_listdir, mock_decrypt):
        # One ignored file, one valid file adn one file in raw dir.
        # Used in walk dir
        mock_listdir.return_value = [
            'ignored', 'bar.ini.passkeeper', 'foo.raw/bli.passkeeper'
        ]
        mock_isfile.return_value = True
        self.pk.decrypt(passphrase='secret')

        mock_decrypt.assert_any_call(output='foo/bar.ini',
                                     passphrase='secret',
                                     source='foo/encrypted/bar.ini.passkeeper')
        mock_decrypt.assert_any_call(
            output='foo/foo.raw/bli',
            passphrase='secret',
            source='foo/encrypted/foo.raw/bli.passkeeper')

        # Test with bad filepath. Do nothing
        mock_decrypt.reset_mock()
        mock_listdir.return_value = ['bad_fake_file']
        mock_isfile.return_value = False
        self.pk.decrypt(passphrase='secret')

        self.assertEquals(mock_decrypt.call_count, 0)

    @patch('passkeeper.create_dir')
    @patch('passkeeper.encrypt')
    @patch('passkeeper.os.listdir')
    @patch('passkeeper.os.path.isfile')
    def test_encrypt(self, mock_isfile, mock_listdir, mock_encrypt,
                     mock_create_dir):
        # Test with bad filepath. Don't encrypt this file
        mock_encrypt.reset_mock()
        self.mock_git.reset_mock()
        mock_listdir.return_value = ['fake_bar_file.ini']
        mock_isfile.return_value = False

        self.assertTrue(self.pk.encrypt(passphrase='secret'))
        self.assertEquals(mock_encrypt.call_count, 0)

        # One ignored file and one valid file
        # And one file in raw subdir
        mock_encrypt.reset_mock()
        self.mock_git.reset_mock()
        mock_create_dir.reset_mock()
        # First for listdir, second for walk
        mock_listdir.side_effect = [['ignored', 'bar.ini', 'foo.raw'], ['bli']]
        mock_isfile.return_value = True

        self.assertTrue(
            self.pk.encrypt(passphrase='secret', commit_message='my message'))

        calls = [call('foo/encrypted'), call('foo/encrypted/foo.raw')]
        mock_create_dir.assert_has_calls(calls)

        mock_encrypt.assert_any_call(passphrase='secret',
                                     source='foo/bar.ini',
                                     output='foo/encrypted/bar.ini.passkeeper')
        mock_encrypt.assert_any_call(
            passphrase='secret',
            source='foo/foo.raw/bli',
            output='foo/encrypted/foo.raw/bli.passkeeper')
        calls = [
            call().add(['encrypted/bar.ini.passkeeper']),
            call().add(['encrypted/foo.raw/bli.passkeeper']),
            call().commit('my message')
        ]
        self.mock_git.assert_has_calls(calls)

    @patch('passkeeper.ConfigParser.RawConfigParser')
    @patch('passkeeper.os.listdir')
    @patch('passkeeper.os.path.isfile')
    def test_search(self, mock_isfile, mock_listdir, mock_rawconfig):
        # One ignored file and one valid file
        # In this file we have 4 sections :
        # - one matching in section name
        # - one matching not matching at all
        # - one matching with value content
        mock_config = MagicMock()
        mock_config.sections.return_value = ['unmatched', 'WanTed', 'value']
        vals = {
            ('unmatched', ): [('foo', 'bar')],
            ('WanTed', ): [('foo', 'bar')],
            ('value', ): [('found', '.wanted.')]
        }

        def side_effect(*args):
            return vals[args]

        mock_config.items = MagicMock(side_effect=side_effect)
        mock_rawconfig.return_value = mock_config
        mock_listdir.return_value = ['ignored', 'bar.ini']
        mock_isfile.return_value = True
        config, matching_sections = self.pk.search(pattern='WANTED')

        mock_config.read.assert_called_once_with('foo/bar.ini')
        self.assertEquals(['WanTed', 'value'], matching_sections)

        # Test with bad filepath.
        mock_config = Mock()
        mock_config.sections.return_value = []
        mock_rawconfig.return_value = mock_config
        mock_listdir.return_value = ['bar.ini']
        mock_isfile.return_value = False
        config, matching_sections = self.pk.search(pattern='WANTED')

        self.assertEquals(mock_config.read.call_count, 0)
        self.assertEquals([], matching_sections)

    @patch('passkeeper.shred_dir')
    def test_flush_history(self, mock_shred):

        self.pk.flush_history()

        mock_shred.assert_called_once_with('foo/.git')
        calls = [
            call().init(),
            call().add(['encrypted', '.gitignore']),
            call().commit('Clean git History')
        ]

        self.mock_git.assert_has_calls(calls)
예제 #8
0
 def setUp(self, mock_git):
     super(PasskeeperTestCase, self).setUp()
     self.mock_git = mock_git
     self.pk = Passkeeper('foo')
예제 #9
0
class PasskeeperTestCase(test_base.TestCase):

    @patch('passkeeper.Git')
    def setUp(self, mock_git):
        super(PasskeeperTestCase, self).setUp()
        self.mock_git = mock_git
        self.pk = Passkeeper('foo')

    def tearDown(self):
        super(PasskeeperTestCase, self).tearDown()
        del self.pk
        del self.mock_git

    def test_constructor(self):
        self.mock_git.assert_called_once_with('foo')
        self.assertEquals(self.pk.directory, 'foo')
        self.assertEquals(self.pk.encrypted_dir, 'encrypted')


    @patch('passkeeper.Passkeeper.remove_old_encrypted_files')
    @patch('passkeeper.Passkeeper.cleanup')
    @patch('passkeeper.Passkeeper.encrypt')
    @patch('passkeeper.create_dir')
    def test_init_dir(self, mock_create_dir, mock_encrypt, mock_cleanup,
                      remove_old_encrypted_files):
        self.mock_git.reset_mock()
        with patch('__builtin__.open', mock_open(), create=True) as file_mock:
            file_handle = file_mock()
            self.pk.init_dir(passphrase='secret')

        calls = [call().init(), call().add_gitignore(['*.ini', '/*.raw'])]
        self.mock_git.assert_has_calls(calls)

        calls = [call('foo'), call('foo/default.raw')]
        mock_create_dir.assert_has_calls(calls)

        file_mock.assert_any_call('foo/default.ini', 'w')
        file_mock.assert_any_call('foo/default.raw/ssh_id.rsa', 'w')

        self.assertEquals(True, file_handle.write.called)

        remove_old_encrypted_files.assert_called_once_with(force_remove=True)

        mock_encrypt.assert_called_once_with(passphrase='secret')
        mock_cleanup.assert_called_once_with()


    @patch('passkeeper.run_cmd')
    @patch('passkeeper.os.listdir')
    @patch('passkeeper.os.path.isfile')
    def test_cleanup(self, mock_isfile, mock_listdir, mock_cmd):
        # One ignored file and one valid file
        mock_listdir.return_value = ['ignored', 'bar.ini']
        mock_isfile.return_value = True
        self.pk.cleanup()

        mock_cmd.assert_called_once_with('shred --remove foo/bar.ini')

        # Test with bad filepath. Do nothing
        mock_cmd.reset_mock()
        mock_listdir.return_value = ['bar.ini']
        mock_isfile.return_value = False
        self.pk.cleanup()

        self.assertEquals(mock_cmd.call_count, 0)


    @patch('passkeeper.raw_input')
    @patch('passkeeper.run_cmd')
    @patch('passkeeper.os.listdir')
    @patch('passkeeper.os.path.isfile')
    def test_remove_old_encrypted_files(self, mock_isfile, mock_listdir,
                               mock_cmd, mock_raw_input):
        # One file and 3 in encrypted so delete one.
        # Basicly the script will remove 2 file.
        # But we will cancel one of them
        #  * bar keep
        #  * foo delete canceled
        #  * bli deleted

        mock_raw_input.side_effect = ['n', 'y']
        # listdir is used by walk
        mock_listdir.return_value = [ 'bar.ini.passkeeper',
                                      'foo.ini.passkeeper',
                                      'dir/bli.ini.passkeeper']
        mock_isfile.side_effect = [ True, False, False ]
        self.pk.remove_old_encrypted_files(force_remove=False)

        mock_cmd.assert_called_once_with('shred foo/encrypted/dir/bli.ini.passkeeper')
        calls = [ call().force_remove(['encrypted/dir/bli.ini.passkeeper']),
                  call().commit('Remove file encrypted/dir/bli.ini.passkeeper')]
        self.mock_git.assert_has_calls(calls)

        # Same test with force remove.
        # Never ask confirmation, just delete both files
        mock_cmd.reset_mock()
        mock_raw_input.reset_mock()
        mock_isfile.side_effect = [ True, False, False ]

        self.pk.remove_old_encrypted_files(force_remove=True)

        self.assertEquals(2, mock_cmd.call_count)
        self.assertEquals(0, mock_raw_input.call_count)


    @patch('passkeeper.decrypt')
    @patch('passkeeper.os.listdir')
    @patch('passkeeper.os.path.isfile')
    def test_decrypt(self, mock_isfile, mock_listdir, mock_decrypt):
        # One ignored file, one valid file adn one file in raw dir.
        # Used in walk dir
        mock_listdir.return_value = ['ignored', 'bar.ini.passkeeper', 'foo.raw/bli.passkeeper']
        mock_isfile.return_value = True
        self.pk.decrypt(passphrase='secret')

        mock_decrypt.assert_any_call(output='foo/bar.ini', passphrase='secret',
                                     source='foo/encrypted/bar.ini.passkeeper')
        mock_decrypt.assert_any_call(output='foo/foo.raw/bli', passphrase='secret',
                                     source='foo/encrypted/foo.raw/bli.passkeeper')

        # Test with bad filepath. Do nothing
        mock_decrypt.reset_mock()
        mock_listdir.return_value = ['bad_fake_file']
        mock_isfile.return_value = False
        self.pk.decrypt(passphrase='secret')

        self.assertEquals(mock_decrypt.call_count, 0)


    @patch('passkeeper.create_dir')
    @patch('passkeeper.encrypt')
    @patch('passkeeper.os.listdir')
    @patch('passkeeper.os.path.isfile')
    def test_encrypt(self, mock_isfile, mock_listdir, mock_encrypt, mock_create_dir):
        # Test with bad filepath. Don't encrypt this file
        mock_encrypt.reset_mock()
        self.mock_git.reset_mock()
        mock_listdir.return_value = ['fake_bar_file.ini']
        mock_isfile.return_value = False

        self.assertTrue(self.pk.encrypt(passphrase='secret'))
        self.assertEquals(mock_encrypt.call_count, 0)

        # One ignored file and one valid file
        # And one file in raw subdir
        mock_encrypt.reset_mock()
        self.mock_git.reset_mock()
        mock_create_dir.reset_mock()
        # First for listdir, second for walk
        mock_listdir.side_effect = [['ignored', 'bar.ini', 'foo.raw'], ['bli']]
        mock_isfile.return_value = True

        self.assertTrue(self.pk.encrypt(passphrase='secret', commit_message='my message'))

        calls = [call('foo/encrypted'), call('foo/encrypted/foo.raw')]
        mock_create_dir.assert_has_calls(calls)

        mock_encrypt.assert_any_call(passphrase='secret',
                                     source='foo/bar.ini',
                                     output='foo/encrypted/bar.ini.passkeeper')
        mock_encrypt.assert_any_call(passphrase='secret',
                                     source='foo/foo.raw/bli',
                                     output='foo/encrypted/foo.raw/bli.passkeeper')
        calls = [call().add(['encrypted/bar.ini.passkeeper']),
                 call().add(['encrypted/foo.raw/bli.passkeeper']),
                 call().commit('my message')]
        self.mock_git.assert_has_calls(calls)


    @patch('passkeeper.ConfigParser.RawConfigParser')
    @patch('passkeeper.os.listdir')
    @patch('passkeeper.os.path.isfile')
    def test_search(self, mock_isfile, mock_listdir, mock_rawconfig):
        # One ignored file and one valid file
        # In this file we have 4 sections :
        # - one matching in section name
        # - one matching not matching at all
        # - one matching with value content
        mock_config = MagicMock()
        mock_config.sections.return_value = ['unmatched', 'WanTed', 'value']
        vals = {('unmatched',): [('foo', 'bar')],
                ('WanTed',): [('foo', 'bar')],
                ('value',): [('found', '.wanted.')]}
        def side_effect(*args):
            return vals[args]
        mock_config.items = MagicMock(side_effect=side_effect)
        mock_rawconfig.return_value = mock_config
        mock_listdir.return_value = ['ignored', 'bar.ini']
        mock_isfile.return_value = True
        config, matching_sections = self.pk.search(pattern='WANTED')

        mock_config.read.assert_called_once_with('foo/bar.ini')
        self.assertEquals(['WanTed', 'value'], matching_sections)

        # Test with bad filepath.
        mock_config = Mock()
        mock_config.sections.return_value = []
        mock_rawconfig.return_value = mock_config
        mock_listdir.return_value = ['bar.ini']
        mock_isfile.return_value = False
        config, matching_sections = self.pk.search(pattern='WANTED')

        self.assertEquals(mock_config.read.call_count, 0)
        self.assertEquals([], matching_sections)


    @patch('passkeeper.shred_dir')
    def test_flush_history(self, mock_shred):

        self.pk.flush_history()

        mock_shred.assert_called_once_with('foo/.git')
        calls = [ call().init(),
                  call().add(['encrypted', '.gitignore']),
                  call().commit('Clean git History')]

        self.mock_git.assert_has_calls(calls)