parsers: Add Confirm from XEP-0070

PulkoMandy created

Change summary

parsers/ChangeLog      |  1 
parsers/src/confirm.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++
parsers/src/lib.rs     |  3 +
parsers/src/ns.rs      |  3 +
4 files changed, 91 insertions(+)

Detailed changes

parsers/ChangeLog 🔗

@@ -107,6 +107,7 @@ XXXX-YY-ZZ RELEASER <admin@example.com>
       - XEP-0045 mediated invites
       - Push Notifications (XEP-0357) (!543)
       - JSON Containers (XEP-0335) (!546)
+      - Verifying HTTP Requests via XMPP (XEP-0070)
     * Improvements:
       - Add support application-specific error conditions in XEP-0198
       - Keep unsupported vCard elements as `minidom::Element`, so that they

parsers/src/confirm.rs 🔗

@@ -0,0 +1,84 @@
+// Copyright (c) 2025 Adrien Destugues <pulkomandy@pulkomandy.tk>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+use xso::{AsXml, FromXml};
+
+use crate::iq::IqGetPayload;
+use crate::message::MessagePayload;
+use crate::ns;
+
+/// XEP-0070 "confirm" element used to request user confirmation before accessing a protected
+/// HTTP resource, or as a reply to such request.
+///
+/// This can be used as:
+/// - A message payload (when the request is sent to a bare JID or when receiving the reply)
+/// - A Set Iq payload (when the request is sent to a full JID as an Iq). The confirm element may
+///   also be present in responses, but should be ignored (the IQ id is used to identify the
+///   request in that case).
+#[derive(FromXml, AsXml, PartialEq, Eq, Hash, Debug, Clone)]
+#[xml(namespace = ns::HTTP_AUTH, name = "confirm")]
+pub struct Confirm {
+    /// HTTP method used to access the resource
+    #[xml(attribute)]
+    pub method: String,
+
+    /// URL being accessed and guarded by the authentication request
+    #[xml(attribute)]
+    pub url: String,
+
+    /// Identifier of the authentication request
+    #[xml(attribute)]
+    pub id: String,
+}
+
+impl IqGetPayload for Confirm {}
+impl MessagePayload for Confirm {}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::ns;
+    use minidom::Element;
+
+    #[cfg(target_pointer_width = "32")]
+    #[test]
+    fn test_size() {
+        assert_size!(Confirm, 36);
+    }
+
+    #[cfg(target_pointer_width = "64")]
+    #[test]
+    fn test_size() {
+        assert_size!(Confirm, 72);
+    }
+
+    #[test]
+    fn test_simple() {
+        let elem: Element = "<confirm xmlns='http://jabber.org/protocol/http-auth' \
+            id='a7374jnjlalasdf82' method='GET' \
+            url='https://files.shakespeare.lit:9345/missive.html'/>"
+            .parse()
+            .unwrap();
+        let confirm = Confirm::try_from(elem).unwrap();
+        assert_eq!(confirm.method, "GET");
+        assert_eq!(confirm.id, "a7374jnjlalasdf82");
+        assert_eq!(
+            confirm.url,
+            "https://files.shakespeare.lit:9345/missive.html"
+        );
+    }
+
+    #[test]
+    fn test_serialise() {
+        let confirm = Confirm {
+            method: "GET".to_string(),
+            url: "https://files.shakespeare.lit/".to_string(),
+            id: "sesame".to_string(),
+        };
+        let elem: Element = confirm.into();
+        assert!(elem.is("confirm", ns::HTTP_AUTH));
+    }
+}

parsers/src/lib.rs 🔗

@@ -101,6 +101,9 @@ pub mod pubsub;
 /// XEP-0066: OOB
 pub mod oob;
 
+/// XEP-0070: Verifying HTTP Requests via XMPP
+pub mod confirm;
+
 /// XEP-0071: XHTML-IM
 pub mod xhtml;
 

parsers/src/ns.rs 🔗

@@ -68,6 +68,9 @@ pub const PUBSUB_CONFIGURE: &str = "http://jabber.org/protocol/pubsub#node_confi
 /// XEP-0066: Out of Band Data
 pub const OOB: &str = "jabber:x:oob";
 
+/// XEP-0070: Verifying HTTP Requests via XMPP
+pub const HTTP_AUTH: &str = "http://jabber.org/protocol/http-auth";
+
 /// XEP-0071: XHTML-IM
 pub const XHTML_IM: &str = "http://jabber.org/protocol/xhtml-im";
 /// XEP-0071: XHTML-IM