import gi import os import subprocess from chrysacase import ChrysalideTestCase from gi.repository import Gio, GLib from pychrysalide.glibext import SecretStorage class TestSecretStorage(ChrysalideTestCase): """TestCase for secret storage features.""" @classmethod def setUpClass(cls): super(TestSecretStorage, cls).setUpClass() cls.log('Creating GSettings schema...') path = os.path.dirname(os.path.realpath(__file__)) subprocess.run([ 'glib-compile-schemas', path ]) @classmethod def tearDownClass(cls): super(TestSecretStorage, cls).tearDownClass() cls.log('Removing compiled GSettings schema...') path = os.path.dirname(os.path.realpath(__file__)) filename = os.path.join(path, 'gschemas.compiled') if os.path.exists(filename): os.remove(filename) def _get_settings(self, sid): """Provide local GSettings instance.""" path = os.path.dirname(os.path.realpath(__file__)) source = Gio.SettingsSchemaSource.new_from_directory(path, None, True) schema = Gio.SettingsSchemaSource.lookup(source, sid, False) settings = Gio.Settings.new_full(schema, None, None) return settings def testMasterKeyDefinition(self): """Check for cryptographic parameters for secret storage.""" settings = self._get_settings('re.chrysalide.tests.secstorage') storage = SecretStorage(settings) settings.reset('master') self.assertEqual(len(settings.get_value('master').unpack()), 0) self.assertFalse(storage.has_key) settings.set_value('master', GLib.Variant('ay', b'ABC')) self.assertFalse(storage.has_key) settings.set_value('master', GLib.Variant('ay', b'A' * 23)) self.assertTrue(storage.has_key) def testMasterKeyCreation(self): """Create and update cryptographic parameters for secret storage.""" settings = self._get_settings('re.chrysalide.tests.secstorage') storage = SecretStorage(settings) settings.reset('salt') settings.reset('master') self.assertFalse(storage.has_key) status = storage.set_password('') self.assertTrue(status); self.assertTrue(storage.has_key) self.assertTrue(storage.is_locked) status = storage.unlock('') self.assertTrue(status) self.assertFalse(storage.is_locked) storage.lock() self.assertTrue(storage.is_locked) status = storage.unlock('XXX') self.assertFalse(status) self.assertTrue(storage.is_locked) def testDataEncryption(self): """Encrypt and decrypt data with the secret storage.""" settings = self._get_settings('re.chrysalide.tests.secstorage') storage = SecretStorage(settings) settings.reset('salt') settings.reset('master') status = storage.set_password('') self.assertTrue(status); status = storage.unlock('') self.assertTrue(status) original = b'ABC' encrypted = storage.encrypt_data(original) self.assertIsNotNone(encrypted) plain = storage.decrypt_data(encrypted) self.assertIsNotNone(plain) self.assertEqual(original, plain) original = b'A' * 136 encrypted = storage.encrypt_data(original) self.assertIsNotNone(encrypted) plain = storage.decrypt_data(encrypted) self.assertIsNotNone(plain) self.assertEqual(original, plain)