Rework receiving stanzas.

Calling client.Recv() multiple times caused messages not appear
in `--listen` mode as calling Recv() for receiving IQs (e.g. for
receiving Ox keys) also received the messages so they were no longer
available for the Recv in the listening function.
oxmuc
Martin Dosch 2 years ago
parent 6893307841
commit 2f2a2fd4fd

@ -3,6 +3,7 @@
## Unreleased
### Changed
- Ox: Improve rpad generation.
- Reworked receiving of stanzas.
## [v0.4.0] 2022-04-30
### Added

@ -20,7 +20,8 @@ import (
"github.com/mattn/go-xmpp" // BSD-3-Clause
)
func httpUpload(client *xmpp.Client, jserver string, filePath string) string {
func httpUpload(client *xmpp.Client, iqc chan xmpp.IQ,
jserver string, filePath string) string {
var uploadComponent string
var maxFileSize int64
@ -53,7 +54,7 @@ func httpUpload(client *xmpp.Client, jserver string, filePath string) string {
fileNameEscaped := reg.ReplaceAllString(fileName, "_")
// Query server for disco#items
iqContent, err := sendIQ(client, jserver, "get",
iqContent, err := sendIQ(client, iqc, jserver, "get",
"<query xmlns='http://jabber.org/protocol/disco#items'/>")
if err != nil {
log.Fatal(err)
@ -76,7 +77,7 @@ func httpUpload(client *xmpp.Client, jserver string, filePath string) string {
if err != nil {
log.Fatal(err)
}
iqDiscoInfo, err := sendIQ(client, jid.Value, "get", iqdi)
iqDiscoInfo, err := sendIQ(client, iqc, jid.Value, "get", iqdi)
if err != nil {
log.Fatal(err)
}
@ -140,7 +141,7 @@ func httpUpload(client *xmpp.Client, jserver string, filePath string) string {
}
// Request http upload slot
uploadSlot, err := sendIQ(client, uploadComponent, "get", r)
uploadSlot, err := sendIQ(client, iqc, uploadComponent, "get", r)
if err != nil {
log.Fatal(err)
}

@ -5,40 +5,31 @@
package main
import (
"log"
"github.com/mattn/go-xmpp" // BSD-3-Clause
)
func sendIQ(client *xmpp.Client, target string, iQtype string,
content string) (xmpp.IQ, error) {
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)
go getIQ(client, id, c, iqc)
_, err := client.RawInformation(client.JID(), target, id,
iQtype, content)
if err != nil {
return iq, err
}
iq = <-c
close(c)
return iq, nil
}
func getIQ(client *xmpp.Client, id string, c chan xmpp.IQ) {
func getIQ(client *xmpp.Client, id string, c chan xmpp.IQ,
iqc chan xmpp.IQ) {
for {
msg, err := client.Recv()
if err != nil {
log.Fatal(err)
}
switch v := msg.(type) {
case xmpp.IQ:
if v.ID == id {
c <- v
return
}
iq := <-iqc
if iq.ID == id {
c <- iq
return
}
}
}

@ -29,6 +29,23 @@ 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
@ -250,11 +267,15 @@ func main() {
log.Fatal(err)
}
iqc := make(chan xmpp.IQ, 100)
msgc := make(chan xmpp.Chat, 100)
go rcvStanzas(client, iqc, msgc)
for _, r := range getopt.Args() {
var re recipientsType
re.Jid = r
if *flagOx {
re.OxKeyRing, err = oxGetPublicKeyRing(client, r)
re.OxKeyRing, err = oxGetPublicKeyRing(client, iqc, r)
if err != nil {
re.OxKeyRing = nil
fmt.Println("Couldn't receive key for:", r)
@ -278,7 +299,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
err = oxGenPrivKey(validatedOwnJid, client, *flagOxPassphrase, "x25519")
err = oxGenPrivKey(validatedOwnJid, client, iqc, *flagOxPassphrase, "x25519")
if err != nil {
log.Fatal(err)
}
@ -288,7 +309,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
err = oxGenPrivKey(validatedOwnJid, client, *flagOxPassphrase, "rsa")
err = oxGenPrivKey(validatedOwnJid, client, iqc, *flagOxPassphrase, "rsa")
if err != nil {
log.Fatal(err)
}
@ -299,7 +320,7 @@ func main() {
log.Fatal(err)
}
err = oxImportPrivKey(validatedOwnJid, *flagOxImportPrivKey,
client)
client, iqc)
if err != nil {
log.Fatal(err)
}
@ -316,7 +337,7 @@ func main() {
}
if *flagHTTPUpload != "" {
message = httpUpload(client, tlsConfig.ServerName,
message = httpUpload(client, iqc, tlsConfig.ServerName,
*flagHTTPUpload)
}
@ -337,8 +358,6 @@ func main() {
if err := scanner.Err(); err != nil {
if err != io.EOF {
// Close connection and quit.
_ = client.Close()
log.Fatal(err)
}
}
@ -387,7 +406,7 @@ func main() {
if recipient.OxKeyRing == nil {
continue
}
oxMessage, err := oxEncrypt(client, oxPrivKey,
oxMessage, err := oxEncrypt(client, iqc, oxPrivKey,
recipient.Jid, recipient.OxKeyRing, message)
if err != nil {
fmt.Println("Ox: couldn't encrypt to",
@ -410,61 +429,52 @@ func main() {
case *flagListen:
tz := time.Now().Location()
for {
received, err := client.Recv()
if err != nil {
log.Println(err)
}
switch v := received.(type) {
case xmpp.Chat:
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)
}
v := <-msgc
switch {
case isOxMsg(v) && *flagOx:
msg, t, err := oxDecrypt(v, client, iqc, 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)
}
}
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)
}
}
}
default:
continue
}
}
default:
@ -481,7 +491,7 @@ func main() {
if recipient.OxKeyRing == nil {
continue
}
oxMessage, err := oxEncrypt(client, oxPrivKey,
oxMessage, err := oxEncrypt(client, iqc, oxPrivKey,
recipient.Jid, recipient.OxKeyRing, message)
if err != nil {
fmt.Println("Ox: couldn't encrypt to", recipient.Jid)
@ -504,10 +514,4 @@ func main() {
// Wait for a short time as some messages are not delievered by the server
// if the connection is closed immediately after sending a message.
time.Sleep(100 * time.Millisecond)
// Close XMPP connection
err = client.Close()
if err != nil {
log.Fatal(err)
}
}

45
ox.go

@ -19,8 +19,8 @@ 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) {
func oxDecrypt(m xmpp.Chat, client *xmpp.Client, iqc chan xmpp.IQ,
user string, oxPrivKey *crypto.Key) (string, time.Time, error) {
var cryptMsgByte []byte
var err error
sender := strings.Split(m.Remote, "/")[0]
@ -39,7 +39,7 @@ func oxDecrypt(m xmpp.Chat, client *xmpp.Client, user string,
if err != nil {
return "error", time.Now(), err
}
senderKeyRing, err := oxGetPublicKeyRing(client, sender)
senderKeyRing, err := oxGetPublicKeyRing(client, iqc, sender)
if err != nil {
return "error", time.Now(), err
}
@ -103,7 +103,8 @@ func isOxMsg(m xmpp.Chat) bool {
return false
}
func oxImportPrivKey(jid string, privKeyLocation string, client *xmpp.Client) error {
func oxImportPrivKey(jid string, privKeyLocation string, client *xmpp.Client,
iqc chan xmpp.IQ) error {
xmppURI := "xmpp:" + jid
buffer, err := readFile(privKeyLocation)
if err != nil {
@ -129,7 +130,7 @@ func oxImportPrivKey(jid string, privKeyLocation string, client *xmpp.Client) er
return err
}
fingerprint := strings.ToUpper(pubKey.GetFingerprint())
_, err = oxRecvPublicKeys(client, jid, fingerprint)
_, err = oxRecvPublicKeys(client, iqc, jid, fingerprint)
if err != nil {
return errors.New("Key not found in pubsub: " + fingerprint)
}
@ -146,7 +147,7 @@ func oxImportPrivKey(jid string, privKeyLocation string, client *xmpp.Client) er
if err != nil {
log.Fatal(err)
}
pubKeyRing, err := oxGetPublicKeyRing(client, jid)
pubKeyRing, err := oxGetPublicKeyRing(client, iqc, jid)
if err == nil {
pubKeys := pubKeyRing.GetKeys()
for _, r := range pubKeys {
@ -155,14 +156,15 @@ func oxImportPrivKey(jid string, privKeyLocation string, client *xmpp.Client) er
}
}
}
err = oxPublishPubKey(jid, client, pubKey)
err = oxPublishPubKey(jid, client, iqc, pubKey)
if err != nil {
return err
}
return nil
}
func oxPublishPubKey(jid string, client *xmpp.Client, pubKey *crypto.Key) error {
func oxPublishPubKey(jid string, client *xmpp.Client, iqc chan xmpp.IQ,
pubKey *crypto.Key) error {
keyCreated := time.Now().UTC().Format("2006-01-02T15:04:05Z")
fingerprint := strings.ToUpper(pubKey.GetFingerprint())
keySerialized, err := pubKey.Serialize()
@ -198,14 +200,14 @@ func oxPublishPubKey(jid string, client *xmpp.Client, pubKey *crypto.Key) error
if err != nil {
return err
}
iqReply, err := sendIQ(client, jid, "set", xmlstring)
iqReply, err := sendIQ(client, iqc, jid, "set", xmlstring)
if err != nil {
return err
}
if iqReply.Type != "result" {
return errors.New("Error while publishing public key")
}
ownPubKeyRingFromPubsub, err := oxRecvPublicKeys(client, jid, fingerprint)
ownPubKeyRingFromPubsub, err := oxRecvPublicKeys(client, iqc, jid, fingerprint)
if err != nil {
return errors.New("Couldn't successfully verify public key upload")
}
@ -245,7 +247,7 @@ func oxPublishPubKey(jid string, client *xmpp.Client, pubKey *crypto.Key) error
if err != nil {
return err
}
iqReply, err = sendIQ(client, jid, "set", xmlstring)
iqReply, err = sendIQ(client, iqc, jid, "set", xmlstring)
if err != nil {
return err
}
@ -377,8 +379,8 @@ func oxStoreKey(location string, key string) error {
return nil
}
func oxGenPrivKey(jid string, client *xmpp.Client, passphrase string,
keyType string) error {
func oxGenPrivKey(jid string, client *xmpp.Client, iqc chan xmpp.IQ,
passphrase string, keyType string) error {
xmppURI := "xmpp:" + jid
key, err := crypto.GenerateKey(xmppURI, "", keyType, 4096)
if err != nil {
@ -411,14 +413,14 @@ func oxGenPrivKey(jid string, client *xmpp.Client, passphrase string,
if err != nil {
return err
}
err = oxPublishPubKey(jid, client, pubKey)
err = oxPublishPubKey(jid, client, iqc, pubKey)
if err != nil {
return err
}
return nil
}
func oxRecvPublicKeys(client *xmpp.Client, recipient string,
func oxRecvPublicKeys(client *xmpp.Client, iqc chan xmpp.IQ, recipient string,
fingerprint string) (*crypto.KeyRing, error) {
opkr := etree.NewDocument()
opkrPs := opkr.CreateElement("pubsub")
@ -430,7 +432,7 @@ func oxRecvPublicKeys(client *xmpp.Client, recipient string,
if err != nil {
return nil, err
}
oxPublicKey, err := sendIQ(client, recipient, "get", opkrString)
oxPublicKey, err := sendIQ(client, iqc, recipient, "get", opkrString)
if err != nil {
return nil, err
}
@ -472,7 +474,8 @@ func oxRecvPublicKeys(client *xmpp.Client, recipient string,
return keyring, nil
}
func oxGetPublicKeyRing(client *xmpp.Client, recipient string) (*crypto.KeyRing, error) {
func oxGetPublicKeyRing(client *xmpp.Client, iqc chan xmpp.IQ,
recipient string) (*crypto.KeyRing, error) {
publicKeyRing, err := crypto.NewKeyRing(nil)
if err != nil {
return nil, err
@ -488,7 +491,7 @@ func oxGetPublicKeyRing(client *xmpp.Client, recipient string) (*crypto.KeyRing,
if err != nil {
log.Fatal(err)
}
oxPublicKeyList, err := sendIQ(client, recipient, "get", opkl)
oxPublicKeyList, err := sendIQ(client, iqc, recipient, "get", opkl)
if err != nil {
log.Fatal(err)
}
@ -571,7 +574,7 @@ func oxGetPublicKeyRing(client *xmpp.Client, recipient string) (*crypto.KeyRing,
}
}
}
pubKeyRing, err := oxRecvPublicKeys(client, recipient, pubKeyRingID)
pubKeyRing, err := oxRecvPublicKeys(client, iqc, recipient, pubKeyRingID)
if err != nil {
return nil, err
}
@ -596,8 +599,8 @@ func oxGetPublicKeyRing(client *xmpp.Client, recipient string) (*crypto.KeyRing,
return pubKeyRing, nil
}
func oxEncrypt(client *xmpp.Client, oxPrivKey *crypto.Key, recipient string,
keyRing *crypto.KeyRing, message string) (string, error) {
func oxEncrypt(client *xmpp.Client, iqc chan xmpp.IQ, oxPrivKey *crypto.Key,
recipient string, keyRing *crypto.KeyRing, message string) (string, error) {
privKeyRing, err := crypto.NewKeyRing(oxPrivKey)
if err != nil {
return "error", err

Loading…
Cancel
Save