예제 #1
0
파일: note.py 프로젝트: ccaroon/cartaro
 def decrypt(self, passwd):
     orig_content = self.content
     try:
         cryer = Crypto(passwd)
         self.content = cryer.decrypt(self.content)
         self.__is_encrypted = False
     except Exception as e:
         self.__is_encrypted = True
         self.content = orig_content
         raise RuntimeError(F"Failed to decrypt: <{e}>")
예제 #2
0
    def test_encrypt_decrypt(self):
        crypto = Crypto("7h3-7ru7h")

        msg = "Hello, World!"
        secret = crypto.encrypt(msg)
        self.assertIsNotNone(secret)
        self.assertNotEqual(msg, secret)

        clear_text = crypto.decrypt(secret)
        self.assertIsNotNone(clear_text)
        self.assertEqual(msg, clear_text)
예제 #3
0
    def __init__(self, id=None, **kwargs):
        self.name = None
        self.system = None
        self.sub_system = None
        self.type = None
        self.__data = None
        self.note = None
        self.__encrypted = False

        # TODO: Find a better way to manage encryption key???
        if not self.ENCRYPTION_KEY:
            raise Exception("Secret - Encryption Key not set.")

        self.__cryer = Crypto(self.ENCRYPTION_KEY)

        super().__init__(id=id, **kwargs)
예제 #4
0
 def setUp(self):
     self.encryption_key = '0000000'
     Secret.ENCRYPTION_KEY = self.encryption_key
     self.crypto = Crypto(self.encryption_key)
