comparison sat/plugins/plugin_xep_0373.py @ 3942:a92eef737703

plugin XEP-0373: download public keys if they are not found in local storage: public keys were only obtained from PEP notifications, however this wasn't working if the entity was not in our roster. Now if no public key is retrieved from local storage, the public key node is requested, and an error is raised if nothing is found. This allows the use of OX with entities which are not in roster. rel 380
author Goffi <goffi@goffi.org>
date Sat, 15 Oct 2022 20:38:33 +0200
parents cecf45416403
children 1ab16449577b
comparison
equal deleted inserted replaced
3941:036188fff714 3942:a92eef737703
97 NS_OX: Final = "urn:xmpp:openpgp:0" 97 NS_OX: Final = "urn:xmpp:openpgp:0"
98 98
99 99
100 PARAM_CATEGORY = "Security" 100 PARAM_CATEGORY = "Security"
101 PARAM_NAME = "ox_policy" 101 PARAM_NAME = "ox_policy"
102 STR_KEY_PUBLIC_KEYS_METADATA = "/public-keys-metadata/{}"
102 103
103 104
104 class VerificationError(Exception): 105 class VerificationError(Exception):
105 """ 106 """
106 Raised by verifying methods of :class:`XEP_0373` on semantical verification errors. 107 Raised by verifying methods of :class:`XEP_0373` on semantical verification errors.
1094 new_public_keys_metadata = { PublicKeyMetadata( 1095 new_public_keys_metadata = { PublicKeyMetadata(
1095 fingerprint=cast(str, pubkey_metadata_elt["v4-fingerprint"]), 1096 fingerprint=cast(str, pubkey_metadata_elt["v4-fingerprint"]),
1096 timestamp=parse_datetime(cast(str, pubkey_metadata_elt["date"])) 1097 timestamp=parse_datetime(cast(str, pubkey_metadata_elt["date"]))
1097 ) for pubkey_metadata_elt in pubkey_metadata_elts } 1098 ) for pubkey_metadata_elt in pubkey_metadata_elts }
1098 1099
1099 storage_key = f"/public-keys-metadata/{sender.userhost()}" 1100 storage_key = STR_KEY_PUBLIC_KEYS_METADATA.format(sender.userhost())
1100 1101
1101 local_public_keys_metadata = cast( 1102 local_public_keys_metadata = cast(
1102 Set[PublicKeyMetadata], 1103 Set[PublicKeyMetadata],
1103 await self.__storage[profile].get(storage_key, set()) 1104 await self.__storage[profile].get(storage_key, set())
1104 ) 1105 )
1183 1184
1184 secret_key = gpg_provider.create_key(f"xmpp:{client.jid.userhost()}") 1185 secret_key = gpg_provider.create_key(f"xmpp:{client.jid.userhost()}")
1185 1186
1186 await self.publish_public_key(client, secret_key.public_key) 1187 await self.publish_public_key(client, secret_key.public_key)
1187 1188
1188 storage_key = f"/public-keys-metadata/{client.jid.userhost()}" 1189 storage_key = STR_KEY_PUBLIC_KEYS_METADATA.format(client.jid.userhost())
1189 1190
1190 public_keys_list = cast( 1191 public_keys_list = cast(
1191 Set[PublicKeyMetadata], 1192 Set[PublicKeyMetadata],
1192 await self.__storage[client.profile].get(storage_key, set()) 1193 await self.__storage[client.profile].get(storage_key, set())
1193 ) 1194 )
1487 raise XMPPInteractionFailed("Publishing the public key failed.") from e 1488 raise XMPPInteractionFailed("Publishing the public key failed.") from e
1488 1489
1489 async def import_all_public_keys( 1490 async def import_all_public_keys(
1490 self, 1491 self,
1491 client: SatXMPPClient, 1492 client: SatXMPPClient,
1492 jid: jid.JID 1493 entity_jid: jid.JID
1493 ) -> Set[GPGPublicKey]: 1494 ) -> Set[GPGPublicKey]:
1494 """Import all public keys of a JID that have not been imported before. 1495 """Import all public keys of a JID that have not been imported before.
1495 1496
1496 @param client: The client. 1497 @param client: The client.
1497 @param jid: The JID. Can be a bare JID. 1498 @param jid: The JID. Can be a bare JID.
1498 @return: The public keys. 1499 @return: The public keys.
1499 @note: Failure to import a key simply results in the key not being included in the 1500 @note: Failure to import a key simply results in the key not being included in the
1500 result. 1501 result.
1501 """ 1502 """
1502 1503
1503 available_public_keys = self.list_public_keys(client, jid) 1504 available_public_keys = self.list_public_keys(client, entity_jid)
1504 1505
1505 storage_key = f"/public-keys-metadata/{jid.userhost()}" 1506 storage_key = STR_KEY_PUBLIC_KEYS_METADATA.format(entity_jid.userhost())
1506 1507
1507 public_keys_metadata = cast( 1508 public_keys_metadata = cast(
1508 Set[PublicKeyMetadata], 1509 Set[PublicKeyMetadata],
1509 await self.__storage[client.profile].get(storage_key, set()) 1510 await self.__storage[client.profile].get(storage_key, set())
1510 ) 1511 )
1512 if not public_keys_metadata:
1513 public_keys_metadata = await self.download_public_keys_list(
1514 client, entity_jid
1515 )
1516 if not public_keys_metadata:
1517 raise exceptions.NotFound(
1518 f"Can't find public keys for {entity_jid}"
1519 )
1520 else:
1521 await self.__storage[client.profile].aset(
1522 storage_key, public_keys_metadata
1523 )
1524
1511 1525
1512 missing_keys = set(filter(lambda public_key_metadata: all( 1526 missing_keys = set(filter(lambda public_key_metadata: all(
1513 public_key_metadata.fingerprint != public_key.fingerprint 1527 public_key_metadata.fingerprint != public_key.fingerprint
1514 for public_key 1528 for public_key
1515 in available_public_keys 1529 in available_public_keys
1516 ), public_keys_metadata)) 1530 ), public_keys_metadata))
1517 1531
1518 for missing_key in missing_keys: 1532 for missing_key in missing_keys:
1519 try: 1533 try:
1520 available_public_keys.add( 1534 available_public_keys.add(
1521 await self.import_public_key(client, jid, missing_key.fingerprint) 1535 await self.import_public_key(client, entity_jid, missing_key.fingerprint)
1522 ) 1536 )
1523 except Exception as e: 1537 except Exception as e:
1524 log.warning( 1538 log.warning(
1525 f"Import of public key {missing_key.fingerprint} owned by" 1539 f"Import of public key {missing_key.fingerprint} owned by"
1526 f" {jid.userhost()} failed, ignoring: {e}" 1540 f" {entity_jid.userhost()} failed, ignoring: {e}"
1527 ) 1541 )
1528 1542
1529 return available_public_keys 1543 return available_public_keys
1530 1544
1531 async def import_public_key( 1545 async def import_public_key(