auth progress
This commit is contained in:
parent
a1005ce6bf
commit
95d72d2912
10 changed files with 110 additions and 24 deletions
|
@ -9,7 +9,6 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
|
||||
"dynatron.me/x/blasphem/pkg/auth/provider"
|
||||
"dynatron.me/x/blasphem/pkg/components"
|
||||
"dynatron.me/x/blasphem/pkg/storage"
|
||||
|
||||
// providers
|
||||
|
@ -35,7 +34,7 @@ type authenticator struct {
|
|||
|
||||
type Authenticator interface {
|
||||
ValidateAccessToken(token AccessToken) *RefreshToken
|
||||
InstallRoutes(e *echo.Echo, comp components.Componenter)
|
||||
InstallRoutes(e *echo.Echo)
|
||||
}
|
||||
|
||||
type AuthError struct {
|
||||
|
@ -43,7 +42,7 @@ type AuthError struct {
|
|||
Description string `json:"error_description"`
|
||||
}
|
||||
|
||||
func (a *authenticator) InstallRoutes(e *echo.Echo, comp components.Componenter) {
|
||||
func (a *authenticator) InstallRoutes(e *echo.Echo) {
|
||||
authG := e.Group("/auth")
|
||||
authG.GET("/providers", a.ProvidersHandler)
|
||||
authG.POST("/token", a.TokenHandler)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"dynatron.me/x/blasphem/internal/common"
|
||||
"dynatron.me/x/blasphem/pkg/auth"
|
||||
"dynatron.me/x/blasphem/pkg/blas/core"
|
||||
"dynatron.me/x/blasphem/pkg/bus"
|
||||
"dynatron.me/x/blasphem/pkg/components"
|
||||
"dynatron.me/x/blasphem/pkg/config"
|
||||
|
@ -21,6 +22,7 @@ type Blas struct {
|
|||
storage.Store
|
||||
auth.Authenticator
|
||||
Config *config.Config
|
||||
core.WebSocketManager
|
||||
|
||||
components components.ComponentStore
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"dynatron.me/x/blasphem/pkg/components"
|
||||
)
|
||||
|
||||
type Setup func(core.Core) (components.Component, error)
|
||||
type Setup func(core.Blas) (components.Component, error)
|
||||
|
||||
var Registry = make(map[components.ComponentKey]Setup)
|
||||
|
||||
|
|
|
@ -10,16 +10,35 @@ import (
|
|||
"dynatron.me/x/blasphem/pkg/storage"
|
||||
)
|
||||
|
||||
type Core interface {
|
||||
type Blas interface {
|
||||
auth.Authenticator
|
||||
bus.Bus
|
||||
storage.Store
|
||||
config.Configured
|
||||
components.Componenter
|
||||
|
||||
WebSocketManager
|
||||
|
||||
Shutdowner
|
||||
Versioner
|
||||
components.Componenter
|
||||
}
|
||||
|
||||
type WebSocketManager interface {
|
||||
// Register registers a websocket command.
|
||||
// cmd is the first part, before first slash
|
||||
// dataNew is a function to create a new message datatype
|
||||
RegisterWSCommand(cmd string, hnd Handler, dataNew NewData)
|
||||
WSCommandHandler(cmd string) (NewData, Handler, error)
|
||||
}
|
||||
|
||||
type WebSocketSession interface {
|
||||
Go() error
|
||||
Blas() Blas
|
||||
}
|
||||
|
||||
type Handler func(wss WebSocketSession, msg interface{}) error
|
||||
type NewData func() interface{}
|
||||
|
||||
type Shutdowner interface {
|
||||
ShutdownBlas(context.Context) error
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@ import (
|
|||
)
|
||||
|
||||
type ServeOptions struct {
|
||||
core blas.Core
|
||||
core blas.Blas
|
||||
}
|
||||
|
||||
func Command(core blas.Core) *cobra.Command {
|
||||
func Command(core blas.Blas) *cobra.Command {
|
||||
opts := makeOptions(core)
|
||||
serveCmd := &cobra.Command{
|
||||
Use: "serve",
|
||||
|
@ -23,7 +23,7 @@ func Command(core blas.Core) *cobra.Command {
|
|||
return serveCmd
|
||||
}
|
||||
|
||||
func makeOptions(core blas.Core) *ServeOptions {
|
||||
func makeOptions(core blas.Blas) *ServeOptions {
|
||||
return &ServeOptions{
|
||||
core: core,
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ func (fe *Frontend) AliasHandler(toFile string) echo.HandlerFunc {
|
|||
|
||||
func (*Frontend) Shutdown() {}
|
||||
|
||||
func Setup(_ core.Core) (components.Component, error) {
|
||||
func Setup(_ core.Blas) (components.Component, error) {
|
||||
fe := &Frontend{}
|
||||
var err error
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
)
|
||||
|
||||
type Server struct {
|
||||
core.Core
|
||||
core.Blas
|
||||
*echo.Echo
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ func (s *Server) installRoutes() {
|
|||
s.GET("/api/websocket", s.wsHandler)
|
||||
|
||||
s.Component(frontend.FrontendKey).(RouteHaver).InstallRoutes(s.Echo)
|
||||
s.Core.(*blas.Blas).Authenticator.InstallRoutes(s.Echo, s.Core)
|
||||
s.Blas.(*blas.Blas).Authenticator.InstallRoutes(s.Echo)
|
||||
|
||||
for _, c := range s.Components() {
|
||||
if rh, ok := c.(RouteHaver); ok {
|
||||
|
@ -41,9 +41,9 @@ func (s *Server) installRoutes() {
|
|||
}
|
||||
}
|
||||
|
||||
func New(core core.Core) (s *Server, err error) {
|
||||
func New(core core.Blas) (s *Server, err error) {
|
||||
s = &Server{
|
||||
Core: core,
|
||||
Blas: core,
|
||||
Echo: echo.New(),
|
||||
}
|
||||
|
||||
|
|
|
@ -23,5 +23,5 @@ func (s *Server) wsHandler(c echo.Context) error {
|
|||
|
||||
log.Debug().Str("remote", c.Request().RemoteAddr).Msg("WS")
|
||||
|
||||
return wsapi.New(s, c, conn).Handle()
|
||||
return wsapi.NewSession(s, c, conn).Go()
|
||||
}
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
package wsapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"dynatron.me/x/blasphem/pkg/auth"
|
||||
blas "dynatron.me/x/blasphem/pkg/blas/core"
|
||||
"dynatron.me/x/blasphem/pkg/blas/core"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var (
|
||||
NoSuchHandlerErr = errors.New("bad websocket command")
|
||||
)
|
||||
|
||||
type Type string
|
||||
type MsgBase struct {
|
||||
Type Type `json:"type"`
|
||||
|
@ -19,7 +25,7 @@ type MsgBase struct {
|
|||
type (
|
||||
wsSession struct {
|
||||
*websocket.Conn
|
||||
b blas.Core
|
||||
b core.Blas
|
||||
ec echo.Context
|
||||
h phaseHandler
|
||||
|
||||
|
@ -27,10 +33,6 @@ type (
|
|||
refreshToken *auth.RefreshToken
|
||||
}
|
||||
|
||||
WS interface {
|
||||
Handle() error
|
||||
}
|
||||
|
||||
phaseHandler interface {
|
||||
handleMsg(io.Reader) error
|
||||
}
|
||||
|
@ -38,19 +40,56 @@ type (
|
|||
cmdHandler struct {
|
||||
*wsSession
|
||||
}
|
||||
|
||||
wsEntry struct {
|
||||
dataNew core.NewData
|
||||
hnd core.Handler
|
||||
}
|
||||
|
||||
wsRegistry map[string]wsEntry
|
||||
|
||||
wsManager struct {
|
||||
r wsRegistry
|
||||
}
|
||||
)
|
||||
|
||||
func New(s blas.Core, c echo.Context, conn *websocket.Conn) WS {
|
||||
func (wsm *wsManager) RegisterWSCommand(cmd string, hnd core.Handler, dataNew core.NewData) {
|
||||
wsm.r[cmd] = wsEntry{
|
||||
dataNew: dataNew,
|
||||
hnd: hnd,
|
||||
}
|
||||
}
|
||||
|
||||
func (wsm *wsManager) WSCommandHandler(cmd string) (core.NewData, core.Handler, error) {
|
||||
wse, ok := wsm.r[cmd]
|
||||
if !ok {
|
||||
return nil, nil, NoSuchHandlerErr
|
||||
}
|
||||
|
||||
return wse.dataNew, wse.hnd, nil
|
||||
}
|
||||
|
||||
func NewManager() core.WebSocketManager {
|
||||
return &wsManager{
|
||||
r: make(wsRegistry),
|
||||
}
|
||||
}
|
||||
|
||||
func NewSession(s core.Blas, c echo.Context, conn *websocket.Conn) core.WebSocketSession {
|
||||
ws := &wsSession{
|
||||
Conn: conn,
|
||||
b: s,
|
||||
ec: c,
|
||||
}
|
||||
|
||||
ws.h = &authPhase{ws}
|
||||
|
||||
return ws
|
||||
}
|
||||
|
||||
func (ws *wsSession) Handle() error {
|
||||
func (ws *wsSession) Blas() core.Blas { return ws.b }
|
||||
|
||||
func (ws *wsSession) Go() error {
|
||||
err := ws.sendAuthRequired()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -76,5 +115,22 @@ type cmdMsg struct {
|
|||
type MsgType string
|
||||
|
||||
func (ws *cmdHandler) handleMsg(r io.Reader) error {
|
||||
return nil
|
||||
var msgMap map[string]interface{}
|
||||
err := json.NewDecoder(r).Decode(&msgMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgType, ok := msgMap["type"].(string)
|
||||
if !ok {
|
||||
return NoSuchHandlerErr
|
||||
}
|
||||
|
||||
newData, hand, err := ws.b.WSCommandHandler(msgType)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
nd := newData()
|
||||
return hand(ws, nd)
|
||||
}
|
||||
|
|
|
@ -37,9 +37,18 @@ func (ap *authPhase) finishAuth(rt *auth.RefreshToken) {
|
|||
ap.user = rt.User
|
||||
ap.refreshToken = rt
|
||||
ap.h = &cmdHandler{ap.wsSession}
|
||||
ap.sendAuthOK()
|
||||
}
|
||||
|
||||
func (ap *authPhase) sendAuthOK() error {
|
||||
return ap.WriteJSON(struct {
|
||||
Type string `json:"type"`
|
||||
Version string `json:"version"`
|
||||
}{Type: "auth_ok", Version: ap.Blas().Version()})
|
||||
}
|
||||
|
||||
func (ap *authPhase) handleMsg(r io.Reader) error {
|
||||
log.Debug().Interface("ap", ap).Msg("auth handlemsg")
|
||||
var authMsg authMsg
|
||||
err := json.NewDecoder(r).Decode(&authMsg)
|
||||
if err != nil {
|
||||
|
@ -49,6 +58,7 @@ func (ap *authPhase) handleMsg(r io.Reader) error {
|
|||
refreshToken := ap.b.ValidateAccessToken(authMsg.AccessToken)
|
||||
if refreshToken != nil {
|
||||
ap.finishAuth(refreshToken)
|
||||
return ap.sendAuthOK()
|
||||
}
|
||||
|
||||
log.Error().Str("remote", ap.ec.Request().RemoteAddr).Msg("websocket auth failed")
|
||||
|
|
Loading…
Reference in a new issue