Add experimental ox support.

ox
Martin Dosch 2 years ago
parent 709ba5ad51
commit c17c002f42

@ -5,6 +5,11 @@
package main
const (
VERSION = "0.4.0-devel"
nsHttpUpload = "urn:xmpp:http:upload:0"
VERSION = "0.4.0-devel"
nsHttpUpload = "urn:xmpp:http:upload:0"
nsPubsub = "http://jabber.org/protocol/pubsub"
nsOx = "urn:xmpp:openpgp:0"
nsOxPubKeys = "urn:xmpp:openpgp:0:public-keys"
nsJabberClient = "jabber:client"
oxAltBody = "This message is encrypted (XEP-0373: OpenPGP for XMPP)."
)

@ -3,10 +3,21 @@ module salsa.debian.org/mdosch/go-sendxmpp
go 1.17
require (
github.com/ProtonMail/gopenpgp/v2 v2.4.6
github.com/gabriel-vasile/mimetype v1.4.0
github.com/mattn/go-xmpp v0.0.0-20220410054612-99ddfc1aa46a
github.com/pborman/getopt/v2 v2.1.0
salsa.debian.org/mdosch/xmppsrv v0.1.1
)
require golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect
require (
github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5 // indirect
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 // indirect
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
golang.org/x/text v0.3.7 // indirect
)

@ -1,20 +1,88 @@
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f h1:J2FzIrXN82q5uyUraeJpLIm7U6PffRwje2ORho5yIik=
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5 h1:cSHEbLj0GZeHM1mWG84qEnGFojNEQ83W7cwaPRjcwXU=
github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f h1:CGq7OieOz3wyQJ1fO8S0eO9TCW1JyvLrf8fhzz1i8ko=
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4=
github.com/ProtonMail/gopenpgp/v2 v2.4.6 h1:/EcJsFIsE0ywShAJ+lNLafcaSd6GBhIzHsaBID5pGXw=
github.com/ProtonMail/gopenpgp/v2 v2.4.6/go.mod h1:ZW1KxHNG6q5LMgFKf9Ap/d2eVYeyGf5+fAUEAjJWtmo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0FnbhiOsEro=
github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/mattn/go-xmpp v0.0.0-20220410054612-99ddfc1aa46a h1:ErhE3+ijxVepytrWsoNSz9D11gCEhWIFJ2kN1eUvj5A=
github.com/mattn/go-xmpp v0.0.0-20220410054612-99ddfc1aa46a/go.mod h1:Cs5mF0OsrRRmhkyOod//ldNPOwJsrBvJ+1WRspv0xoc=
github.com/pborman/getopt/v2 v2.1.0 h1:eNfR+r+dWLdWmV8g5OlpyrTYHkhVNxHBdN2cCrJmOEA=
github.com/pborman/getopt/v2 v2.1.0/go.mod h1:4NtW75ny4eBw9fO1bhtNdYTlZKYX5/tBLtsOpwKIKd0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 h1:iU7T1X1J6yxDr0rda54sWGkHgOp5XJrqm79gcNlC2VM=
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c=
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f h1:8w7RhxzTVgUzw/AH/9mUV5q0vMgy40SQRursCcfmkCw=
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
salsa.debian.org/mdosch/xmppsrv v0.1.1 h1:I/5HS+cOg27LRADQ2R4KqQY6DTVMsaPMu9ywSAMTOG8=
salsa.debian.org/mdosch/xmppsrv v0.1.1/go.mod h1:udWXnWFa9zkcyN9YSB/u44BCnnRDpeQ0eDy3MVLjHZQ=

