diff options
Diffstat (limited to 'xmpp/gateway/gateway.go')
-rw-r--r-- | xmpp/gateway/gateway.go | 116 |
1 files changed, 116 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( +} |