85 lines
1.8 KiB
Go
85 lines
1.8 KiB
Go
package auth
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"forge.cadoles.com/arcad/edge/pkg/app"
|
|
"forge.cadoles.com/arcad/edge/pkg/module"
|
|
"forge.cadoles.com/arcad/edge/pkg/module/util"
|
|
"github.com/dop251/goja"
|
|
"github.com/golang-jwt/jwt"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const (
|
|
AnonymousSubject = "anonymous"
|
|
)
|
|
|
|
type Module struct {
|
|
server *app.Server
|
|
keyFunc jwt.Keyfunc
|
|
}
|
|
|
|
func (m *Module) Name() string {
|
|
return "auth"
|
|
}
|
|
|
|
func (m *Module) Export(export *goja.Object) {
|
|
if err := export.Set("getSubject", m.getSubject); err != nil {
|
|
panic(errors.Wrap(err, "could not set 'getSubject' function"))
|
|
}
|
|
|
|
if err := export.Set("ANONYMOUS", AnonymousSubject); err != nil {
|
|
panic(errors.Wrap(err, "could not set 'ANONYMOUS_USER' property"))
|
|
}
|
|
}
|
|
|
|
func (m *Module) getSubject(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
|
|
ctx := util.AssertContext(call.Argument(0), rt)
|
|
|
|
req, ok := ctx.Value(module.ContextKeyOriginRequest).(*http.Request)
|
|
if !ok {
|
|
panic(errors.New("could not find http request in context"))
|
|
}
|
|
|
|
rawToken := strings.TrimPrefix(req.Header.Get("Authorization"), "Bearer ")
|
|
if rawToken == "" {
|
|
rawToken = req.URL.Query().Get("token")
|
|
}
|
|
|
|
if rawToken == "" {
|
|
return rt.ToValue(AnonymousSubject)
|
|
}
|
|
|
|
token, err := jwt.Parse(rawToken, m.keyFunc)
|
|
if err != nil {
|
|
panic(errors.WithStack(err))
|
|
}
|
|
|
|
if !token.Valid {
|
|
panic(errors.Errorf("invalid jwt token: '%v'", token.Raw))
|
|
}
|
|
|
|
mapClaims, ok := token.Claims.(jwt.MapClaims)
|
|
if !ok {
|
|
panic(errors.Errorf("unexpected claims type '%T'", token.Claims))
|
|
}
|
|
|
|
subject, exists := mapClaims["sub"]
|
|
if !exists {
|
|
return rt.ToValue(AnonymousSubject)
|
|
}
|
|
|
|
return rt.ToValue(subject)
|
|
}
|
|
|
|
func ModuleFactory(keyFunc jwt.Keyfunc) app.ServerModuleFactory {
|
|
return func(server *app.Server) app.ServerModule {
|
|
return &Module{
|
|
server: server,
|
|
keyFunc: keyFunc,
|
|
}
|
|
}
|
|
}
|