parent
							
								
									531c267473
								
							
						
					
					
						commit
						88c59ac00b
					
				|  | @ -25,6 +25,7 @@ require ( | |||
| 	github.com/go-playground/locales v0.13.0 // indirect | ||||
| 	github.com/go-playground/universal-translator v0.17.0 // 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/gorilla/context 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.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||
| 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/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= | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ import ( | |||
| var VERSION = "development" | ||||
| 
 | ||||
| type configData struct { | ||||
| 	JWTSecret   JWTSecret   `toml"jwt_secret"` | ||||
| 	EndpointURL string      `toml:"endpoint_url"` | ||||
| 	XMPP        XMPPService `toml:"xmpp"` | ||||
| 	Webserver   web.Service `toml:"webserver"` | ||||
|  | @ -42,6 +43,7 @@ func main() { | |||
| 	} | ||||
| 	// just for more beautiful config file - jere
 | ||||
| 	config.XMPP.EndpointURL = config.EndpointURL | ||||
| 	config.XMPP.JWTSecret = config.JWTSecret | ||||
| 
 | ||||
| 	go func() { | ||||
| 		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") | ||||
| 	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 | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"dev.sum7.eu/genofire/golang-lib/web" | ||||
| 	"dev.sum7.eu/genofire/golang-lib/web/api/status" | ||||
| 	"dev.sum7.eu/genofire/golang-lib/web/metrics" | ||||
| 	"github.com/gin-gonic/gin" | ||||
| ) | ||||
| 
 | ||||
| // Bind to webservice
 | ||||
|  | @ -18,13 +18,13 @@ import ( | |||
| // @securityDefinitions.apikey ApiKeyAuth
 | ||||
| // @in header
 | ||||
| // @name Authorization
 | ||||
| func Bind(xmpp *XMPPService) web.ModuleRegisterFunc { | ||||
| func Bind(xmpp *XMPPService, jwt JWTSecret) web.ModuleRegisterFunc { | ||||
| 	return func(r *gin.Engine, ws *web.Service) { | ||||
| 		// docs.Bind(r, ws)
 | ||||
| 
 | ||||
| 		status.Register(r, ws) | ||||
| 		metrics.Register(r, ws) | ||||
| 		Get(r, ws) | ||||
| 		Post(r, ws, xmpp) | ||||
| 		Post(r, ws, xmpp, jwt) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -2,16 +2,22 @@ package main | |||
| 
 | ||||
| import ( | ||||
| 	"github.com/gin-gonic/gin" | ||||
| 	"net/http" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"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) { | ||||
| 		to := c.Query("to") | ||||
| 		token := c.Query("token") | ||||
| 		to, token, err := jwtsecret.Read(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) | ||||
| 		if err != nil { | ||||
| 			c.JSON(http.StatusBadRequest, web.HTTPError{ | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ type XMPPService struct { | |||
| 	Secret string `toml:"secret"` | ||||
| 	// hidden here for beautiful config file
 | ||||
| 	EndpointURL string    `toml:"-"` | ||||
| 	JWTSecret   JWTSecret `toml"-"` | ||||
| 	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"} | ||||
| 		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.Register.Endpoint = &messages.EndpointData{Body: 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
 | ||||
| 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{}{ | ||||
| 		"to":    to, | ||||
| 		"token": token, | ||||
| 	}).Info("forward message to xmpp") | ||||
| 	return s.session.Encode(context.TODO(), messages.Message{ | ||||
| 		Message: stanza.Message{ | ||||
| 			To:   jid.MustParse(to), | ||||
| 			To:   to, | ||||
| 			From: jid.MustParse(s.JID), | ||||
| 			// Type: stanza.ChatMessage,
 | ||||
| 			Type: stanza.NormalMessage, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue