2021-09-09 23:12:29 +02:00
package main
import (
"context"
"crypto/tls"
"encoding/xml"
2021-09-11 17:16:38 +02:00
"errors"
2021-09-12 00:31:03 +02:00
"io"
2021-09-09 23:12:29 +02:00
"github.com/bdlm/log"
2021-09-14 21:37:37 +02:00
"github.com/google/uuid"
2021-09-09 23:12:29 +02:00
"mellium.im/sasl"
"mellium.im/xmlstream"
"mellium.im/xmpp"
2021-09-15 17:04:06 +02:00
"mellium.im/xmpp/disco"
2021-09-09 23:12:29 +02:00
"mellium.im/xmpp/jid"
2021-09-11 17:16:38 +02:00
"mellium.im/xmpp/mux"
2021-09-09 23:12:29 +02:00
"mellium.im/xmpp/stanza"
"unifiedpush.org/go/np2p_dbus/distributor"
2021-09-14 21:37:37 +02:00
"unifiedpush.org/go/np2p_dbus/storage"
2021-09-11 17:16:38 +02:00
"dev.sum7.eu/genofire/unified-push-xmpp/messages"
2021-09-09 23:12:29 +02:00
)
type XMPPService struct {
Login string
Password string
Gateway string
dbus * distributor . DBus
2021-09-12 00:31:03 +02:00
session * xmpp . Session
2021-09-14 21:37:37 +02:00
store * storage . Storage
2021-09-09 23:12:29 +02:00
}
2021-09-14 21:37:37 +02:00
func ( s * XMPPService ) Run ( dbus * distributor . DBus , store * storage . Storage ) error {
2021-09-11 17:16:38 +02:00
var err error
s . dbus = dbus
2021-09-14 21:37:37 +02:00
s . store = store
2021-09-11 17:16:38 +02:00
j := jid . MustParse ( s . Login )
if s . session , err = xmpp . DialClientSession (
2021-09-09 23:12:29 +02:00
context . TODO ( ) , j ,
xmpp . BindResource ( ) ,
xmpp . StartTLS ( & tls . Config {
ServerName : j . Domain ( ) . String ( ) ,
} ) ,
//TODO sasl.ScramSha1Plus <- problem with (my) ejabberd
2021-09-11 17:16:38 +02:00
//xmpp.SASL("", s.Password, sasl.ScramSha1Plus, sasl.ScramSha1, sasl.Plain),
xmpp . SASL ( "" , s . Password , sasl . ScramSha1 , sasl . Plain ) ,
) ; err != nil {
2021-09-09 23:12:29 +02:00
return err
}
defer func ( ) {
2021-09-14 09:49:59 +02:00
log . Info ( "closing session" )
2021-09-11 17:16:38 +02:00
if err := s . session . Close ( ) ; err != nil {
2021-09-14 09:49:59 +02:00
log . Errorf ( "error closing session: %q" , err )
2021-09-09 23:12:29 +02:00
}
2021-09-14 09:49:59 +02:00
log . Println ( "closing connection" )
2021-09-11 17:16:38 +02:00
if err := s . session . Conn ( ) . Close ( ) ; err != nil {
2021-09-14 09:49:59 +02:00
log . Errorf ( "error closing connection: %q" , err )
2021-09-09 23:12:29 +02:00
}
} ( )
// Send initial presence to let the server know we want to receive messages.
2021-09-11 17:16:38 +02:00
err = s . session . Send ( context . TODO ( ) , stanza . Presence { Type : stanza . AvailablePresence } . Wrap ( nil ) )
2021-09-09 23:12:29 +02:00
if err != nil {
return err
}
2021-09-15 17:04:06 +02:00
go s . checkServer ( )
2021-09-11 17:16:38 +02:00
s . session . Serve ( mux . New (
2021-09-15 17:04:06 +02:00
// disco.Handle(),
2021-09-11 17:16:38 +02:00
mux . MessageFunc ( "" , xml . Name { Local : "subject" } , s . message ) ,
2021-09-09 23:12:29 +02:00
) )
return nil
}
2021-09-11 17:16:38 +02:00
// handler of incoming message - forward to DBUS
func ( s * XMPPService ) message ( msgHead stanza . Message , t xmlstream . TokenReadEncoder ) error {
2021-09-14 09:49:59 +02:00
logger := log . WithFields ( map [ string ] interface { } {
"to" : msgHead . To . String ( ) ,
"from" : msgHead . From . String ( ) ,
"id" : msgHead . ID ,
} )
2021-09-09 23:12:29 +02:00
d := xml . NewTokenDecoder ( t )
2021-09-11 17:16:38 +02:00
msg := messages . MessageBody { }
2021-09-09 23:12:29 +02:00
err := d . Decode ( & msg )
if err != nil && err != io . EOF {
2021-09-14 09:49:59 +02:00
log . WithField ( "msg" , msg ) . Errorf ( "error decoding message: %q" , err )
2021-09-09 23:12:29 +02:00
return nil
}
from := msgHead . From . Bare ( ) . String ( )
2021-09-11 17:16:38 +02:00
if s . Gateway == "" || from != s . Gateway {
2021-09-09 23:12:29 +02:00
log . WithField ( "from" , from ) . Info ( "message not from gateway, that is no notification" )
return nil
}
2021-09-14 21:55:21 +02:00
if msg . Body == "" || msg . PublicToken == "" {
2021-09-09 23:12:29 +02:00
log . Infof ( "empty: %v" , msgHead )
return nil
}
2021-09-14 09:49:59 +02:00
logger = logger . WithFields ( map [ string ] interface { } {
2021-09-14 21:55:21 +02:00
"publicToken" : msg . PublicToken ,
2021-09-14 21:37:37 +02:00
"content" : msg . Body ,
2021-09-14 09:49:59 +02:00
} )
2021-09-09 23:12:29 +02:00
2021-09-14 21:55:21 +02:00
conn := s . store . GetConnectionbyPublic ( msg . PublicToken )
2021-09-14 21:37:37 +02:00
if conn == nil {
logger . Warnf ( "no appID and appToken found for publicToken" )
2021-09-11 17:16:38 +02:00
}
2021-09-14 09:49:59 +02:00
logger = logger . WithFields ( map [ string ] interface { } {
2021-09-14 21:37:37 +02:00
"appID" : conn . AppID ,
"appToken" : conn . AppToken ,
2021-09-14 09:49:59 +02:00
} )
2021-09-11 17:16:38 +02:00
if s . dbus .
2021-09-14 21:37:37 +02:00
NewConnector ( conn . AppID ) .
Message ( conn . AppToken , msg . Body , msgHead . ID ) != nil {
2021-09-14 09:49:59 +02:00
logger . Errorf ( "Error send unified push: %q" , err )
2021-09-09 23:12:29 +02:00
return nil
}
2021-09-14 09:49:59 +02:00
logger . Infof ( "recieve unified push" )
2021-09-09 23:12:29 +02:00
return nil
}
2021-09-12 00:31:03 +02:00
2021-09-15 17:04:06 +02:00
// checkServer - background job
func ( s * XMPPService ) checkServer ( ) error {
domain := s . session . LocalAddr ( ) . Domain ( )
log . Infof ( "your instant is %s - check running" , domain )
info , err := disco . GetInfo ( context . TODO ( ) , "" , domain , s . session )
if err != nil {
return err
}
// check if server support msgoffline
supportMSGOffline := false
for _ , f := range info . Features {
if f . Var == "msgoffline" {
supportMSGOffline = true
break
}
}
if ! supportMSGOffline {
log . Warn ( "your server does not support offline messages (XEP-0160) - it is need to deliever messages later, if this distributer has current no connection" )
}
return nil
}
2021-09-11 17:16:38 +02:00
// Register handler of DBUS Distribution
2021-09-14 21:37:37 +02:00
func ( s * XMPPService ) Register ( appID , appToken string ) ( string , string , error ) {
publicToken := uuid . New ( ) . String ( )
2021-09-11 17:16:38 +02:00
logger := log . WithFields ( map [ string ] interface { } {
2021-09-14 21:37:37 +02:00
"appID" : appID ,
"appToken" : appToken ,
"publicToken" : publicToken ,
2021-09-11 17:16:38 +02:00
} )
iq := messages . RegisterIQ {
IQ : stanza . IQ {
Type : stanza . SetIQ ,
2021-09-12 00:31:03 +02:00
To : jid . MustParse ( s . Gateway ) ,
2021-09-11 17:16:38 +02:00
} ,
}
2021-09-14 21:37:37 +02:00
iq . Register . Token = & messages . TokenData { Body : publicToken }
2021-09-11 17:16:38 +02:00
t , err := s . session . EncodeIQ ( context . TODO ( ) , iq )
if err != nil {
logger . Errorf ( "xmpp send IQ for register: %v" , err )
return "" , "xmpp unable send iq to gateway" , err
}
2021-09-14 09:14:07 +02:00
defer func ( ) {
if err := t . Close ( ) ; err != nil {
logger . Errorf ( "unable to close registration response %v" , err )
}
} ( )
2021-09-11 17:16:38 +02:00
d := xml . NewTokenDecoder ( t )
iqRegister := messages . RegisterIQ { }
if err := d . Decode ( & iqRegister ) ; err != nil {
logger . Errorf ( "xmpp recv IQ for register: %v" , err )
return "" , "xmpp unable recv iq to gateway" , err
}
if endpoint := iqRegister . Register . Endpoint ; endpoint != nil {
logger . WithField ( "endpoint" , endpoint . Body ) . Info ( "success" )
2021-09-14 21:37:37 +02:00
// update Endpoint
conn := s . store . NewConnectionWithToken ( appID , appToken , publicToken , endpoint . Body )
return conn . Endpoint , "" , nil
2021-09-11 17:16:38 +02:00
}
errStr := "Unknown Error"
if errr := iqRegister . Register . Error ; errr != nil {
errStr = errr . Body
}
err = errors . New ( errStr )
logger . WithField ( "error" , err ) . Error ( "unable to register" )
return "" , errStr , err
}
// Unregister handler of DBUS Distribution
func ( xs * XMPPService ) Unregister ( token string ) {
2021-09-14 21:37:37 +02:00
conn , _ := xs . store . DeleteConnection ( token )
2021-09-11 17:16:38 +02:00
log . WithFields ( map [ string ] interface { } {
2021-09-14 21:37:37 +02:00
"appID" : conn . AppID ,
"appToken" : conn . AppToken ,
"publicToken" : conn . PublicToken ,
"endpoint" : conn . Endpoint ,
2021-09-11 17:16:38 +02:00
} ) . Info ( "distributor-unregister" )
2021-09-14 21:37:37 +02:00
_ = xs . dbus . NewConnector ( conn . AppID ) . Unregistered ( conn . AppToken )
2021-09-11 17:16:38 +02:00
}