fix: more issue #112 follow-ups (stanza-id disco gate, account sanitizer)
All checks were successful
CI Code / Check spelling (pull_request) Successful in 19s
CI Code / Check coding style (pull_request) Successful in 32s
CI Code / Linux (debian) (pull_request) Successful in 4m50s
CI Code / Linux (ubuntu) (pull_request) Successful in 5m7s
CI Code / Code Coverage (pull_request) Successful in 7m14s
CI Code / Linux (arch) (pull_request) Successful in 10m31s
All checks were successful
CI Code / Check spelling (pull_request) Successful in 19s
CI Code / Check coding style (pull_request) Successful in 32s
CI Code / Linux (debian) (pull_request) Successful in 4m50s
CI Code / Linux (ubuntu) (pull_request) Successful in 5m7s
CI Code / Code Coverage (pull_request) Successful in 7m14s
CI Code / Linux (arch) (pull_request) Successful in 10m31s
- xmpp: gate XEP-0359 stanza-id dedup on disco urn:xmpp:sid:0. Before honoring <stanza-id by='…'/> for archive_id dedup, check that the entity in `by` (or its domain — that's what profanity disco's on connect) announces the namespace; fall back to no-dedup when caps are unknown, matching the XEP §6 disco-gate (#1). - accounts: narrow group-name sanitizer to only the characters GKeyFile actually forbids in group headers (`[`, `]`, `\n`, `\r`); `=` and `#` are valid inside a header and stay (#2). - functional tests cover both branches of the disco gate — replayed stanza-id is flagged as duplicate when sid:0 is announced, and not flagged when it isn't. Refs #112
This commit is contained in:
@@ -43,8 +43,8 @@ _sanitize_account_name(const char* const name)
|
|||||||
gchar* sanitized = g_strdup(name);
|
gchar* sanitized = g_strdup(name);
|
||||||
gchar* p = sanitized;
|
gchar* p = sanitized;
|
||||||
while (*p) {
|
while (*p) {
|
||||||
// GKeyFile special characters: [ ] = # \n \r
|
// GKeyFile group header forbids these characters.
|
||||||
if (*p == '[' || *p == ']' || *p == '=' || *p == '#' || *p == '\n' || *p == '\r') {
|
if (*p == '[' || *p == ']' || *p == '\n' || *p == '\r') {
|
||||||
*p = '_';
|
*p = '_';
|
||||||
}
|
}
|
||||||
p++;
|
p++;
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ static void _handle_pubsub(xmpp_stanza_t* const stanza, xmpp_stanza_t* const eve
|
|||||||
static gboolean _handle_form(xmpp_stanza_t* const stanza);
|
static gboolean _handle_form(xmpp_stanza_t* const stanza);
|
||||||
static gboolean _handle_jingle_message(xmpp_stanza_t* const stanza);
|
static gboolean _handle_jingle_message(xmpp_stanza_t* const stanza);
|
||||||
static gboolean _should_ignore_based_on_silence(xmpp_stanza_t* const stanza);
|
static gboolean _should_ignore_based_on_silence(xmpp_stanza_t* const stanza);
|
||||||
|
static gboolean _stanza_id_by_trusted(const char* by);
|
||||||
#ifdef HAVE_OMEMO
|
#ifdef HAVE_OMEMO
|
||||||
static void _receive_omemo(xmpp_stanza_t* const stanza, ProfMessage* message);
|
static void _receive_omemo(xmpp_stanza_t* const stanza, ProfMessage* message);
|
||||||
#endif
|
#endif
|
||||||
@@ -1088,7 +1089,7 @@ _handle_groupchat(xmpp_stanza_t* const stanza)
|
|||||||
xmpp_stanza_t* stanzaidst = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_STANZA_ID, STANZA_NS_STABLE_ID);
|
xmpp_stanza_t* stanzaidst = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_STANZA_ID, STANZA_NS_STABLE_ID);
|
||||||
if (stanzaidst) {
|
if (stanzaidst) {
|
||||||
const char* by = xmpp_stanza_get_attribute(stanzaidst, "by");
|
const char* by = xmpp_stanza_get_attribute(stanzaidst, "by");
|
||||||
if (by && (g_strcmp0(by, from_jid->barejid) == 0)) {
|
if (by && g_strcmp0(by, from_jid->barejid) == 0 && _stanza_id_by_trusted(by)) {
|
||||||
stanzaid = (char*)xmpp_stanza_get_attribute(stanzaidst, STANZA_ATTR_ID);
|
stanzaid = (char*)xmpp_stanza_get_attribute(stanzaidst, STANZA_ATTR_ID);
|
||||||
if (stanzaid) {
|
if (stanzaid) {
|
||||||
message->stanzaid = strdup(stanzaid);
|
message->stanzaid = strdup(stanzaid);
|
||||||
@@ -1397,7 +1398,7 @@ _handle_chat(xmpp_stanza_t* const stanza, gboolean is_mam, gboolean is_carbon, c
|
|||||||
xmpp_stanza_t* stanzaidst = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_STANZA_ID, STANZA_NS_STABLE_ID);
|
xmpp_stanza_t* stanzaidst = xmpp_stanza_get_child_by_name_and_ns(stanza, STANZA_NAME_STANZA_ID, STANZA_NS_STABLE_ID);
|
||||||
if (stanzaidst) {
|
if (stanzaidst) {
|
||||||
const char* by = xmpp_stanza_get_attribute(stanzaidst, "by");
|
const char* by = xmpp_stanza_get_attribute(stanzaidst, "by");
|
||||||
if (by && equals_our_barejid(by)) {
|
if (by && equals_our_barejid(by) && _stanza_id_by_trusted(by)) {
|
||||||
stanzaid = (char*)xmpp_stanza_get_attribute(stanzaidst, STANZA_ATTR_ID);
|
stanzaid = (char*)xmpp_stanza_get_attribute(stanzaidst, STANZA_ATTR_ID);
|
||||||
if (stanzaid) {
|
if (stanzaid) {
|
||||||
message->stanzaid = strdup(stanzaid);
|
message->stanzaid = strdup(stanzaid);
|
||||||
@@ -1735,3 +1736,22 @@ _should_ignore_based_on_silence(xmpp_stanza_t* const stanza)
|
|||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XEP-0359 §6 disco-gate; falls back to domain since that's what disco is run against.
|
||||||
|
static gboolean
|
||||||
|
_stanza_id_by_trusted(const char* by)
|
||||||
|
{
|
||||||
|
if (!by) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
GHashTable* features = connection_get_features(by);
|
||||||
|
if (features && g_hash_table_contains(features, STANZA_NS_STABLE_ID)) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
const char* at = strchr(by, '@');
|
||||||
|
if (!at) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
features = connection_get_features(at + 1);
|
||||||
|
return features && g_hash_table_contains(features, STANZA_NS_STABLE_ID);
|
||||||
|
}
|
||||||
|
|||||||
@@ -253,6 +253,10 @@ main(int argc, char* argv[])
|
|||||||
PROF_FUNC_TEST(message_receive_console),
|
PROF_FUNC_TEST(message_receive_console),
|
||||||
PROF_FUNC_TEST(message_receive_chatwin),
|
PROF_FUNC_TEST(message_receive_chatwin),
|
||||||
|
|
||||||
|
/* XEP-0359 disco gate for stanza-id trust */
|
||||||
|
PROF_FUNC_TEST(stanza_id_dedup_fires_when_server_announces_sid0),
|
||||||
|
PROF_FUNC_TEST(stanza_id_not_trusted_when_server_does_not_announce_sid0),
|
||||||
|
|
||||||
#ifdef HAVE_SQLITE
|
#ifdef HAVE_SQLITE
|
||||||
/* MUC (groupchat) database — export/import of type="muc" messages */
|
/* MUC (groupchat) database — export/import of type="muc" messages */
|
||||||
PROF_FUNC_TEST(muc_export_sqlite_to_flatfile),
|
PROF_FUNC_TEST(muc_export_sqlite_to_flatfile),
|
||||||
|
|||||||
@@ -56,3 +56,70 @@ message_receive_chatwin(void **state)
|
|||||||
|
|
||||||
assert_true(prof_output_regex("someuser@chatserv.org/laptop: .+How are you?"));
|
assert_true(prof_output_regex("someuser@chatserv.org/laptop: .+How are you?"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XEP-0359 disco gate: server announces urn:xmpp:sid:0 -> stanza-id trusted -> replay flagged as duplicate.
|
||||||
|
void
|
||||||
|
stanza_id_dedup_fires_when_server_announces_sid0(void **state)
|
||||||
|
{
|
||||||
|
stbbr_for_query("http://jabber.org/protocol/disco#info",
|
||||||
|
"<iq type='result' to='stabber@localhost/profanity' from='localhost'>"
|
||||||
|
"<query xmlns='http://jabber.org/protocol/disco#info'>"
|
||||||
|
"<identity category='server' type='im' name='TestServer'/>"
|
||||||
|
"<feature var='urn:xmpp:sid:0'/>"
|
||||||
|
"</query>"
|
||||||
|
"</iq>"
|
||||||
|
);
|
||||||
|
|
||||||
|
prof_connect();
|
||||||
|
|
||||||
|
stbbr_send(
|
||||||
|
"<message id='m-trust-1' to='stabber@localhost' from='someuser@chatserv.org/laptop' type='chat'>"
|
||||||
|
"<body>first</body>"
|
||||||
|
"<stanza-id xmlns='urn:xmpp:sid:0' by='stabber@localhost' id='archive-id-42'/>"
|
||||||
|
"</message>"
|
||||||
|
);
|
||||||
|
assert_true(prof_output_exact("<< chat message: someuser@chatserv.org/laptop (win 2)"));
|
||||||
|
|
||||||
|
stbbr_send(
|
||||||
|
"<message id='m-trust-2' to='stabber@localhost' from='someuser@chatserv.org/laptop' type='chat'>"
|
||||||
|
"<body>replay</body>"
|
||||||
|
"<stanza-id xmlns='urn:xmpp:sid:0' by='stabber@localhost' id='archive-id-42'/>"
|
||||||
|
"</message>"
|
||||||
|
);
|
||||||
|
assert_true(prof_output_exact("Got a message with duplicate (server-generated) stanza-id from someuser@chatserv.org/laptop."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// XEP-0359 disco gate: server does NOT announce urn:xmpp:sid:0 -> stanza-id untrusted -> no replay error.
|
||||||
|
void
|
||||||
|
stanza_id_not_trusted_when_server_does_not_announce_sid0(void **state)
|
||||||
|
{
|
||||||
|
stbbr_for_query("http://jabber.org/protocol/disco#info",
|
||||||
|
"<iq type='result' to='stabber@localhost/profanity' from='localhost'>"
|
||||||
|
"<query xmlns='http://jabber.org/protocol/disco#info'>"
|
||||||
|
"<identity category='server' type='im' name='TestServer'/>"
|
||||||
|
"<feature var='urn:xmpp:ping'/>"
|
||||||
|
"</query>"
|
||||||
|
"</iq>"
|
||||||
|
);
|
||||||
|
|
||||||
|
prof_connect();
|
||||||
|
|
||||||
|
stbbr_send(
|
||||||
|
"<message id='m-untrust-1' to='stabber@localhost' from='someuser@chatserv.org/laptop' type='chat'>"
|
||||||
|
"<body>first</body>"
|
||||||
|
"<stanza-id xmlns='urn:xmpp:sid:0' by='stabber@localhost' id='archive-id-77'/>"
|
||||||
|
"</message>"
|
||||||
|
);
|
||||||
|
assert_true(prof_output_exact("<< chat message: someuser@chatserv.org/laptop (win 2)"));
|
||||||
|
|
||||||
|
stbbr_send(
|
||||||
|
"<message id='m-untrust-2' to='stabber@localhost' from='someuser@chatserv.org/laptop' type='chat'>"
|
||||||
|
"<body>replay</body>"
|
||||||
|
"<stanza-id xmlns='urn:xmpp:sid:0' by='stabber@localhost' id='archive-id-77'/>"
|
||||||
|
"</message>"
|
||||||
|
);
|
||||||
|
|
||||||
|
prof_timeout(2);
|
||||||
|
assert_false(prof_output_exact("Got a message with duplicate (server-generated) stanza-id"));
|
||||||
|
prof_timeout_reset();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
void message_send(void **state);
|
void message_send(void **state);
|
||||||
void message_receive_console(void **state);
|
void message_receive_console(void **state);
|
||||||
void message_receive_chatwin(void **state);
|
void message_receive_chatwin(void **state);
|
||||||
|
void stanza_id_dedup_fires_when_server_announces_sid0(void **state);
|
||||||
|
void stanza_id_not_trusted_when_server_does_not_announce_sid0(void **state);
|
||||||
|
|||||||
Reference in New Issue
Block a user