diff options
Diffstat (limited to 'xmpp/gateway')
-rw-r--r-- | xmpp/gateway/gateway.go | 116 | ||||
-rw-r--r-- | xmpp/gateway/gateway_test.go | 5 |
2 files changed, 121 insertions, 0 deletions
diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go index 534ee7e..9cd2102 100644 --- a/xmpp/gateway/gateway.go +++ b/xmpp/gateway/gateway.go @@ -1,8 +1,13 @@ package gateway import ( + "bytes" + "encoding/base64" "encoding/xml" "github.com/pkg/errors" + "fmt" + "io" + "sort" "strings" "sync" @@ -37,6 +42,19 @@ var DirtySessions = false // MessageOutgoingPermission allows to fake outgoing messages by foreign JIDs var MessageOutgoingPermission = false +// CapsType is a capability category +type CapsType int +const ( + CapsAudio CapsType = iota +) + +// ContactType is a disco JID category +type ContactType int +const ( + ContactTransport CapsType = iota + ContactPM +) + // SendMessage creates and sends a message stanza 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) @@ -225,6 +243,9 @@ var SPResource = args.NewString() // SPImmed skips queueing var SPImmed = args.NewBool(args.Default(true)) +// SPCaps is a XEP-0115 verification string +var SPCaps = args.NewString() + func newPresence(bareJid string, to string, args ...args.V) stanza.Presence { var presenceFrom string if SPFrom.IsSet(args) { @@ -280,6 +301,16 @@ func newPresence(bareJid string, to string, args ...args.V) stanza.Presence { }) } } + if SPCaps.IsSet(args) { + ver := SPCaps.Get(args) + if ver != "" { + presence.Extensions = append(presence.Extensions, extensions.CapsExtension{ + Hash: "sha-1", + Node: "https://dev.narayana.im/narayana/telegabber/", + Ver: ver, + }) + } + } return presence } @@ -356,3 +387,88 @@ func SplitJID(from string) (string, string, bool) { } return fromJid.Bare(), fromJid.Resource, true } + +func getDiscoFeatures(caps []CapsType) []string { + features := []string{ + "http://jabber.org/protocol/caps", + "http://jabber.org/protocol/disco#info", + } + for typ := range features { + switch typ { + case CapsAudio: + features = append( + features, + "urn:xmpp:jingle-message:0", + "urn:xmpp:jingle:1", + "urn:xmpp:jingle:apps:dtls:0", + "urn:xmpp:jingle:apps:rtp:1", + "urn:xmpp:jingle:apps:rtp:audio", + "urn:xmpp:jingle:transports:ice-udp:1", + ) + } + } + return features +} + +// GetDiscoInfo generates a disco info IQ query response +func GetDiscoInfo(typ ContactType, features []string) *stanza.DiscoInfo { + disco := stanza.DiscoInfo{} + if typ == ContactPM { + disco.AddIdentity("", "account", "registered") + } else { + disco.AddIdentity("Telegram Gateway", "gateway", "telegram") + } + disco.AddFeatures(features...) + return &disco +} + + +// GetCapsVer hashes a capabilities set into a verification string +func GetCapsVer(caps []CapsType) (string, error) { + features := getDiscoFeatures(caps) + disco := GetDiscoInfo(features) + discoToCapsHash(disco) + buf := new(bytes.Buffer) + binval := base64.NewEncoder(base64.StdEncoding, buf) + _, err = io.Copy(binval, file) + binval.Close() + if err != nil { + return "", errors.Wrap(err, "Error calculating caps base64") + } + return buf.String(), nil +} + +func iOctetComparator(a, b string) bool { + return a < b +} + +func discoToCaps(disco *stanza.DiscoInfo) string { + var s strings.Builder + var identities, vars, capsForms []string + + for _, identity := range disco.Identity { + identities = append(identities, fmt.Sprintf( + "%s/%s//%s", + identity.Category, + identity.Type, + identity.Name, + )) + } + sort.Slice(identities, iOctetComparator) + for _, identity := range identities { + s.WriteString(identity) + s.WriteString(">") + } + + for _, feature := range disco.Features { + vars = append(vars, feature.Var) + } + sort.Slice(vars, iOctetComparator) + for _, var := range vars { + s.WriteString(var) + s.WriteString(">") + } + + for disco + s.WriteString( +} diff --git a/xmpp/gateway/gateway_test.go b/xmpp/gateway/gateway_test.go index 6191844..b75db4d 100644 --- a/xmpp/gateway/gateway_test.go +++ b/xmpp/gateway/gateway_test.go @@ -52,3 +52,8 @@ func TestPresencePhoto(t *testing.T) { presence := newPresence("from@test", "to@test", SPPhoto("01b87fcd030b72895ff8e88db57ec525450f000d")) testPresence(t, presence, "<presence from=\"from@test\" to=\"to@test\"><x xmlns=\"vcard-temp:x:update\"><photo>01b87fcd030b72895ff8e88db57ec525450f000d</photo></x></presence>") } + +func TestPresenceCaps(t *testing.T) { + caps := newPresence("from@test", "to@test", SPCaps("QgayPKawpkPSDYmwT/WM94uAlu0=")) + testPresence(t, presence, "<presence from=\"from@test\" to=\"to@test\"><c xmlns=\"http://jabber.org/protocol/caps\" hash=\"sha-1\" node=\"https://dev.narayana.im/narayana/telegabber\" ver=\"QgayPKawpkPSDYmwT/WM94uAlu0=\"/></presence>") +} |