From f0a4bcf10c1bc29124bcbc15ef035c20f94e4561 Mon Sep 17 00:00:00 2001 From: Martin Dosch Date: Tue, 26 Jul 2022 22:28:04 +0200 Subject: [PATCH] Reply to IQs. --- CHANGELOG.md | 4 ++ const.go | 1 + iqhandling.go | 35 ------------- main.go | 17 ------- stanzahandling.go | 127 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+), 52 deletions(-) delete mode 100644 iqhandling.go create mode 100644 stanzahandling.go diff --git a/CHANGELOG.md b/CHANGELOG.md index a04b0f3..bf5e947 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog ## Unreleased +### Added +- Reply to `disco#info` queries. +- Send `service-unavailable` errors for all other IQs of type `get` and `set`. + ### Changed - Ox: Improve error messages for failed key requests. - Ox: Do not encrypt empty messages. diff --git a/const.go b/const.go index 871ae69..4a37c4b 100644 --- a/const.go +++ b/const.go @@ -17,6 +17,7 @@ const ( nsOxPubKeys = "urn:xmpp:openpgp:0:public-keys" nsPubsub = "http://jabber.org/protocol/pubsub" nsPubsubOwner = "http://jabber.org/protocol/pubsub#owner" + nsXMPPStanzas = "xmlns='urn:ietf:params:xml:ns:xmpp-stanzas" oxAltBody = "This message is encrypted (XEP-0373: OpenPGP for XMPP)." pubsubPubOptions = "http://jabber.org/protocol/pubsub#publish-options" ) diff --git a/iqhandling.go b/iqhandling.go deleted file mode 100644 index 9fbcf41..0000000 --- a/iqhandling.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2020 - 2021 Martin Dosch. -// Use of this source code is governed by the BSD-2-clause -// license that can be found in the LICENSE file. - -package main - -import ( - "github.com/mattn/go-xmpp" // BSD-3-Clause -) - -func sendIQ(client *xmpp.Client, iqc chan xmpp.IQ, target string, - iQtype string, content string) (xmpp.IQ, error) { - var iq xmpp.IQ - id := getID() - c := make(chan xmpp.IQ) - go getIQ(client, id, c, iqc) - _, err := client.RawInformation(client.JID(), target, id, - iQtype, content + "\n") - if err != nil { - return iq, err - } - iq = <-c - return iq, nil -} - -func getIQ(client *xmpp.Client, id string, c chan xmpp.IQ, - iqc chan xmpp.IQ) { - for { - iq := <-iqc - if iq.ID == id { - c <- iq - return - } - } -} diff --git a/main.go b/main.go index f8c49c0..a8235f4 100644 --- a/main.go +++ b/main.go @@ -29,23 +29,6 @@ type configuration struct { resource string } -func rcvStanzas(client *xmpp.Client, iqc chan xmpp.IQ, msgc chan xmpp.Chat) { - for { - received, err := client.Recv() - if err != nil { - log.Println(err) - } - switch v := received.(type) { - case xmpp.Chat: - msgc <- v - case xmpp.IQ: - iqc <- v - case xmpp.Presence: - default: - } - } -} - func readMessage(messageFilePath string) (string, error) { var ( output string diff --git a/stanzahandling.go b/stanzahandling.go new file mode 100644 index 0000000..00fc705 --- /dev/null +++ b/stanzahandling.go @@ -0,0 +1,127 @@ +// Copyright 2020 - 2021 Martin Dosch. +// Use of this source code is governed by the BSD-2-clause +// license that can be found in the LICENSE file. + +package main + +import ( + "log" + + "github.com/beevik/etree" // BSD-2-clause + "github.com/mattn/go-xmpp" // BSD-3-Clause +) + +func sendIQ(client *xmpp.Client, iqc chan xmpp.IQ, target string, + iQtype string, content string) (xmpp.IQ, error) { + var iq xmpp.IQ + id := getID() + c := make(chan xmpp.IQ) + go getIQ(client, id, c, iqc) + _, err := client.RawInformation(client.JID(), target, id, + iQtype, content+"\n") + if err != nil { + return iq, err + } + iq = <-c + return iq, nil +} + +func getIQ(client *xmpp.Client, id string, c chan xmpp.IQ, + iqc chan xmpp.IQ) { + for { + iq := <-iqc + if iq.ID == id { + c <- iq + return + } + } +} + +func rcvStanzas(client *xmpp.Client, iqc chan xmpp.IQ, msgc chan xmpp.Chat) { + for { + received, err := client.Recv() + if err != nil { + log.Println(err) + } + switch v := received.(type) { + case xmpp.Chat: + msgc <- v + case xmpp.IQ: + switch v.Type { + case "get": + iq := etree.NewDocument() + err = iq.ReadFromBytes(v.Query) + if err != nil { + log.Println("Couldn't parse IQ:", + string(v.Query), err) + } + query := iq.SelectElement("query") + xmlns := query.SelectAttr("xmlns") + switch xmlns.Value { + case nsDiscoInfo: + root := etree.NewDocument() + reply := root.CreateElement("iq") + reply.CreateAttr("type", "result") + reply.CreateAttr("from", client.JID()) + reply.CreateAttr("to", v.From) + reply.CreateAttr("id", v.ID) + replyQuery := reply.CreateElement("query") + replyQuery.CreateAttr("xmlns", nsDiscoInfo) + identity := replyQuery.CreateElement("identity") + identity.CreateAttr("category", "client") + identity.CreateAttr("type", "bot") + identity.CreateAttr("name", "go-sendxmpp") + feat := replyQuery.CreateElement("feature") + feat.CreateAttr("var", nsDiscoInfo) + xmlString, err := root.WriteToString() + if err == nil { + _, err = client.SendOrg(xmlString) + if err != nil { + log.Println(err) + } + } + default: + root := etree.NewDocument() + reply := root.CreateElement("iq") + reply.CreateAttr("type", "error") + reply.CreateAttr("from", client.JID()) + reply.CreateAttr("to", v.From) + reply.CreateAttr("id", v.ID) + errorReply := reply.CreateElement("error") + errorReply.CreateAttr("type", "cancel") + su := errorReply.CreateElement("service-unavailable") + su.CreateAttr("xmlns", nsXMPPStanzas) + xmlString, err := root.WriteToString() + if err == nil { + _, err = client.SendOrg(xmlString) + if err != nil { + log.Println(err) + } + } + } + case "set": + root := etree.NewDocument() + reply := root.CreateElement("iq") + reply.CreateAttr("type", "error") + reply.CreateAttr("from", client.JID()) + reply.CreateAttr("to", v.From) + reply.CreateAttr("id", v.ID) + errorReply := reply.CreateElement("error") + errorReply.CreateAttr("type", "cancel") + su := errorReply.CreateElement("service-unavailable") + su.CreateAttr("xmlns", nsXMPPStanzas) + xmlString, err := root.WriteToString() + if err == nil { + _, err = client.SendOrg(xmlString) + if err != nil { + log.Println(err) + } + } + case "reply", "error": + iqc <- v + default: + iqc <- v + } + } + } +}