parent
							
								
									531c267473
								
							
						
					
					
						commit
						88c59ac00b
					
				|  | @ -25,6 +25,7 @@ require ( | ||||||
| 	github.com/go-playground/locales v0.13.0 // indirect | 	github.com/go-playground/locales v0.13.0 // indirect | ||||||
| 	github.com/go-playground/universal-translator v0.17.0 // indirect | 	github.com/go-playground/universal-translator v0.17.0 // indirect | ||||||
| 	github.com/go-playground/validator/v10 v10.4.1 // indirect | 	github.com/go-playground/validator/v10 v10.4.1 // indirect | ||||||
|  | 	github.com/golang-jwt/jwt v3.2.2+incompatible // indirect | ||||||
| 	github.com/golang/protobuf v1.4.3 // indirect | 	github.com/golang/protobuf v1.4.3 // indirect | ||||||
| 	github.com/gorilla/context v1.1.1 // indirect | 	github.com/gorilla/context v1.1.1 // indirect | ||||||
| 	github.com/gorilla/securecookie v1.1.1 // indirect | 	github.com/gorilla/securecookie v1.1.1 // indirect | ||||||
|  |  | ||||||
|  | @ -123,6 +123,8 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG | ||||||
| github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||||
| github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||||
| github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= | ||||||
|  | github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= | ||||||
|  | github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= | ||||||
| github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= | ||||||
| github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||||||
| github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ import ( | ||||||
| var VERSION = "development" | var VERSION = "development" | ||||||
| 
 | 
 | ||||||
| type configData struct { | type configData struct { | ||||||
|  | 	JWTSecret   JWTSecret   `toml"jwt_secret"` | ||||||
| 	EndpointURL string      `toml:"endpoint_url"` | 	EndpointURL string      `toml:"endpoint_url"` | ||||||
| 	XMPP        XMPPService `toml:"xmpp"` | 	XMPP        XMPPService `toml:"xmpp"` | ||||||
| 	Webserver   web.Service `toml:"webserver"` | 	Webserver   web.Service `toml:"webserver"` | ||||||
|  | @ -42,6 +43,7 @@ func main() { | ||||||
| 	} | 	} | ||||||
| 	// just for more beautiful config file - jere
 | 	// just for more beautiful config file - jere
 | ||||||
| 	config.XMPP.EndpointURL = config.EndpointURL | 	config.XMPP.EndpointURL = config.EndpointURL | ||||||
|  | 	config.XMPP.JWTSecret = config.JWTSecret | ||||||
| 
 | 
 | ||||||
| 	go func() { | 	go func() { | ||||||
| 		if err := config.XMPP.Run(); err != nil { | 		if err := config.XMPP.Run(); err != nil { | ||||||
|  | @ -49,7 +51,7 @@ func main() { | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
| 
 | 
 | ||||||
| 	config.Webserver.ModuleRegister(Bind(&config.XMPP)) | 	config.Webserver.ModuleRegister(Bind(&config.XMPP, config.JWTSecret)) | ||||||
| 
 | 
 | ||||||
| 	log.Info("startup") | 	log.Info("startup") | ||||||
| 	if err := config.Webserver.Run(); err != nil { | 	if err := config.Webserver.Run(); err != nil { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,49 @@ | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"github.com/golang-jwt/jwt" | ||||||
|  | 	"mellium.im/xmpp/jid" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // JWTSecret the secret
 | ||||||
|  | type JWTSecret string | ||||||
|  | 
 | ||||||
|  | // JWTToken data field
 | ||||||
|  | type JWTToken struct { | ||||||
|  | 	jwt.StandardClaims | ||||||
|  | 	Token string `json:"token"` | ||||||
|  | 	JID   string `json:"jid"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Generate an jwt token by token and jid
 | ||||||
|  | func (s JWTSecret) Generate(jid jid.JID, token string) (string, error) { | ||||||
|  | 	jwtToken := JWTToken{ | ||||||
|  | 		Token: token, | ||||||
|  | 		JID:   jid.String(), | ||||||
|  | 	} | ||||||
|  | 	claim := jwt.NewWithClaims(jwt.SigningMethodHS512, jwtToken) | ||||||
|  | 	t, err := claim.SignedString([]byte(s)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	return t, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Read token to token and jid
 | ||||||
|  | func (s JWTSecret) Read(jwtToken string) (jid.JID, string, error) { | ||||||
|  | 	token, err := jwt.ParseWithClaims(jwtToken, &JWTToken{}, func(token *jwt.Token) (interface{}, error) { | ||||||
|  | 		return []byte(s), nil | ||||||
|  | 	}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return jid.JID{}, "", err | ||||||
|  | 	} | ||||||
|  | 	claims, ok := token.Claims.(*JWTToken) | ||||||
|  | 	if !ok { | ||||||
|  | 		return jid.JID{}, "", jwt.ErrInvalidKey | ||||||
|  | 	} | ||||||
|  | 	addr, err := jid.Parse(claims.JID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return jid.JID{}, "", err | ||||||
|  | 	} | ||||||
|  | 	return addr, claims.Token, nil | ||||||
|  | } | ||||||
|  | @ -0,0 +1,25 @@ | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	"mellium.im/xmpp/jid" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestJWT(t *testing.T) { | ||||||
|  | 	assert := assert.New(t) | ||||||
|  | 
 | ||||||
|  | 	addr := "a@example.org" | ||||||
|  | 	token := "pushtoken" | ||||||
|  | 
 | ||||||
|  | 	secret := JWTSecret("CHANGEME") | ||||||
|  | 	jwt, err := secret.Generate(jid.MustParse(addr), token) | ||||||
|  | 	assert.NoError(err) | ||||||
|  | 	assert.NoEqual("", jwt) | ||||||
|  | 
 | ||||||
|  | 	jid, t, err := secret.Read(jwt) | ||||||
|  | 	assert.NoError(err) | ||||||
|  | 	assert.Equal(addr, jid.String()) | ||||||
|  | 	assert.Equal(t, token) | ||||||
|  | } | ||||||
|  | @ -1,10 +1,10 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"github.com/gin-gonic/gin" |  | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web" | 	"dev.sum7.eu/genofire/golang-lib/web" | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web/api/status" | 	"dev.sum7.eu/genofire/golang-lib/web/api/status" | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web/metrics" | 	"dev.sum7.eu/genofire/golang-lib/web/metrics" | ||||||
|  | 	"github.com/gin-gonic/gin" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Bind to webservice
 | // Bind to webservice
 | ||||||
|  | @ -18,13 +18,13 @@ import ( | ||||||
| // @securityDefinitions.apikey ApiKeyAuth
 | // @securityDefinitions.apikey ApiKeyAuth
 | ||||||
| // @in header
 | // @in header
 | ||||||
| // @name Authorization
 | // @name Authorization
 | ||||||
| func Bind(xmpp *XMPPService) web.ModuleRegisterFunc { | func Bind(xmpp *XMPPService, jwt JWTSecret) web.ModuleRegisterFunc { | ||||||
| 	return func(r *gin.Engine, ws *web.Service) { | 	return func(r *gin.Engine, ws *web.Service) { | ||||||
| 		// docs.Bind(r, ws)
 | 		// docs.Bind(r, ws)
 | ||||||
| 
 | 
 | ||||||
| 		status.Register(r, ws) | 		status.Register(r, ws) | ||||||
| 		metrics.Register(r, ws) | 		metrics.Register(r, ws) | ||||||
| 		Get(r, ws) | 		Get(r, ws) | ||||||
| 		Post(r, ws, xmpp) | 		Post(r, ws, xmpp, jwt) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,16 +2,22 @@ package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
| 	"net/http" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
|  | 	"net/http" | ||||||
| 
 | 
 | ||||||
| 	"dev.sum7.eu/genofire/golang-lib/web" | 	"dev.sum7.eu/genofire/golang-lib/web" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func Post(r *gin.Engine, ws *web.Service, xmpp *XMPPService) { | func Post(r *gin.Engine, ws *web.Service, xmpp *XMPPService, jwtsecret JWTSecret) { | ||||||
| 	r.POST("/UP", func(c *gin.Context) { | 	r.POST("/UP", func(c *gin.Context) { | ||||||
| 		to := c.Query("to") | 		to, token, err := jwtsecret.Read(c.Query("token")) | ||||||
| 		token := c.Query("token") | 		if err != nil { | ||||||
|  | 			c.JSON(http.StatusUnauthorized, web.HTTPError{ | ||||||
|  | 				Message: "jwt token unauthoried - or not given", | ||||||
|  | 				Error:   err.Error(), | ||||||
|  | 			}) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
| 		b, err := ioutil.ReadAll(c.Request.Body) | 		b, err := ioutil.ReadAll(c.Request.Body) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			c.JSON(http.StatusBadRequest, web.HTTPError{ | 			c.JSON(http.StatusBadRequest, web.HTTPError{ | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ type XMPPService struct { | ||||||
| 	Secret string `toml:"secret"` | 	Secret string `toml:"secret"` | ||||||
| 	// hidden here for beautiful config file
 | 	// hidden here for beautiful config file
 | ||||||
| 	EndpointURL string    `toml:"-"` | 	EndpointURL string    `toml:"-"` | ||||||
|  | 	JWTSecret   JWTSecret `toml"-"` | ||||||
| 	session     *xmpp.Session | 	session     *xmpp.Session | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -102,7 +103,13 @@ func (s *XMPPService) handleRegister(iq stanza.IQ, t xmlstream.TokenReadEncoder, | ||||||
| 		reply.Register.Error = &messages.ErrorData{Body: "no token"} | 		reply.Register.Error = &messages.ErrorData{Body: "no token"} | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	endpoint := s.EndpointURL+"/UP?token=" + token + "&to=" + iq.From.String() | 	jwt, err := s.JWTSecret.Generate(iq.From, token) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Errorf("unable jwt generation: %v", err) | ||||||
|  | 		reply.Register.Error = &messages.ErrorData{Body: "jwt error on gateway"} | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	endpoint := s.EndpointURL + "/UP?token=" + jwt | ||||||
| 	reply.IQ.Type = stanza.ResultIQ | 	reply.IQ.Type = stanza.ResultIQ | ||||||
| 	reply.Register.Endpoint = &messages.EndpointData{Body: endpoint} | 	reply.Register.Endpoint = &messages.EndpointData{Body: endpoint} | ||||||
| 	log.Infof("generate respone: %v", endpoint) | 	log.Infof("generate respone: %v", endpoint) | ||||||
|  | @ -145,14 +152,14 @@ func (s *XMPPService) handleDisco(iq stanza.IQ, t xmlstream.TokenReadEncoder, st | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SendMessage of an UP Notification
 | // SendMessage of an UP Notification
 | ||||||
| func (s *XMPPService) SendMessage(to, token, content string) error { | func (s *XMPPService) SendMessage(to jid.JID, token, content string) error { | ||||||
| 	log.WithFields(map[string]interface{}{ | 	log.WithFields(map[string]interface{}{ | ||||||
| 		"to":    to, | 		"to":    to, | ||||||
| 		"token": token, | 		"token": token, | ||||||
| 	}).Info("forward message to xmpp") | 	}).Info("forward message to xmpp") | ||||||
| 	return s.session.Encode(context.TODO(), messages.Message{ | 	return s.session.Encode(context.TODO(), messages.Message{ | ||||||
| 		Message: stanza.Message{ | 		Message: stanza.Message{ | ||||||
| 			To:   jid.MustParse(to), | 			To:   to, | ||||||
| 			From: jid.MustParse(s.JID), | 			From: jid.MustParse(s.JID), | ||||||
| 			// Type: stanza.ChatMessage,
 | 			// Type: stanza.ChatMessage,
 | ||||||
| 			Type: stanza.NormalMessage, | 			Type: stanza.NormalMessage, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue