aboutsummaryrefslogtreecommitdiff
path: root/xmpp
diff options
context:
space:
mode:
Diffstat (limited to 'xmpp')
-rw-r--r--xmpp/extensions/extensions.go77
-rw-r--r--xmpp/gateway/gateway.go77
-rw-r--r--xmpp/handlers.go34
3 files changed, 165 insertions, 23 deletions
diff --git a/xmpp/extensions/extensions.go b/xmpp/extensions/extensions.go
index c982581..2cf7d45 100644
--- a/xmpp/extensions/extensions.go
+++ b/xmpp/extensions/extensions.go
@@ -141,6 +141,45 @@ type FallbackSubject struct {
End string `xml:"end,attr"`
}
+// CarbonReceived is from XEP-0280
+type CarbonReceived struct {
+ XMLName xml.Name `xml:"urn:xmpp:carbons:2 received"`
+ Forwarded stanza.Forwarded `xml:"urn:xmpp:forward:0 forwarded"`
+}
+
+// CarbonSent is from XEP-0280
+type CarbonSent struct {
+ XMLName xml.Name `xml:"urn:xmpp:carbons:2 sent"`
+ Forwarded stanza.Forwarded `xml:"urn:xmpp:forward:0 forwarded"`
+}
+
+// ComponentPrivilege is from XEP-0356
+type ComponentPrivilege struct {
+ XMLName xml.Name `xml:"urn:xmpp:privilege:1 privilege"`
+ Perms []ComponentPerm `xml:"perm"`
+ Forwarded stanza.Forwarded `xml:"urn:xmpp:forward:0 forwarded"`
+}
+
+// ComponentPerm is from XEP-0356
+type ComponentPerm struct {
+ XMLName xml.Name `xml:"perm"`
+ Access string `xml:"access,attr"`
+ Type string `xml:"type,attr"`
+ Push bool `xml:"push,attr"`
+}
+
+// ClientMessage is a jabber:client NS message compatible with Prosody's XEP-0356 implementation
+type ClientMessage struct {
+ XMLName xml.Name `xml:"jabber:client message"`
+ stanza.Attrs
+
+ Subject string `xml:"subject,omitempty"`
+ Body string `xml:"body,omitempty"`
+ Thread string `xml:"thread,omitempty"`
+ Error stanza.Err `xml:"error,omitempty"`
+ Extensions []stanza.MsgExtension `xml:",omitempty"`
+}
+
// Namespace is a namespace!
func (c PresenceNickExtension) Namespace() string {
return c.XMLName.Space
@@ -171,6 +210,26 @@ func (c Fallback) Namespace() string {
return c.XMLName.Space
}
+// Namespace is a namespace!
+func (c CarbonReceived) Namespace() string {
+ return c.XMLName.Space
+}
+
+// Namespace is a namespace!
+func (c CarbonSent) Namespace() string {
+ return c.XMLName.Space
+}
+
+// Namespace is a namespace!
+func (c ComponentPrivilege) Namespace() string {
+ return c.XMLName.Space
+}
+
+// Name is a packet name
+func (ClientMessage) Name() string {
+ return "message"
+}
+
// NewReplyFallback initializes a fallback range
func NewReplyFallback(start uint64, end uint64) Fallback {
return Fallback{
@@ -214,4 +273,22 @@ func init() {
"urn:xmpp:fallback:0",
"fallback",
}, Fallback{})
+
+ // carbon received
+ stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{
+ "urn:xmpp:carbons:2",
+ "received",
+ }, CarbonReceived{})
+
+ // carbon sent
+ stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{
+ "urn:xmpp:carbons:2",
+ "sent",
+ }, CarbonSent{})
+
+ // component privilege
+ stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{
+ "urn:xmpp:privilege:1",
+ "privilege",
+ }, ComponentPrivilege{})
}
diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go
index de8b495..534ee7e 100644
--- a/xmpp/gateway/gateway.go
+++ b/xmpp/gateway/gateway.go
@@ -2,6 +2,7 @@ package gateway
import (
"encoding/xml"
+ "github.com/pkg/errors"
"strings"
"sync"
@@ -33,31 +34,44 @@ var Jid *stanza.Jid
// were changed and need to be re-flushed to the YamlDB
var DirtySessions = false
+// MessageOutgoingPermission allows to fake outgoing messages by foreign JIDs
+var MessageOutgoingPermission = false
+
// SendMessage creates and sends a message stanza
-func SendMessage(to string, from string, body string, id string, component *xmpp.Component, reply *Reply) {
- sendMessageWrapper(to, from, body, id, component, reply, "")
+func SendMessage(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, isOutgoing bool) {
+ sendMessageWrapper(to, from, body, id, component, reply, "", isOutgoing)
}
// SendServiceMessage creates and sends a simple message stanza from transport
func SendServiceMessage(to string, body string, component *xmpp.Component) {
- sendMessageWrapper(to, "", body, "", component, nil, "")
+ sendMessageWrapper(to, "", body, "", component, nil, "", false)
}
// SendTextMessage creates and sends a simple message stanza
func SendTextMessage(to string, from string, body string, component *xmpp.Component) {
- sendMessageWrapper(to, from, body, "", component, nil, "")
+ sendMessageWrapper(to, from, body, "", component, nil, "", false)
}
// SendMessageWithOOB creates and sends a message stanza with OOB URL
-func SendMessageWithOOB(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, oob string) {
- sendMessageWrapper(to, from, body, id, component, reply, oob)
+func SendMessageWithOOB(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, oob string, isOutgoing bool) {
+ sendMessageWrapper(to, from, body, id, component, reply, oob, isOutgoing)
}
-func sendMessageWrapper(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, oob string) {
+func sendMessageWrapper(to string, from string, body string, id string, component *xmpp.Component, reply *Reply, oob string, isOutgoing bool) {
+ toJid, err := stanza.NewJid(to)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "to": to,
+ }).Error(errors.Wrap(err, "Invalid to JID!"))
+ return
+ }
+ bareTo := toJid.Bare()
+
componentJid := Jid.Full()
var logFrom string
var messageFrom string
+ var messageTo string
if from == "" {
logFrom = componentJid
messageFrom = componentJid
@@ -65,6 +79,12 @@ func sendMessageWrapper(to string, from string, body string, id string, componen
logFrom = from
messageFrom = from + "@" + componentJid
}
+ if isOutgoing {
+ messageTo = messageFrom
+ messageFrom = bareTo + "/" + Jid.Resource
+ } else {
+ messageTo = to
+ }
log.WithFields(log.Fields{
"from": logFrom,
@@ -74,7 +94,7 @@ func sendMessageWrapper(to string, from string, body string, id string, componen
message := stanza.Message{
Attrs: stanza.Attrs{
From: messageFrom,
- To: to,
+ To: messageTo,
Type: "chat",
Id: id,
},
@@ -96,7 +116,34 @@ func sendMessageWrapper(to string, from string, body string, id string, componen
}
}
- sendMessage(&message, component)
+ if isOutgoing {
+ carbonMessage := extensions.ClientMessage{
+ Attrs: stanza.Attrs{
+ From: bareTo,
+ To: to,
+ Type: "chat",
+ },
+ }
+ carbonMessage.Extensions = append(carbonMessage.Extensions, extensions.CarbonSent{
+ Forwarded: stanza.Forwarded{
+ Stanza: extensions.ClientMessage(message),
+ },
+ })
+ privilegeMessage := stanza.Message{
+ Attrs: stanza.Attrs{
+ From: Jid.Bare(),
+ To: toJid.Domain,
+ },
+ }
+ privilegeMessage.Extensions = append(privilegeMessage.Extensions, extensions.ComponentPrivilege{
+ Forwarded: stanza.Forwarded{
+ Stanza: carbonMessage,
+ },
+ })
+ sendMessage(&privilegeMessage, component)
+ } else {
+ sendMessage(&message, component)
+ }
}
// SetNickname sets a new nickname for a contact
@@ -297,3 +344,15 @@ func ResumableSend(component *xmpp.Component, packet stanza.Packet) error {
}
return err
}
+
+// SplitJID tokenizes a JID string to bare JID and resource
+func SplitJID(from string) (string, string, bool) {
+ fromJid, err := stanza.NewJid(from)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "from": from,
+ }).Error(errors.Wrap(err, "Invalid from JID!"))
+ return "", "", false
+ }
+ return fromJid.Bare(), fromJid.Resource, true
+}
diff --git a/xmpp/handlers.go b/xmpp/handlers.go
index acf62a2..2bdbaef 100644
--- a/xmpp/handlers.go
+++ b/xmpp/handlers.go
@@ -79,7 +79,7 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) {
}).Warn("Message")
log.Debugf("%#v", msg)
- bare, resource, ok := splitFrom(msg.From)
+ bare, resource, ok := gateway.SplitJID(msg.From)
if !ok {
return
}
@@ -152,6 +152,23 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) {
}
log.Warn("Unknown purpose of the message, skipping")
}
+
+ if msg.Body == "" {
+ var privilege extensions.ComponentPrivilege
+ if ok := msg.Get(&privilege); ok {
+ log.Debugf("privilege: %#v", privilege)
+ }
+
+ for _, perm := range privilege.Perms {
+ if perm.Access == "message" && perm.Type == "outgoing" {
+ gateway.MessageOutgoingPermission = true
+ }
+ }
+ }
+
+ if msg.Type == "error" {
+ log.Errorf("MESSAGE ERROR: %#v", p)
+ }
}
// HandlePresence processes an incoming XMPP presence
@@ -196,7 +213,7 @@ func handleSubscription(s xmpp.Sender, p stanza.Presence) {
if !ok {
return
}
- bare, _, ok := splitFrom(p.From)
+ bare, _, ok := gateway.SplitJID(p.From)
if !ok {
return
}
@@ -227,7 +244,7 @@ func handlePresence(s xmpp.Sender, p stanza.Presence) {
log.Debugf("%#v", p)
// create session
- bare, resource, ok := splitFrom(p.From)
+ bare, resource, ok := gateway.SplitJID(p.From)
if !ok {
return
}
@@ -385,17 +402,6 @@ func handleGetDiscoInfo(s xmpp.Sender, iq *stanza.IQ) {
_ = gateway.ResumableSend(component, answer)
}
-func splitFrom(from string) (string, string, bool) {
- fromJid, err := stanza.NewJid(from)
- if err != nil {
- log.WithFields(log.Fields{
- "from": from,
- }).Error(errors.Wrap(err, "Invalid from JID!"))
- return "", "", false
- }
- return fromJid.Bare(), fromJid.Resource, true
-}
-
func toToID(to string) (int64, bool) {
toParts := strings.Split(to, "@")
if len(toParts) < 2 {