def apply(self, ui): envelope = ui.current_buffer.envelope if self.action == 'rmencrypt': try: for keyid in self.encrypt_keys: tmp_key = crypto.get_key(keyid) del envelope.encrypt_keys[crypto.hash_key(tmp_key)] except GPGProblem as e: ui.notify(e.message, priority='error') if not envelope.encrypt_keys: envelope.encrypt = False ui.current_buffer.rebuild() return elif self.action == 'encrypt': encrypt = True elif self.action == 'unencrypt': encrypt = False elif self.action == 'toggleencrypt': encrypt = not envelope.encrypt envelope.encrypt = encrypt if encrypt: if not self.encrypt_keys: for recipient in envelope.headers['To'][0].split(','): if not recipient: continue match = re.search("<(.*@.*)>", recipient) if match: recipient = match.group(0) self.encrypt_keys.append(recipient) logging.debug("encryption keys: " + str(self.encrypt_keys)) for keyid in self.encrypt_keys: try: key = crypto.get_key(keyid, validate=True, encrypt=True) except GPGProblem as e: if e.code == GPGCode.AMBIGUOUS_NAME: possible_keys = crypto.list_keys(hint=keyid) tmp_choices = [k.uids[0].uid for k in possible_keys] choices = { str(len(tmp_choices) - x): tmp_choices[x] for x in range(0, len(tmp_choices)) } keyid = yield ui.choice("ambiguous keyid! Which " + "key do you want to use?", choices, cancel=None) if keyid: self.encrypt_keys.append(keyid) continue else: ui.notify(e.message, priority='error') continue envelope.encrypt_keys[crypto.hash_key(key)] = key if not envelope.encrypt_keys: envelope.encrypt = False # reload buffer ui.current_buffer.rebuild()
def test_ambiguous_two_valid(self): with mock.patch('alot.crypto.gpg.core.Context', mock.Mock(return_value=self._context_mock())), \ mock.patch('alot.crypto.list_keys', mock.Mock(return_value=[utilities.make_key(), utilities.make_key()])): with self.assertRaises(crypto.GPGProblem) as cm: crypto.get_key('placeholder') self.assertEqual(cm.exception.code, GPGCode.AMBIGUOUS_NAME)
def test_get_keys_from_cc(self): ui = utilities.make_ui() envelope = Envelope() envelope['Cc'] = '[email protected], [email protected]' yield utils.set_encrypt(ui, envelope) self.assertTrue(envelope.encrypt) self.assertEqual( [f.fpr for f in envelope.encrypt_keys.itervalues()], [crypto.get_key(FPR).fpr, crypto.get_key(EXTRA_FPRS[0]).fpr])
async def test_get_keys_from_cc(self): ui = utilities.make_ui() envelope = Envelope() envelope['Cc'] = '[email protected], [email protected]' await utils.update_keys(ui, envelope) self.assertTrue(envelope.encrypt) self.assertCountEqual( [f.fpr for f in envelope.encrypt_keys.values()], [crypto.get_key(FPR).fpr, crypto.get_key(EXTRA_FPRS[0]).fpr])
def apply(self, ui): envelope = ui.current_buffer.envelope if self.action == 'rmencrypt': try: for keyid in self.encrypt_keys: tmp_key = crypto.get_key(keyid) del envelope.encrypt_keys[crypto.hash_key(tmp_key)] except GPGProblem as e: ui.notify(e.message, priority='error') if not envelope.encrypt_keys: envelope.encrypt = False ui.current_buffer.rebuild() return elif self.action == 'encrypt': encrypt = True elif self.action == 'unencrypt': encrypt = False elif self.action == 'toggleencrypt': encrypt = not envelope.encrypt envelope.encrypt = encrypt if encrypt: if not self.encrypt_keys: for recipient in envelope.headers['To'][0].split(','): if not recipient: continue match = re.search("<(.*@.*)>", recipient) if match: recipient = match.group(0) self.encrypt_keys.append(recipient) logging.debug("encryption keys: " + str(self.encrypt_keys)) for keyid in self.encrypt_keys: try: key = crypto.get_key(keyid, validate=True, encrypt=True) except GPGProblem as e: if e.code == GPGCode.AMBIGUOUS_NAME: possible_keys = crypto.list_keys(hint=keyid) tmp_choices = [k.uids[0].uid for k in possible_keys] choices = {str(len(tmp_choices) - x): tmp_choices[x] for x in range(0, len(tmp_choices))} keyid = yield ui.choice("ambiguous keyid! Which" + "key do you want to use?", choices, cancel=None) if keyid: self.encrypt_keys.append(keyid) continue else: ui.notify(e.message, priority='error') continue envelope.encrypt_keys[crypto.hash_key(key)] = key if not envelope.encrypt_keys: envelope.encrypt = False # reload buffer ui.current_buffer.rebuild()
def apply(self, ui): sign = None key = None envelope = ui.current_buffer.envelope # sign status if self.action == 'sign': sign = True elif self.action == 'unsign': sign = False elif self.action == 'toggle': sign = not envelope.sign envelope.sign = sign # try to find key if hint given as parameter if sign: if len(self.keyid) > 0: keyid = str(' '.join(self.keyid)) try: key = crypto.get_key(keyid, validate=True, sign=True) except GPGProblem as e: envelope.sign = False ui.notify(e.message, priority='error') return envelope.sign_key = key else: envelope.sign_key = None # reload buffer ui.current_buffer.rebuild()
def test_validate(self): # Since we already test validation we're only going to test validate # once. with gpg.core.Context() as ctx: expected = ctx.get_key(FPR).uids[0].uid actual = crypto.get_key(FPR, validate=True, encrypt=True, sign=True).uids[0].uid self.assertEqual(expected, actual)
def test_get_keys_ambiguous(self): """Test gettings keys when when the key is ambiguous.""" key = crypto.get_key(FPR, validate=True, encrypt=True, signed_only=False) ui = mock.Mock() # Creat a ui.choice object that can satisfy twisted, but can also be # queried for calls as a mock @inlineCallbacks def choice(*args, **kwargs): yield None ui.choice = mock.Mock(wraps=choice) ids = [FPR] with mock.patch( 'alot.commands.utils.crypto.get_key', mock.Mock(side_effect=errors.GPGProblem( 'test', errors.GPGCode.AMBIGUOUS_NAME))): with mock.patch('alot.commands.utils.crypto.list_keys', mock.Mock(return_value=[key])): yield utils._get_keys(ui, ids, signed_only=False) ui.choice.assert_called_once()
def add_signature_headers(mail, sigs, error_msg): '''Add pseudo headers to the mail indicating whether the signature verification was successful. :param mail: :class:`email.message.Message` the message to entitle :param sigs: list of :class:`gpgme.Signature` :param error_msg: `str` containing an error message, the empty string indicating no error ''' sig_from = '' if len(sigs) == 0: error_msg = error_msg or 'no signature found' else: try: sig_from = crypto.get_key(sigs[0].fpr).uids[0].uid except: sig_from = sigs[0].fpr mail.add_header( X_SIGNATURE_VALID_HEADER, 'False' if error_msg else 'True', ) mail.add_header( X_SIGNATURE_MESSAGE_HEADER, u'Invalid: {0}'.format(error_msg) if error_msg else u'Valid: {0}'.format(sig_from), )
def get_keys(ui, encrypt_keyids, block_error=False): keys = {} for keyid in encrypt_keyids: try: key = crypto.get_key(keyid, validate=True, encrypt=True) except GPGProblem as e: if e.code == GPGCode.AMBIGUOUS_NAME: possible_keys = crypto.list_keys(hint=keyid) tmp_choices = [k.uids[0].uid for k in possible_keys] choices = { str(len(tmp_choices) - x): tmp_choices[x] for x in range(0, len(tmp_choices)) } keyid = yield ui.choice("ambiguous keyid! Which " + "key do you want to use?", choices, cancel=None) if keyid: encrypt_keyids.append(keyid) continue else: ui.notify(e.message, priority='error', block=block_error) continue keys[crypto.hash_key(key)] = key returnValue(keys)
def add_signature_headers(mail, sigs, error_msg): '''Add pseudo headers to the mail indicating whether the signature verification was successful. :param mail: :class:`email.message.Message` the message to entitle :param sigs: list of :class:`gpgme.Signature` :param error_msg: `str` containing an error message, the empty string indicating no error ''' sig_from = '' if len(sigs) == 0: error_msg = error_msg or 'no signature found' else: try: sig_from = crypto.get_key(sigs[0].fpr).uids[0].uid except: sig_from = sigs[0].fpr mail.add_header( X_SIGNATURE_VALID_HEADER, 'False' if error_msg else 'True', ) mail.add_header( X_SIGNATURE_MESSAGE_HEADER, 'Invalid: {0}'.format(error_msg) if error_msg else 'Valid: {0}'.format(sig_from), )
def test_get_partial_keys(self): ui = mock.Mock() envelope = Envelope() envelope['Cc'] = '[email protected], [email protected]' yield utils.set_encrypt(ui, envelope) self.assertTrue(envelope.encrypt) self.assertEqual([f.fpr for f in envelope.encrypt_keys.itervalues()], [crypto.get_key(FPR).fpr])
async def test_get_partial_keys(self): ui = utilities.make_ui() envelope = Envelope() envelope['Cc'] = '[email protected], [email protected]' await utils.update_keys(ui, envelope) self.assertTrue(envelope.encrypt) self.assertCountEqual([f.fpr for f in envelope.encrypt_keys.values()], [crypto.get_key(FPR).fpr])
async def test_get_partial_keys(self): ui = utilities.make_ui() envelope = Envelope() envelope['Cc'] = '[email protected], [email protected]' await utils.update_keys(ui, envelope) self.assertTrue(envelope.encrypt) self.assertCountEqual( [f.fpr for f in envelope.encrypt_keys.values()], [crypto.get_key(FPR).fpr])
async def test_get_keys_missing(self): """Test that getting keys works when some keys are missing.""" expected = crypto.get_key(FPR, validate=True, encrypt=True, signed_only=False) ui = utilities.make_ui() ids = [FPR, "6F6B15509CF8E59E6E469F327F438280EF8D349F"] actual = await utils._get_keys(ui, ids) self.assertIn(FPR, actual) self.assertEqual(actual[FPR].fpr, expected.fpr)
def gpg_key(value): """ test if value points to a known gpg key and return that key as :class:`pyme.pygpgme._gpgme_key`. """ try: return crypto.get_key(value) except GPGProblem, e: raise ValidateError(e.message)
async def test_get_keys(self): """Test that getting keys works when all keys are present.""" expected = crypto.get_key(FPR, validate=True, encrypt=True, signed_only=False) ui = utilities.make_ui() ids = [FPR] actual = await utils._get_keys(ui, ids) self.assertIn(FPR, actual) self.assertEqual(actual[FPR].fpr, expected.fpr)
def test_get_partial_keys(self): ui = utilities.make_ui() envelope = Envelope() envelope['Cc'] = '[email protected], [email protected]' yield utils.set_encrypt(ui, envelope) self.assertTrue(envelope.encrypt) self.assertEqual( [f.fpr for f in envelope.encrypt_keys.itervalues()], [crypto.get_key(FPR).fpr])
def test_ambiguous_one_valid(self): invalid_key = utilities.make_key(invalid=True) valid_key = utilities.make_key() with mock.patch('alot.crypto.gpg.core.Context', mock.Mock(return_value=self._context_mock())), \ mock.patch('alot.crypto.list_keys', mock.Mock(return_value=[valid_key, invalid_key])): key = crypto.get_key('placeholder') self.assertIs(key, valid_key)
async def test_encrypt_to_self_false(self): ui = utilities.make_ui() envelope = Envelope() envelope['From'] = '*****@*****.**' envelope['To'] = '*****@*****.**' gpg_key = crypto.get_key(FPR) account = _Account(encrypt_to_self=False, gpg_key=gpg_key) envelope.account = account await utils.update_keys(ui, envelope) self.assertTrue(envelope.encrypt) self.assertNotIn(FPR, envelope.encrypt_keys)
def test_encrypt(self): to_encrypt = b"this is a string\nof data." encrypted = crypto.encrypt(to_encrypt, keys=[crypto.get_key(FPR)]) with tempfile.NamedTemporaryFile(delete=False) as f: f.write(encrypted) enc_file = f.name self.addCleanup(os.unlink, enc_file) dec = subprocess.check_output(['gpg2', '--decrypt', enc_file], stderr=DEVNULL) self.assertEqual(to_encrypt, dec)
def test_encrypt_to_self_false(self): ui = utilities.make_ui() envelope = Envelope() envelope['From'] = '*****@*****.**' envelope['To'] = '*****@*****.**' gpg_key = crypto.get_key(FPR) account = _Account(encrypt_to_self=False, gpg_key=gpg_key) with mock.patch('alot.commands.thread.settings.get_account_by_address', mock.Mock(return_value=account)): yield utils.set_encrypt(ui, envelope) self.assertTrue(envelope.encrypt) self.assertNotIn(FPR, envelope.encrypt_keys)
def test_encrypt(self): to_encrypt = "this is a string\nof data." encrypted = crypto.encrypt(to_encrypt, keys=[crypto.get_key(FPR)]) with tempfile.NamedTemporaryFile(delete=False) as f: f.write(encrypted) enc_file = f.name self.addCleanup(os.unlink, enc_file) dec = subprocess.check_output(['gpg', '--decrypt', enc_file], stderr=DEVNULL) self.assertEqual(to_encrypt, dec)
async def test_encrypt_to_self_true(self): ui = utilities.make_ui() envelope = Envelope() envelope['From'] = '*****@*****.**' envelope['To'] = '*****@*****.**' gpg_key = crypto.get_key(FPR) account = _Account(encrypt_to_self=True, gpg_key=gpg_key) with mock.patch('alot.commands.thread.settings.get_account_by_address', mock.Mock(return_value=account)): await utils.update_keys(ui, envelope) self.assertTrue(envelope.encrypt) self.assertIn(FPR, envelope.encrypt_keys) self.assertEqual(gpg_key, envelope.encrypt_keys[FPR])
def apply(self, ui): envelope = ui.current_buffer.envelope if self.action == 'rmencrypt': try: for keyid in self.encrypt_keys: tmp_key = crypto.get_key(keyid) del envelope.encrypt_keys[crypto.hash_key(tmp_key)] except GPGProblem as e: ui.notify(e.message, priority='error') if not envelope.encrypt_keys: envelope.encrypt = False ui.current_buffer.rebuild() return elif self.action == 'encrypt': encrypt = True elif self.action == 'unencrypt': encrypt = False elif self.action == 'toggleencrypt': encrypt = not envelope.encrypt envelope.encrypt = encrypt if encrypt: if not self.encrypt_keys: for recipient in envelope.headers['To'][0].split(','): if not recipient: continue match = re.search("<(.*@.*)>", recipient) if match: recipient = match.group(0) self.encrypt_keys.append(recipient) logging.debug("encryption keys: " + str(self.encrypt_keys)) for keyid in self.encrypt_keys: try: key = crypto.get_key(keyid, validate=True, encrypt=True) except GPGProblem as e: if e.code == GPGCode.AMBIGUOUS_NAME: possible_keys = crypto.list_keys(hint=keyid) tmp_choices = [k.uids[0].uid for k in possible_keys]
async def test_get_keys_ambiguous(self): """Test gettings keys when when the key is ambiguous.""" key = crypto.get_key( FPR, validate=True, encrypt=True, signed_only=False) ui = utilities.make_ui() # Creat a ui.choice object that can satisfy asyncio, but can also be # queried for calls as a mock async def choice(*args, **kwargs): return None ui.choice = mock.Mock(wraps=choice) ids = [FPR] with mock.patch('alot.commands.utils.crypto.get_key', mock.Mock(side_effect=errors.GPGProblem( 'test', errors.GPGCode.AMBIGUOUS_NAME))): with mock.patch('alot.commands.utils.crypto.list_keys', mock.Mock(return_value=[key])): await utils._get_keys(ui, ids, signed_only=False) ui.choice.assert_called_once()
def get_keys(ui, encrypt_keyids, block_error=False): keys = {} for keyid in encrypt_keyids: try: key = crypto.get_key(keyid, validate=True, encrypt=True) except GPGProblem as e: if e.code == GPGCode.AMBIGUOUS_NAME: possible_keys = crypto.list_keys(hint=keyid) tmp_choices = [k.uids[0].uid for k in possible_keys] choices = {str(len(tmp_choices) - x): tmp_choices[x] for x in range(0, len(tmp_choices))} keyid = yield ui.choice("ambiguous keyid! Which " + "key do you want to use?", choices, cancel=None) if keyid: encrypt_keyids.append(keyid) continue else: ui.notify(e.message, priority='error', block=block_error) continue keys[crypto.hash_key(key)] = key returnValue(keys)
def apply(self, ui): envelope = ui.current_buffer.envelope if self.action == 'rmencrypt': try: for keyid in self.encrypt_keys: tmp_key = crypto.get_key(keyid) del envelope.encrypt_keys[crypto.hash_key(tmp_key)] except GPGProblem as e: ui.notify(e.message, priority='error') if not envelope.encrypt_keys: envelope.encrypt = False ui.current_buffer.rebuild() return elif self.action == 'encrypt': encrypt = True elif self.action == 'unencrypt': encrypt = False elif self.action == 'toggleencrypt': encrypt = not envelope.encrypt envelope.encrypt = encrypt if encrypt: if not self.encrypt_keys: for recipient in envelope.headers['To'][0].split(','): if not recipient: continue match = re.search("<(.*@.*)>", recipient) if match: recipient = match.group(0) self.encrypt_keys.append(recipient) logging.debug("encryption keys: " + str(self.encrypt_keys)) keys = yield get_keys(ui, self.encrypt_keys) if keys: envelope.encrypt_keys.update(keys) else: envelope.encrypt = False # reload buffer ui.current_buffer.rebuild()
def get_keys(ui, encrypt_keyids, block_error=False): """Get several keys from the GPG keyring. The keys are selected by keyid and are checked if they can be used for encryption. :param ui: the main user interface object :type ui: alot.ui.UI :param encrypt_keyids: the key ids of the keys to get :type encrypt_keyids: list(str) :param block_error: wether error messages for the user should expire automatically or block the ui :type block_error: bool :returns: the available keys indexed by their key hash :rtype: dict(str->gpgme.Key) """ keys = {} for keyid in encrypt_keyids: try: key = crypto.get_key(keyid, validate=True, encrypt=True) except GPGProblem as e: if e.code == GPGCode.AMBIGUOUS_NAME: possible_keys = crypto.list_keys(hint=keyid) tmp_choices = [k.uids[0].uid for k in possible_keys] choices = {str(len(tmp_choices) - x): tmp_choices[x] for x in range(0, len(tmp_choices))} keyid = yield ui.choice("ambiguous keyid! Which " + "key do you want to use?", choices, cancel=None) if keyid: encrypt_keyids.append(keyid) continue else: ui.notify(e.message, priority='error', block=block_error) continue keys[crypto.hash_key(key)] = key returnValue(keys)
def apply(self, ui): sign = None key = None envelope = ui.current_buffer.envelope # sign status if self.action == 'sign': sign = True elif self.action == 'unsign': sign = False elif self.action == 'toggle': sign = not envelope.sign envelope.sign = sign # try to find key if hint given as parameter if sign: if len(self.keyid) > 0: keyid = str(' '.join(self.keyid)) try: key = crypto.get_key(keyid) except GPGProblem, e: envelope.sign = False ui.notify(e.message, priority='error') return envelope.sign_key = key
def test_decrypt(self): to_encrypt = "this is a string\nof data." encrypted = crypto.encrypt(to_encrypt, keys=[crypto.get_key(FPR)]) _, dec = crypto.decrypt_verify(encrypted) self.assertEqual(to_encrypt, dec)
def test_signed_only_false(self): with self.assertRaises(GPGProblem) as e: crypto.get_key(FPR, signed_only=True) self.assertEqual(e.exception.code, GPGCode.NOT_FOUND)
def test_signed_only_true(self): try: crypto.get_key(FPR, signed_only=True) except GPGProblem as e: raise AssertionError(e)
def test_invalid_key(self): with self.assertRaises(GPGProblem) as caught: crypto.get_key('z') self.assertEqual(caught.exception.code, GPGCode.NOT_FOUND)
def test_missing_key(self): with self.assertRaises(GPGProblem) as caught: crypto.get_key('*****@*****.**') self.assertEqual(caught.exception.code, GPGCode.NOT_FOUND)
def test_plain(self): # Test the uid of the only identity attached to the key we generated. with gpg.core.Context() as ctx: expected = ctx.get_key(FPR).uids[0].uid actual = crypto.get_key(FPR).uids[0].uid self.assertEqual(expected, actual)
def test_decrypt(self): to_encrypt = b"this is a string\nof data." encrypted = crypto.encrypt(to_encrypt, keys=[crypto.get_key(FPR)]) _, dec = crypto.decrypt_verify(encrypted) self.assertEqual(to_encrypt, dec)