diff --git a/go.mod b/go.mod index 61336bc..c24bb65 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( require ( github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jinzhu/copier v0.3.5 // indirect github.com/labstack/gommon v0.3.1 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect diff --git a/go.sum b/go.sum index b98afe7..529222c 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= +github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/labstack/echo/v4 v4.6.1/go.mod h1:RnjgMWNDB9g/HucVWhQYNQP9PvbYf6adqftqryo7s9k= github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY= github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= diff --git a/pkg/auth/authenticator.go b/pkg/auth/authenticator.go index 346d8f6..004c3dd 100644 --- a/pkg/auth/authenticator.go +++ b/pkg/auth/authenticator.go @@ -6,6 +6,7 @@ import ( "net/http" "github.com/labstack/echo/v4" + "github.com/rs/zerolog/log" "dynatron.me/x/blasphem/pkg/frontend" "dynatron.me/x/blasphem/pkg/storage" @@ -110,6 +111,7 @@ func (a *Authenticator) Check(f *Flow, rm map[string]interface{}) error { success := p.ValidateCreds(rm) if success { + log.Info().Str("user", rm["username"].(string)).Msg("Login success") return nil } } diff --git a/pkg/auth/flow.go b/pkg/auth/flow.go index 2f9c72b..5da892a 100644 --- a/pkg/auth/flow.go +++ b/pkg/auth/flow.go @@ -7,7 +7,10 @@ import ( "strings" "time" + "github.com/jinzhu/copier" "github.com/labstack/echo/v4" + + "dynatron.me/x/blasphem/internal/common" ) type FlowStore map[FlowID]*Flow @@ -27,7 +30,8 @@ type FlowSchemaItem struct { type FlowType string const ( - TypeForm FlowType = "form" + TypeForm FlowType = "form" + TypeCreateEntry FlowType = "create_entry" ) type FlowID string @@ -41,18 +45,18 @@ type Flow struct { Type FlowType `json:"type"` ID FlowID `json:"flow_id"` Handler []*string `json:"handler"` - StepID Step `json:"step_id"` + StepID *Step `json:"step_id,omitempty"` Schema []FlowSchemaItem `json:"data_schema"` Errors interface{} `json:"errors"` DescPlace *string `json:"description_placeholders"` LastStep *string `json:"last_step"` request *FlowRequest - age time.Time + ctime time.Time } func (f *Flow) touch() { - f.age = time.Now() + f.ctime = time.Now() } func genFlowID() FlowID { @@ -77,7 +81,7 @@ const cullAge = time.Minute * 30 func (fs FlowStore) cull() { for k, v := range fs { - if time.Now().Sub(v.age) > cullAge { + if time.Now().Sub(v.ctime) > cullAge { delete(fs, k) } } @@ -113,7 +117,7 @@ func (a *Authenticator) NewFlow(r *FlowRequest) *Flow { flow := &Flow{ Type: TypeForm, ID: genFlowID(), - StepID: StepInit, + StepID: stepPtr(StepInit), Schema: sch, Handler: r.Handler, Errors: []string{}, @@ -126,8 +130,19 @@ func (a *Authenticator) NewFlow(r *FlowRequest) *Flow { return flow } +func stepPtr(s Step) *Step { return &s } + +func (f *Flow) redirect(c echo.Context) { + c.Request().Header.Set("Location", f.request.RedirectURI) +} + func (f *Flow) progress(a *Authenticator, c echo.Context) error { - switch f.StepID { + if f.StepID == nil { + c.Logger().Error("stepID is nil") + return c.String(http.StatusInternalServerError, "No Step ID") + } + + switch *f.StepID { case StepInit: rm := make(map[string]interface{}) @@ -146,9 +161,24 @@ func (f *Flow) progress(a *Authenticator, c echo.Context) error { err = a.Check(f, rm) switch err { case nil: + var finishedFlow struct { + ID FlowID `json:"flow_id"` + Handler []*string `json:"handler"` + Result string `json:"result"` + Title string `json:"title"` + Type FlowType `json:"type"` + Version int `json:"version"` + } // TODO: setup the session. delete the flow. a.Flows.Remove(f) - return c.String(http.StatusOK, "login success!") + copier.Copy(&finishedFlow, f) + finishedFlow.Type = TypeCreateEntry + finishedFlow.Title = common.AppName + finishedFlow.Version = 1 + + f.redirect(c) + + return c.JSON(http.StatusCreated, &finishedFlow) case ErrInvalidHandler: return c.String(http.StatusNotFound, err.Error()) case ErrInvalidAuth: @@ -211,6 +241,12 @@ func (a *Authenticator) LoginFlowHandler(c echo.Context) error { return c.String(http.StatusNotFound, "no such flow") } + if time.Now().Sub(flow.ctime) > cullAge { + a.Flows.Remove(flow) + + return c.String(http.StatusGone, "flow timed out") + } + return flow.progress(a, c) } diff --git a/pkg/auth/provider.go b/pkg/auth/provider.go index f372976..4b6d240 100644 --- a/pkg/auth/provider.go +++ b/pkg/auth/provider.go @@ -16,6 +16,7 @@ type User struct { Password string `json:"password"` Username string `json:"username"` } + type HomeAssistantProvider struct { AuthProviderBase `json:"-"` Users []User `json:"users"`