plugin XEP-0115: Fix disco duplicate on caps node query + check own generation:
When caps node was requested, disco infos was returned from cache + infos from normal disco gathering, resulting in doubled items and other entities rejecting the disco info. This is fixed by subclassing the disco handler to add a trigger. This trigger is used by XEP-0115 to short circuit the disco gathering and returned its cached data instead. Our own hash is re-generated on each connection, and validated, so if there is a bug, this helps see and catch it.
This commit is contained in:
parent
58834f15ae
commit
18d3f0167f
3 changed files with 109 additions and 47 deletions
|
|
@ -146,10 +146,8 @@ class TestXEP0115Handler:
|
|||
assert disco.DiscoFeature(NS_ENTITY_CAPABILITY) in result
|
||||
assert disco.DiscoFeature(NS_CAPS_OPTIMIZE) in result
|
||||
|
||||
def test_getDiscoInfo_caps_node_query(self, host, xep_0115):
|
||||
"""getDiscoInfo returns cached disco info for caps node queries."""
|
||||
handler = xep_0115.get_handler(MagicMock())
|
||||
|
||||
def test_disco_info_trigger_caps_node_query(self, host, xep_0115):
|
||||
"""_disco_info_trigger returns cached disco info for caps node queries."""
|
||||
# Create and cache some disco info
|
||||
disco_infos = disco.DiscoInfo()
|
||||
disco_infos.append(disco.DiscoIdentity("client", "pc", "Test Client"))
|
||||
|
|
@ -161,9 +159,14 @@ class TestXEP0115Handler:
|
|||
|
||||
# Query with caps node format
|
||||
node_identifier = f"{C.APP_URL}#{cap_hash}"
|
||||
result = handler.getDiscoInfo(MagicMock(), MagicMock(), node_identifier)
|
||||
cont, deferred = xep_0115._disco_info_trigger(
|
||||
MagicMock(), MagicMock(), node_identifier
|
||||
)
|
||||
|
||||
# Should return the cached disco info items
|
||||
# Should not continue, return cached disco info
|
||||
assert cont is False
|
||||
assert deferred is not None
|
||||
result = deferred.result
|
||||
assert len(result) > 0
|
||||
assert any(isinstance(item, disco.DiscoIdentity) for item in result)
|
||||
assert any(isinstance(item, disco.DiscoFeature) for item in result)
|
||||
|
|
@ -177,17 +180,26 @@ class TestXEP0115Handler:
|
|||
assert disco.DiscoFeature("http://jabber.org/protocol/caps") in features
|
||||
assert disco.DiscoFeature("http://jabber.org/protocol/disco#info") in features
|
||||
|
||||
def test_getDiscoInfo_unknown_caps_node(self, xep_0115):
|
||||
"""getDiscoInfo returns caps features for unknown caps nodes."""
|
||||
handler = xep_0115.get_handler(MagicMock())
|
||||
|
||||
def test_disco_info_trigger_unknown_caps_node(self, xep_0115):
|
||||
"""_disco_info_trigger lets unknown caps nodes pass through."""
|
||||
# Query with unknown hash
|
||||
node_identifier = f"{C.APP_URL}#unknownhash123"
|
||||
result = handler.getDiscoInfo(MagicMock(), MagicMock(), node_identifier)
|
||||
cont, deferred = xep_0115._disco_info_trigger(
|
||||
MagicMock(), MagicMock(), node_identifier
|
||||
)
|
||||
|
||||
# Should return just the caps features, not cached info
|
||||
assert disco.DiscoFeature(NS_ENTITY_CAPABILITY) in result
|
||||
assert disco.DiscoFeature(NS_CAPS_OPTIMIZE) in result
|
||||
# Should continue, let normal flow proceed
|
||||
assert cont is True
|
||||
assert deferred is None
|
||||
|
||||
def test_disco_info_trigger_non_caps_node(self, xep_0115):
|
||||
"""_disco_info_trigger ignores non-caps nodes."""
|
||||
cont, deferred = xep_0115._disco_info_trigger(
|
||||
MagicMock(), MagicMock(), "some:other:node"
|
||||
)
|
||||
|
||||
assert cont is True
|
||||
assert deferred is None
|
||||
|
||||
def test_getDiscoItems_empty(self, xep_0115):
|
||||
"""getDiscoItems returns empty list (caps nodes are virtual)."""
|
||||
|
|
|
|||
Loading…
Reference in a new issue