diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a095d9..72b4928 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Always look up CNAME before doing SRV lookups (via xmppsrv v0.2.3). - Detect CNAME loops (max. 5 CNAMEs) (via xmppsrv >= v0.2.4). - Deprecate resource config option and command line flag. +- Improve error handling in XML parsing. ## [v0.5.1] 2022-05-22 ### Changed diff --git a/httpupload.go b/httpupload.go index ae7e618..8f8fcf3 100644 --- a/httpupload.go +++ b/httpupload.go @@ -65,6 +65,9 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, log.Fatal(err) } iqDiscoItemsXMLQuery := iqDiscoItemsXML.SelectElement("query") + if iqDiscoItemsXMLQuery == nil { + log.Fatal("no query element in disco items reply") + } iqDiscoItemsXMLItems := iqDiscoItemsXMLQuery.SelectElements("item") // Check the services reported by disco#items for the http upload service @@ -90,10 +93,21 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, log.Fatal(err) } iqDiscoInfoXMLQuery := iqDiscoInfoXML.SelectElement("query") + if iqDiscoInfoXMLQuery == nil { + continue + } iqDiscoInfoXMLIdentity := iqDiscoInfoXMLQuery.SelectElement("identity") + if iqDiscoInfoXMLIdentity == nil { + continue + } iqDiscoInfoXMLType := iqDiscoInfoXMLIdentity.SelectAttr("type") + if iqDiscoInfoXMLType == nil { + continue + } iqDiscoInfoXMLCategory := iqDiscoInfoXMLIdentity.SelectAttr("category") - + if iqDiscoInfoXMLCategory == nil { + continue + } if iqDiscoInfoXMLType.Value == "file" && iqDiscoInfoXMLCategory.Value == "store" { uploadComponent = jid.Value @@ -108,8 +122,17 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, field := r.SelectElements("field") for i, t := range field { varAttr := t.SelectAttr("var") + if varAttr == nil { + continue + } prevFieldVal := field[i-1].SelectElement("value") + if prevFieldVal == nil { + continue + } curFieldVal := t.SelectElement("value") + if curFieldVal == nil { + continue + } if varAttr.Value == "max-file-size" && prevFieldVal.Text() == nsHTTPUpload { maxFileSize, err = strconv.ParseInt(curFieldVal.Text(), 10, 64) if err != nil { @@ -154,8 +177,17 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, log.Fatal(err) } iqHTTPUploadSlotXMLSlot := iqHTTPUploadSlotXML.SelectElement("slot") + if iqHTTPUploadSlotXMLSlot == nil { + log.Fatal("http-upload: no slot element") + } iqHTTPUploadSlotXMLPut := iqHTTPUploadSlotXMLSlot.SelectElement("put") + if iqHTTPUploadSlotXMLPut == nil { + log.Fatal("http-upload: no put element") + } iqHTTPUploadSlotXMLPutURL := iqHTTPUploadSlotXMLPut.SelectAttr("url") + if iqHTTPUploadSlotXMLPutURL == nil { + log.Fatal("http-upload: no url attribute") + } // Upload file httpClient := &http.Client{} @@ -168,6 +200,9 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, iqHTTPUploadSlotXMLPutHeaders := iqHTTPUploadSlotXMLPut.SelectElements("header") for _, h := range iqHTTPUploadSlotXMLPutHeaders { name := h.SelectAttr("name") + if name == nil { + continue + } switch name.Value { case "Authorization", "Cookie", "Expires": req.Header.Set(name.Value, h.Text()) @@ -184,6 +219,12 @@ func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ, // Return http link iqHTTPUploadSlotXMLGet := iqHTTPUploadSlotXMLSlot.SelectElement("get") + if iqHTTPUploadSlotXMLGet == nil { + log.Fatal("http-upload: no get element") + } iqHTTPUploadSlotXMLGetURL := iqHTTPUploadSlotXMLGet.SelectAttr("url") + if iqHTTPUploadSlotXMLGetURL == nil { + log.Fatal("http-upload: no url attribute") + } return iqHTTPUploadSlotXMLGetURL.Value } diff --git a/ox.go b/ox.go index 1f6823c..0c3f935 100644 --- a/ox.go +++ b/ox.go @@ -511,11 +511,26 @@ func oxRecvPublicKeys(client *xmpp.Client, iqc chan xmpp.IQ, recipient string, return nil, err } oxPublicKeyXMLPubsub := oxPublicKeyXML.SelectElement("pubsub") + if oxPublicKeyXMLPubsub == nil { + return nil, errors.New("ox: no pubsub element in reply to public " + + "key request") + } oxPublicKeyXMLItems := oxPublicKeyXMLPubsub.SelectElement("items") + if oxPublicKeyXMLItems == nil { + return nil, errors.New("ox: no items element in reply to public " + + "key request") + } oxPublicKeyXMLItem := oxPublicKeyXMLItems.SelectElement("item") + if oxPublicKeyXMLItem == nil { + return nil, errors.New("ox: no item element in reply to public " + + "key request") + } oxPublicKeyXMLPubkeys := oxPublicKeyXMLItem.SelectElements("pubkey") for _, r := range oxPublicKeyXMLPubkeys { data := r.SelectElement("data") + if data == nil { + continue + } decodedPubKey, err := base64.StdEncoding.DecodeString(data.Text()) if err != nil { return nil, err @@ -573,14 +588,32 @@ func oxGetPublicKeyRing(client *xmpp.Client, iqc chan xmpp.IQ, } oxPubKeyListXMLPubsub := oxPubKeyListXML.SelectElement("pubsub") + if oxPubKeyListXMLPubsub == nil { + return nil, errors.New("ox: no pubsub element in public key list") + } oxPubKeyListXMLPubsubItems := oxPubKeyListXMLPubsub.SelectElement("items") + if oxPubKeyListXMLPubsubItems == nil { + return nil, errors.New("ox: no items element in public key list") + } oxPubKeyListXMLPubsubItemsItem := oxPubKeyListXMLPubsubItems.SelectElement("item") + if oxPubKeyListXMLPubsubItemsItem == nil { + return nil, errors.New("ox: no item element in public key list") + } oxPubKeyListXMLPubsubItemsItemPkl := oxPubKeyListXMLPubsubItemsItem.SelectElement("public-keys-list") + if oxPubKeyListXMLPubsubItemsItemPkl == nil { + return nil, errors.New("ox: no keblic-keys-list element") + } oxPubKeyListXMLPubsubItemsItemPklPm := oxPubKeyListXMLPubsubItemsItemPkl.SelectElements("pubkey-metadata") for _, r := range oxPubKeyListXMLPubsubItemsItemPklPm { date := r.SelectAttr("date") + if date == nil { + continue + } fingerprint := r.SelectAttr("v4-fingerprint") + if fingerprint == nil { + continue + } keyDate, err := time.Parse(time.RFC3339, date.Value) if err != nil { return nil, err diff --git a/stanzahandling.go b/stanzahandling.go index 00fc705..ed2940b 100644 --- a/stanzahandling.go +++ b/stanzahandling.go @@ -49,6 +49,7 @@ func rcvStanzas(client *xmpp.Client, iqc chan xmpp.IQ, msgc chan xmpp.Chat) { case xmpp.IQ: switch v.Type { case "get": + var xmlns *etree.Attr iq := etree.NewDocument() err = iq.ReadFromBytes(v.Query) if err != nil { @@ -56,7 +57,9 @@ func rcvStanzas(client *xmpp.Client, iqc chan xmpp.IQ, msgc chan xmpp.Chat) { string(v.Query), err) } query := iq.SelectElement("query") - xmlns := query.SelectAttr("xmlns") + if query != nil { + xmlns = query.SelectAttr("xmlns") + } switch xmlns.Value { case nsDiscoInfo: root := etree.NewDocument()