Ox: Add support for receiving and decrypting Ox messages.

v0.4
Martin Dosch 2 years ago
parent 7a6948bf86
commit 10c9986e7d

@ -137,8 +137,6 @@ func main() {
log.Fatal("No Ox support for http-upload available.")
case *flagOx && *flagChatroom:
log.Fatal("No Ox support for chat rooms available.")
case *flagOx && *flagListen:
log.Fatal("No Ox support for receiving messages available.")
case *flagHTTPUpload != "" && *flagInteractive:
log.Fatal("Interactive mode and http upload can't" +
" be used at the same time.")
@ -410,6 +408,7 @@ func main() {
}
}
case *flagListen:
tz := time.Now().Location()
for {
received, err := client.Recv()
if err != nil {
@ -418,24 +417,49 @@ func main() {
switch v := received.(type) {
case xmpp.Chat:
var t time.Time
if v.Text == "" {
continue
}
if v.Stamp.IsZero() {
t = time.Now()
} else {
t = v.Stamp
}
bareFrom := strings.Split(v.Remote, "/")[0]
// Print any messages if no recipients are specified
if len(recipients) == 0 {
fmt.Println(t.Format(time.RFC3339), bareFrom+":", v.Text)
} else {
for _, recipient := range recipients {
if bareFrom == strings.ToLower(recipient.Jid) {
fmt.Println(t.Format(time.RFC3339),
bareFrom+":", v.Text)
switch {
case isOxMsg(v) && *flagOx:
msg, t, err := oxDecrypt(v, client, user, oxPrivKey)
if err != nil {
log.Println(err)
continue
}
if msg == "" {
continue
}
bareFrom := strings.Split(v.Remote, "/")[0]
// Print any messages if no recipients are specified
if len(recipients) == 0 {
fmt.Println(t.In(tz).Format(time.RFC3339), "[OX]",
bareFrom+":", msg)
} else {
for _, recipient := range recipients {
if bareFrom == strings.ToLower(recipient.Jid) {
fmt.Println(t.In(tz).Format(time.RFC3339),
"[OX]", bareFrom+":", msg)
}
}
}
default:
var t time.Time
if v.Text == "" {
continue
}
if v.Stamp.IsZero() {
t = time.Now()
} else {
t = v.Stamp
}
bareFrom := strings.Split(v.Remote, "/")[0]
// Print any messages if no recipients are specified
if len(recipients) == 0 {
fmt.Println(t.In(tz).Format(time.RFC3339), bareFrom+":", v.Text)
} else {
for _, recipient := range recipients {
if bareFrom == strings.ToLower(recipient.Jid) {
fmt.Println(t.In(tz).Format(time.RFC3339),
bareFrom+":", v.Text)
}
}
}
}

@ -34,7 +34,7 @@ You can either pipe a programs output to \fBgo\-sendxmpp\fR, write in your termi
.P
\fB\-\-ox\fR: Use "OpenPGP for XMPP" encryption (experimental)\.
.br
\fBOx\fR in go\-sendxmpp only supports sending encrypted 1\-1 messages\. Sending to groupchats, sending encrypted files or receiving encrypted messages is not supported\. There is no check whether the recipients key is trusted as there is no local keyring used\. Go\-sendxmpp just uses the most recent key that is provided via pubsub and checks that it is not expired\.
\fBOx\fR in go\-sendxmpp only supports sending encrypted 1\-1 messages\. Sending to groupchats and sending encrypted files is not supported\. There is no check whether the recipients key is trusted as there is no local keyring used\. Go\-sendxmpp just uses the most recent key that is provided via pubsub and checks that it is not expired\.
.P
\fB\-\-ox\-genprivkey\-rsa\fR: Generate a private OpenPGP key (RSA 4096 bit) for the configured account (via config file or \fB\-u\fR and \fB\-p\fR) and publish the corresponding public key\. Go\-sendxmpp will save the key in \fB$XDG_DATA_HOME/go\-sendxmpp/oxprivkeys\fR or \fB$HOME/\.local/share/go\-sendxmpp/oxprivkeys\fR\. To protect the key a passphrase might be set using \fB\-\-ox\-passphrase\fR while generating the key\.
.br

@ -127,8 +127,8 @@ file location is specified with <code>-f</code> or <code>--file</code>.</p>
<p><code>--ox</code>:
Use "OpenPGP for XMPP" encryption (experimental). <br>
<code>Ox</code> in go-sendxmpp only supports sending encrypted 1-1 messages. Sending to groupchats, sending
encrypted files or receiving encrypted messages is not supported.
<code>Ox</code> in go-sendxmpp only supports sending encrypted 1-1 messages. Sending to groupchats and
sending encrypted files is not supported.
There is no check whether the recipients key is trusted as there is no local keyring used.
Go-sendxmpp just uses the most recent key that is provided via pubsub and checks that it is not
expired.</p>

@ -52,8 +52,8 @@ file location is specified with `-f` or `--file`.
`--ox`:
Use "OpenPGP for XMPP" encryption (experimental).
`Ox` in go-sendxmpp only supports sending encrypted 1-1 messages. Sending to groupchats, sending
encrypted files or receiving encrypted messages is not supported.
`Ox` in go-sendxmpp only supports sending encrypted 1-1 messages. Sending to groupchats and
sending encrypted files is not supported.
There is no check whether the recipients key is trusted as there is no local keyring used.
Go-sendxmpp just uses the most recent key that is provided via pubsub and checks that it is not
expired.

80
ox.go

@ -18,6 +18,86 @@ import (
"github.com/mattn/go-xmpp" // BSD-3-Clause
)
func oxDecrypt(m xmpp.Chat, client *xmpp.Client, user string,
oxPrivKey *crypto.Key) (string, time.Time, error) {
var cryptMsgByte []byte
var err error
sender := strings.Split(m.Remote, "/")[0]
for _, r := range m.OtherElem {
if r.XMLName.Space == nsOx {
cryptMsgByte, err =
base64.StdEncoding.DecodeString(r.InnerXML)
if err != nil {
return "error", time.Now(), err
}
break
}
}
oxMsg := crypto.NewPGPMessage(cryptMsgByte)
keyRing, err := crypto.NewKeyRing(oxPrivKey)
if err != nil {
return "error", time.Now(), err
}
senderKeyRing, err := oxGetPublicKeyRing(client, sender)
if err != nil {
return "error", time.Now(), err
}
decryptMsg, err := keyRing.Decrypt(oxMsg, senderKeyRing, crypto.GetUnixTime())
if err != nil {
return "error", time.Now(), err
}
doc := etree.NewDocument()
err = doc.ReadFromBytes(decryptMsg.Data)
if err != nil {
return "error", time.Now(), err
}
signcrypt := doc.SelectElement("signcrypt")
if signcrypt == nil {
return "error", time.Now(), errors.New("Ox: no signcrypt element")
}
to := signcrypt.SelectElement("to")
if to == nil {
return "error", time.Now(), errors.New("Ox: no to element")
}
jid := to.SelectAttr("jid")
if jid == nil {
return "error", time.Now(), errors.New("Ox: no jid attribute")
}
if strings.Split(jid.Value, "/")[0] != user {
return "error", time.Now(), errors.New("Ox: encrypted for wrong user")
}
timestamp := signcrypt.SelectElement("time")
if timestamp == nil {
return "error", time.Now(), errors.New("Ox: no time element")
}
stamp := timestamp.SelectAttr("stamp")
if stamp == nil {
return "error", time.Now(), errors.New("Ox: no stamp attribute")
}
msgStamp, err := time.Parse("2006-01-02T15:04:05Z", stamp.Value)
if err != nil {
return "error", time.Now(), err
}
payload := signcrypt.SelectElement("payload")
if payload == nil {
return "error", time.Now(), errors.New("Ox: no payload element")
}
body := payload.SelectElement("body")
if body == nil {
return "", time.Now(), nil
}
return body.Text(), msgStamp, nil
}
func isOxMsg(m xmpp.Chat) bool {
for _, r := range m.OtherElem {
if r.XMLName.Space == nsOx {
return true
}
}
return false
}
func oxImportPrivKey(jid string, privKeyLocation string, client *xmpp.Client) error {
xmppURI := "xmpp:" + jid
buffer, err := readFile(privKeyLocation)

Loading…
Cancel
Save