@ -8,8 +8,21 @@ import (
"crypto/rand"
"fmt"
"log"
mrand "math/rand"
"time"
)
func getRpad() string {
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,;?!+-_§$%&/()=")
mrand.Seed(time.Now().UnixNano())
s := make([]rune, mrand.Intn(30)+20)
for i := range s {
s[i] = letters[mrand.Intn(len(letters))]
}
return string(s)
}
func getID() string {
b := make([]byte, 12)
_, err := rand.Read(b)

@ -5,7 +5,6 @@
package main
import (
"errors"
"log"
"github.com/mattn/go-xmpp" // BSD-3-Clause
@ -24,9 +23,6 @@ func sendIQ(client *xmpp.Client, target string, iQtype string,
}
iq = <-c
close(c)
if iq.Type != "result" {
return iq, errors.New("No result for " + content)
}
return iq, nil
}

@ -6,6 +6,97 @@ package main
import "encoding/xml"
// Created with https://github.com/miku/zek
type OxMessageElement struct {
XMLName xml.Name `xml:"message"`
Text string `xml:",chardata"`
To string `xml:"to,attr"`
Openpgp struct {
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
} `xml:"openpgp"`
Body string `xml:"body"`
}
// Created with https://github.com/miku/zek
type OxCryptElement struct {
XMLName xml.Name `xml:"crypt"`
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
To struct {
Text string `xml:",chardata"`
Jid string `xml:"jid,attr"`
} `xml:"to"`
Time struct {
Text string `xml:",chardata"`
Stamp string `xml:"stamp,attr"`
} `xml:"time"`
Rpad string `xml:"rpad"`
Payload struct {
Text string `xml:",chardata"`
Body struct {
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
} `xml:"body"`
} `xml:"payload"`
}
// Created with https://github.com/miku/zek
type OxPublicKey struct {
XMLName xml.Name `xml:"pubsub"`
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
Items struct {
Text string `xml:",chardata"`
Node string `xml:"node,attr"`
Item struct {
Text string `xml:",chardata"`
ID string `xml:"id,attr"`
Pubkey struct {
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
Data string `xml:"data"`
} `xml:"pubkey"`
} `xml:"item"`
} `xml:"items"`
}
// Created with https://github.com/miku/zek
type OxPublicKeysList struct {
XMLName xml.Name `xml:"pubsub"`
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
Items struct {
Text string `xml:",chardata"`
Node string `xml:"node,attr"`
Item struct {
Text string `xml:",chardata"`
ID string `xml:"id,attr"`
PublicKeysList struct {
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
PubkeyMetadata []struct {
Text string `xml:",chardata"`
Date string `xml:"date,attr"`
V4Fingerprint string `xml:"v4-fingerprint,attr"`
} `xml:"pubkey-metadata"`
} `xml:"public-keys-list"`
} `xml:"item"`
} `xml:"items"`
}
// Created with https://github.com/miku/zek
type IQPubsubRequest struct {
XMLName xml.Name `xml:"pubsub"`
Text string `xml:",chardata"`
Xmlns string `xml:"xmlns,attr"`
Items struct {
Text string `xml:",chardata"`
Node string `xml:"node,attr"`
MaxItems string `xml:"max_items,attr"`
} `xml:"items"`
}
// Created with https://github.com/miku/zek
type IQDiscoItemsType struct {
XMLName xml.Name `xml:"query"`

@ -99,6 +99,7 @@ func main() {
"Minimal TLS version. 10 (TLSv1.0), 11 (TLSv1.1), 12 (TLSv1.2) or 13 (TLSv1.3).")
flagVersion := getopt.BoolLong("version", 0, "Show version information.")
flagMUCPassword := getopt.StringLong("muc-password", 0, "", "Password for password protected MUCs.")
flagOx := getopt.BoolLong("ox", 0, "Use \"OpenPGP for XMPP\" encryption (experimental).")
// Parse command line flags.
getopt.Parse()
@ -116,6 +117,19 @@ func main() {
os.Exit(0)
}
// Quit if Ox (OpenPGP for XMPP) is requested for unsupported operations like
// groupchat, http-upload or listening.
if *flagOx && (*flagHttpUpload != "" || *flagChatroom || *flagListen) {
switch {
case *flagHttpUpload != "":
log.Fatal("No Ox support for http-upload available.")
case *flagChatroom:
log.Fatal("No Ox support for chat rooms available.")
case *flagListen:
log.Fatal("No Ox support for receiving messages available.")
}
}
// Read recipients from command line and quit if none are specified.
// For listening or sending raw XML it's not required to specify a recipient except
// when sending raw messages to MUCs (go-sendxmpp will join the MUC automatically).
@ -432,13 +446,25 @@ func main() {
scanner.Scan()
message = scanner.Text()
for _, recipient := range recipients {
_, err = client.Send(xmpp.Chat{Remote: recipient,
Type: "chat", Text: message})
if err != nil {
// Try to nicely close connection,
// even if there was an error sending.
_ = client.Close()
log.Fatal(err)
if *flagOx {
message, err = oxEncrypt(client, recipient, message)
if err != nil {
fmt.Println("Ox: couldn't encrypt to", recipient)
continue
}
_, err = client.SendOrg(message)
if err != nil {
log.Fatal(err)
}
} else {
_, err = client.Send(xmpp.Chat{Remote: recipient,
Type: "chat", Text: message})
if err != nil {
// Try to nicely close connection,
// even if there was an error sending.
_ = client.Close()
log.Fatal(err)
}
}
}
}
@ -448,8 +474,20 @@ func main() {
_, err = client.Send(xmpp.Chat{Remote: recipient, Type: "chat",
Ooburl: message, Text: message})
} else {
_, err = client.Send(xmpp.Chat{Remote: recipient, Type: "chat",
Text: message})
if *flagOx {
message, err = oxEncrypt(client, recipient, message)
if err != nil {
fmt.Println("Ox: couldn't encrypt to", recipient)
continue
}
_, err = client.SendOrg(message)
if err != nil {
log.Fatal(err)
}
} else {
_, err = client.Send(xmpp.Chat{Remote: recipient, Type: "chat",
Text: message})
}
}
if err != nil {
// Try to nicely close connection,

121
ox.go

@ -0,0 +1,121 @@
// Copyright 2022 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 (
"encoding/base64"
"encoding/xml"
"errors"
"log"
"time"
"github.com/ProtonMail/gopenpgp/v2/crypto" // MIT License
"github.com/mattn/go-xmpp" // BSD-3-Clause
)
func oxEncrypt(client *xmpp.Client, recipient string, message string) (string, error) {
var oxPublicKeyListRequest IQPubsubRequest
var oxPublicKeyRequest IQPubsubRequest
var oxPublicKeyListXML OxPublicKeysList
var oxPublicKeyXML OxPublicKey
var oxCryptMessage OxCryptElement
var oxMessage OxMessageElement
oxPublicKeyListRequest.Xmlns = nsPubsub
oxPublicKeyListRequest.Items.Node = nsOxPubKeys
opkl, err := xml.Marshal(oxPublicKeyListRequest)
if err != nil {
log.Fatal(err)
}
oxPublicKeyList, err := sendIQ(client, recipient, "get", string(opkl))
if err != nil {
log.Fatal(err)
}
if oxPublicKeyList.Type != "result" {
return "error", errors.New("Error while requesting public openpgp keys for " +
recipient)
}
err = xml.Unmarshal(oxPublicKeyList.Query, &oxPublicKeyListXML)
if err != nil {
return "error", err
}
fingerprint := "none"
newestKey, err := time.Parse(time.RFC3339, "1900-01-01T06:06:06Z")
if err != nil {
return "error", err
}
for _, r := range oxPublicKeyListXML.Items.Item.PublicKeysList.PubkeyMetadata {
keyDate, err := time.Parse(time.RFC3339, r.Date)
if err != nil {
return "error", err
}
if keyDate.After(newestKey) {
newestKey = keyDate
fingerprint = r.V4Fingerprint
}
}
if fingerprint == "none" {
return "error", errors.New("server didn't provide public key fingerprints for " + recipient)
}
oxPublicKeyRequest.Xmlns = nsPubsub
oxPublicKeyRequest.Items.Node = nsOxPubKeys + ":" + fingerprint
oxPublicKeyRequest.Items.MaxItems = "1"
opk, err := xml.Marshal(oxPublicKeyRequest)
if err != nil {
return "error", err
}
oxPublicKey, err := sendIQ(client, recipient, "get", string(opk))
if err != nil {
return "error", err
}
if oxPublicKey.Type != "result" {
return "error", errors.New("Err while requesting public key for " + recipient)
}
err = xml.Unmarshal(oxPublicKey.Query, &oxPublicKeyXML)
if err != nil {
return "error", err
}
// func NewKey(binKeys []byte) (key *Key, err error)
// armor, err := helper.EncryptMessageArmored(pubkey, "plain text")
decodedPubKey, err := base64.StdEncoding.DecodeString(oxPublicKeyXML.Items.Item.Pubkey.Data)
if err != nil {
return "error", err
}
key, err := crypto.NewKey(decodedPubKey)
if err != nil {
return "error", err
}
keyRing, err := crypto.NewKeyRing(key)
if err != nil {
return "error", err
}
oxCryptMessage.Xmlns = nsOx
oxCryptMessage.To.Jid = recipient
oxCryptMessage.Time.Stamp = time.Now().Format(time.RFC3339)
oxCryptMessage.Rpad = getRpad()
oxCryptMessage.Payload.Body.Xmlns = nsJabberClient
oxCryptMessage.Payload.Body.Text = message
ocm, err := xml.Marshal(oxCryptMessage)
if err != nil {
return "error", err
}
plainMessage := crypto.NewPlainMessage([]byte(ocm))
pgpMessage, err := keyRing.Encrypt(plainMessage, nil)
if err != nil {
return "error", err
}
oxMessage.To = recipient
oxMessage.Openpgp.Text = base64.StdEncoding.EncodeToString(pgpMessage.Data)
oxMessage.Openpgp.Xmlns = nsOx
oxMessage.Body = oxAltBody
om, err := xml.Marshal(oxMessage)
if err != nil {
return "error", err
}
return string(om), nil
}
Loading…
Cancel
Save