예제 #5
0
class SecretTest(unittest.TestCase):

    def setUp(self):
        self.encryption_key = '0000000'
        Secret.ENCRYPTION_KEY = self.encryption_key
        self.crypto = Crypto(self.encryption_key)

    def test_missing_encryption_key(self):
        Secret.ENCRYPTION_KEY = None

        with self.assertRaisesRegex(Exception, "Secret - Encryption Key not set"):
            secret = Secret(name="bad wolf")

    def test_construction(self):
        # Set secret 'data' directly
        secret = Secret(
            name="LEGO",
            system="www.lego.com",
            sub_system="UI",
            type=Secret.TYPE_USER_PASS,
            data={'username': '******', 'password': '******'}
        )

        self.assertDictEqual(secret.data, {
            'username': '******',
            'password': '******'
        })

        # "Forge" secret 'data' from kwargs
        secret = Secret(
            name="LEGO",
            system="api.lego.com",
            sub_system="REST API",
            type=Secret.TYPE_KEY_SECRET,
            key="4c1300c900d1af3de0e67560f542090b",
            secret="bWluaS1maWcK"
        )

        self.assertDictEqual(secret.data, {
            'key': "4c1300c900d1af3de0e67560f542090b",
            'secret': "bWluaS1maWcK"
        })

    def test_forge(self):
        # user-pass
        secret = Secret.forge(
            Secret.TYPE_USER_PASS,
            username="******",
            password="******"
        )

        self.assertDictEqual(secret, {
            'username': "******",
            'password': "******"
        })

        # token
        secret = Secret.forge(
            Secret.TYPE_TOKEN,
            token="0xDEADBEEF"
        )

        self.assertDictEqual(secret, {'token': "0xDEADBEEF"})

        # key-secret
        secret = Secret.forge(
            Secret.TYPE_KEY_SECRET,
            key="abc12377x",
            secret="frog blast the vent core"
        )

        self.assertDictEqual(secret, {
            'key': "abc12377x",
            'secret': "frog blast the vent core"
        })

    def test_forge_invalid_type(self):
        with self.assertRaisesRegex(TypeError, "Invalid Secret Type: 'base64-encoded-string'"):
            Secret.forge('base64-encoded-string', string="deciduous manifestations")

    def test_forge_missing_args(self):
        with self.assertRaisesRegex(ValueError, "Missing Required Value: 'username'"):
            Secret.forge(
                Secret.TYPE_USER_PASS,
                password="******"
            )

    def test_encryption(self):
        Secret.purge()

        stype = Secret.TYPE_USER_PASS
        username = '******'
        password = '******'
        secret = Secret(
            name="My Email Account",
            system="email.com",
            sub_system="UI",
            type=stype,
            data={'username': username, 'password': password},
            note="Personal Email **ONLY**"
        )

        self.assertEqual(secret.data['username'], username)
        self.assertEqual(secret.data['password'], password)

        secret.save()

        with open('tests/tmp/Secrets-test.json') as file:
            raw_data = json.load(file).get('_default', {}).get('1', {}).get('data')

        self.assertNotEqual(raw_data['username'], secret.data['username'])
        self.assertNotEqual(raw_data['password'], secret.data['password'])

        self.assertEqual(self.crypto.decrypt(raw_data['username']), secret.data['username'])
        self.assertEqual(self.crypto.decrypt(raw_data['password']), secret.data['password'])

        self.assertEqual(secret.data['username'], username)
        self.assertEqual(secret.data['password'], password)

        # Load and check stuff
        secret2 = Secret(id=1)
        secret2.load()

        self.assertEqual(secret2.type, stype)
        self.assertEqual(secret2.data['username'], username)
        self.assertEqual(secret2.data['password'], password)


    def test_serialize(self):
        # set data directly
        secret = Secret(
            name="My Email Account",
            system="email.com",
            sub_system="UI",
            type=Secret.TYPE_USER_PASS,
            data={'username': '******', 'password': '******'},
            note="Personal Email **ONLY**"
        )

        data = secret.serialize()

        self.assertEqual(secret.name, "My Email Account")
        self.assertEqual(secret.system, "email.com")
        self.assertEqual(secret.sub_system, "UI")
        self.assertEqual(secret.type, Secret.TYPE_USER_PASS)
        self.assertEqual(secret.data['username'], "rufus42")
        self.assertEqual(secret.data['password'], "y5kqyRrPXUUjS4DM")
        self.assertEqual(secret.note, "Personal Email **ONLY**")

        # forge data directly
        secret = Secret(
            name="My Email Account",
            system="email.com",
            sub_system="UI",
            type=Secret.TYPE_USER_PASS,
            username='******',
            password='******',
            note="Personal Email **ONLY**"
        )

        data = secret.serialize()

        self.assertEqual(secret.name, "My Email Account")
        self.assertEqual(secret.system, "email.com")
        self.assertEqual(secret.sub_system, "UI")
        self.assertEqual(secret.type, Secret.TYPE_USER_PASS)
        self.assertEqual(secret.data['username'], "rufus007")
        self.assertEqual(secret.data['password'], "y5kqyRrXPXUUjS4DM")
        self.assertEqual(secret.note, "Personal Email **ONLY**")

    def test_tagging(self):
        # Basic instance
        secret = Secret(
            name="LEGO",
            system="www.lego.com",
            sub_system="UI",
            type=Secret.TYPE_USER_PASS,
            data={'username': '******', 'password': '******'},
        )
        self.assertIsNotNone(secret.tags)
        self.assertIsInstance(secret.tags, set)
        self.assertEqual(len(secret.tags), 0)

        # Create with Tags
        secret.tag("lego")
        secret.tag("brick-by-brick")
        self.assertEqual(len(secret.tags), 2)
        self.assertIsInstance(list(secret.tags)[0], Tag)
        secret.save()

        # Retrieve has Tags
        secret2 = Secret(id=secret.id)
        secret2.load()
        self.assertIsNotNone(secret2.tags)
        self.assertIsInstance(secret2.tags, set)
        self.assertEqual(len(secret2.tags), 2)
        self.assertIsInstance(list(secret2.tags)[0], Tag)
        self.assertTrue(Tag(name="lego") in secret2.tags)

        # Update tags
        secret2.tag("studs-r-us")
        self.assertEqual(len(secret2.tags), 3)
        self.assertIsInstance(list(secret2.tags)[2], Tag)

        secret2.save()

        secret3 = Secret(id=secret2.id)
        secret3.load()
        self.assertIsNotNone(secret3.tags)
        self.assertIsInstance(secret3.tags, set)
        self.assertEqual(len(secret3.tags), 3)

        self.assertTrue(Tag(name="lego") in secret3.tags)
        self.assertTrue(Tag(name="brick-by-brick") in secret3.tags)
        self.assertTrue(Tag(name="studs-r-us") in secret3.tags)

    def test_blot(self):
        license = 'this is the way the world ends. not with a bang...'
        secret = Secret(
            name="Hydra License",
            system="Hydra",
            sub_system="license",
            type=Secret.TYPE_BLOT,
            data={'content': license}
        )

        self.assertEqual(secret.type, Secret.TYPE_BLOT)

        self.assertDictEqual(secret.data, {
            'content': license
        })
