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})
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})
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})
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')
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})
def setUp(self, mock_git): super(PasskeeperTestCase, self).setUp() self.mock_git = mock_git self.pk = Passkeeper('foo')
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)
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)