commands working ish

This commit is contained in:
Daniel Ponte 2022-12-20 20:11:11 -05:00
parent f119f7086f
commit caa371eff1
6 changed files with 62 additions and 13 deletions

View file

@ -276,24 +276,25 @@ func (r *RefreshToken) AccessToken(req *http.Request) (string, error) {
} }
func (a *authenticator) ValidateAccessToken(token AccessToken) *RefreshToken { func (a *authenticator) ValidateAccessToken(token AccessToken) *RefreshToken {
var uvIssRT *RefreshToken
claims := &jwt.StandardClaims{} claims := &jwt.StandardClaims{}
tok, err := jwt.ParseWithClaims(string(token), claims, func(jt *jwt.Token) (interface{}, error) { _, err := jwt.ParseWithClaims(string(token), claims, func(jt *jwt.Token) (interface{}, error) {
iss := jt.Claims.(*jwt.StandardClaims).Issuer iss := jt.Claims.(*jwt.StandardClaims).Issuer
rt := a.store.GetRefreshToken(RefreshTokenID(iss)) uvIssRT = a.store.GetRefreshToken(RefreshTokenID(iss))
if rt == nil { if uvIssRT == nil {
return nil, fmt.Errorf("bad token") return nil, fmt.Errorf("bad token")
} }
return rt.JWTKey, nil return []byte(uvIssRT.JWTKey), nil
}) })
if err != nil { if err != nil {
log.Error().Err(err).Msg("validateAccessToken")
return nil return nil
} }
iss := tok.Claims.(*jwt.StandardClaims).Issuer return uvIssRT
return a.store.GetRefreshToken(RefreshTokenID(iss))
} }
func (a *authenticator) verifyAndGetCredential(tr *TokenRequest) *Credentials { func (a *authenticator) verifyAndGetCredential(tr *TokenRequest) *Credentials {

View file

@ -100,7 +100,7 @@ func (as *authStore) GetRefreshToken(tid RefreshTokenID) *RefreshToken {
for _, u := range as.Users { for _, u := range as.Users {
for _, rt := range u.RefreshTokens { for _, rt := range u.RefreshTokens {
if subtle.ConstantTimeCompare([]byte(tid), []byte(rt.ID)) == 1 { if subtle.ConstantTimeCompare([]byte(tid), []byte(rt.ID.String())) == 1 {
found = rt found = rt
found.User = u found.User = u
} }

View file

@ -13,6 +13,7 @@ import (
"dynatron.me/x/blasphem/pkg/components" "dynatron.me/x/blasphem/pkg/components"
"dynatron.me/x/blasphem/pkg/config" "dynatron.me/x/blasphem/pkg/config"
"dynatron.me/x/blasphem/pkg/storage" "dynatron.me/x/blasphem/pkg/storage"
"dynatron.me/x/blasphem/pkg/wsapi"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@ -82,6 +83,7 @@ func New(cfg *config.Config) (b *Blas, err error) {
Bus: bus.New(), Bus: bus.New(),
Config: cfg, Config: cfg,
components: make(components.ComponentStore), components: make(components.ComponentStore),
WebSocketManager: wsapi.NewManager(),
} }
err = b.openStore() err = b.openStore()

View file

@ -36,7 +36,7 @@ type WebSocketSession interface {
Blas() Blas Blas() Blas
} }
type Handler func(wss WebSocketSession, msg interface{}) error type Handler func(wss WebSocketSession, msgID int, msg interface{}) error
type NewData func() interface{} type NewData func() interface{}
type Shutdowner interface { type Shutdowner interface {

View file

@ -15,6 +15,7 @@ import (
var ( var (
NoSuchHandlerErr = errors.New("bad websocket command") NoSuchHandlerErr = errors.New("bad websocket command")
NoMessageIDErr = errors.New("no message ID")
) )
type Type string type Type string
@ -113,6 +114,30 @@ type cmdMsg struct {
} }
type MsgType string type MsgType string
const (
ResultMsgType MsgType = "result"
)
type Error struct {
Code string `json:"code"`
Message string `json:"message"`
}
type WSError struct {
ID *int `json:"id,omitempty"`
Type MsgType `json:"type"`
Success bool `json:"success"`
Error Error `json:"error"`
}
func (ws *cmdHandler) writeError(id int, err Error) error {
return ws.WriteJSON(WSError{
ID: &id,
Type: ResultMsgType,
Success: false,
Error: err,
})
}
func (ws *cmdHandler) handleMsg(r io.Reader) error { func (ws *cmdHandler) handleMsg(r io.Reader) error {
var msgMap map[string]interface{} var msgMap map[string]interface{}
@ -126,11 +151,33 @@ func (ws *cmdHandler) handleMsg(r io.Reader) error {
return NoSuchHandlerErr return NoSuchHandlerErr
} }
newData, hand, err := ws.b.WSCommandHandler(msgType) idFl, ok := msgMap["id"].(float64)
if !ok { if !ok {
return ws.WriteJSON(
WSError{
Type: ResultMsgType,
Success: false,
Error: Error{
Code: "invalid_id",
Message: "command has no ID",
},
})
}
id := int(idFl)
newData, hand, err := ws.b.WSCommandHandler(msgType)
switch err {
case nil:
case NoSuchHandlerErr:
return ws.writeError(id, Error{
Code: "invalid_type",
Message: "no such command",
})
default:
return err return err
} }
nd := newData() nd := newData()
return hand(ws, nd) return hand(ws, id, nd)
} }

View file

@ -16,7 +16,7 @@ type authPhase struct {
func (ws *wsSession) sendAuthRequired() error { func (ws *wsSession) sendAuthRequired() error {
authReq := &struct { authReq := &struct {
MsgBase MsgBase
Version string `json:"version"` Version string `json:"ha_version"`
}{ }{
MsgBase{"auth_required"}, MsgBase{"auth_required"},
ws.b.Version(), ws.b.Version(),
@ -37,13 +37,12 @@ func (ap *authPhase) finishAuth(rt *auth.RefreshToken) {
ap.user = rt.User ap.user = rt.User
ap.refreshToken = rt ap.refreshToken = rt
ap.h = &cmdHandler{ap.wsSession} ap.h = &cmdHandler{ap.wsSession}
ap.sendAuthOK()
} }
func (ap *authPhase) sendAuthOK() error { func (ap *authPhase) sendAuthOK() error {
return ap.WriteJSON(struct { return ap.WriteJSON(struct {
Type string `json:"type"` Type string `json:"type"`
Version string `json:"version"` Version string `json:"ha_version"`
}{Type: "auth_ok", Version: ap.Blas().Version()}) }{Type: "auth_ok", Version: ap.Blas().Version()})
} }