예제 #6
0
 def test_construct(self):
     with self.assertRaisesRegex(ValueError,
                                 "'password' cannot be empty or None"):
         Crypto(None)
예제 #7
0
class Secret(Taggable, Base):

    TYPE_USER_PASS = '******'
    TYPE_TOKEN = 'token'
    TYPE_KEY_SECRET = 'key-secret'
    TYPE_BLOT = 'blot'
    ENCRYPTION_KEY = None

    TEMPLATES = {
        TYPE_USER_PASS: {
            'username': None,
            'password': None
        },
        TYPE_TOKEN: {
            'token': None,
        },
        TYPE_KEY_SECRET: {
            'key': None,
            'secret': None
        },
        TYPE_BLOT: {
            'content': None
        }
    }

    def __init__(self, id=None, **kwargs):
        self.name = None
        self.system = None
        self.sub_system = None
        self.type = None
        self.__data = None
        self.note = None
        self.__encrypted = False

        # TODO: Find a better way to manage encryption key???
        if not self.ENCRYPTION_KEY:
            raise Exception("Secret - Encryption Key not set.")

        self.__cryer = Crypto(self.ENCRYPTION_KEY)

        super().__init__(id=id, **kwargs)

    @property
    def data(self):
        if self.__encrypted:
            self.__decrypt_data()
        return self.__data

    @data.setter
    def data(self, new_data):
        # Assume new_data is in clear text
        self.__data = new_data
        self.__encrypt_data()

    @classmethod
    def forge(cls, stype, **kwargs):
        template = cls.TEMPLATES.get(stype, None)
        if not template:
            raise TypeError(F"Invalid Secret Type: '{stype}'")

        secret = template.copy()
        for attr in secret.keys():
            if attr not in kwargs:
                raise ValueError(
                    F"Secret.forge - Missing Required Value: '{attr}'")

            secret[attr] = kwargs.get(attr)

        return secret

    def __encrypt_data(self):
        if self.__data:
            enc_data = self.__data.copy()
            for attr in enc_data.keys():
                enc_data[attr] = self.__cryer.encrypt(enc_data[attr])

            self.__data = enc_data
            self.__encrypted = True

    def __decrypt_data(self):
        if self.__data:
            clear_data = self.__data.copy()
            for attr in clear_data.keys():
                clear_data[attr] = self.__cryer.decrypt(clear_data[attr])

            self.__data = clear_data
            self.__encrypted = False

    def _serialize(self):
        if not self.__encrypted:
            self.__encrypt_data()

        data = {
            'name': self.name,
            'system': self.system,
            'sub_system': self.sub_system,
            'type': self.type,
            # MUST access via __data else it will be decrypted
            'data': self.__data,
            'note': self.note,
            '__encrypted': self.__encrypted
        }

        # Tags
        data.update(super()._serialize())

        return data

    def rekey(self, new_key):
        self.__cryer = Crypto(new_key)
        self.save()

    def update(self, data):
        self.name = data.get('name', self.name)
        self.system = data.get('system', self.system)
        self.sub_system = data.get('sub_system', self.sub_system)
        self.type = data.get('type', self.type)
        # Access via __data so as to not change the underlying data
        self.__data = data.get('data', self.__data)
        self.note = data.get('note', self.note)
        self.__encrypted = data.get('__encrypted', self.__encrypted)
        self.tags = data.get('tags', self.tags)

        if self.type and self.data is None:
            self.data = Secret.forge(self.type, **data)
예제 #8
0
 def rekey(self, new_key):
     self.__cryer = Crypto(new_key)
     self.save()