feat: add secret session workspace setting

This commit is contained in:
Steven 2023-06-27 22:15:26 +08:00
parent 106cdfa7da
commit 2fb0d145a2
9 changed files with 100 additions and 47 deletions

View File

@ -57,7 +57,7 @@ func (s *APIV1Service) registerAuthRoutes(g *echo.Group, secret string) {
g.POST("/auth/signup", func(c echo.Context) error {
ctx := c.Request().Context()
disallowSignUpSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: WorkspaceDisallowSignUp.String(),
Key: store.WorkspaceDisallowSignUp,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to get workspace setting").SetInternal(err)

View File

@ -22,7 +22,7 @@ func NewAPIV1Service(profile *profile.Profile, store *store.Store) *APIV1Service
func (s *APIV1Service) Start(apiGroup *echo.Group, secret string) {
apiV1Group := apiGroup.Group("/api/v1")
apiV1Group.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return JWTMiddleware(s, next, string(secret))
return JWTMiddleware(s, next, secret)
})
s.registerWorkspaceRoutes(apiV1Group)
s.registerAuthRoutes(apiV1Group, secret)
@ -31,7 +31,7 @@ func (s *APIV1Service) Start(apiGroup *echo.Group, secret string) {
redirectorGroup := apiGroup.Group("/s")
redirectorGroup.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return JWTMiddleware(s, next, string(secret))
return JWTMiddleware(s, next, secret)
})
s.registerRedirectorRoutes(redirectorGroup)
}

View File

@ -10,33 +10,18 @@ import (
"github.com/labstack/echo/v4"
)
type WorkspaceSettingKey string
const (
// WorkspaceDisallowSignUp is the key type for disallow sign up in workspace level.
WorkspaceDisallowSignUp WorkspaceSettingKey = "disallow-signup"
)
// String returns the string format of WorkspaceSettingKey type.
func (key WorkspaceSettingKey) String() string {
if key == WorkspaceDisallowSignUp {
return "disallow-signup"
}
return ""
}
type WorkspaceSetting struct {
Key WorkspaceSettingKey `json:"key"`
Value string `json:"value"`
Key string `json:"key"`
Value string `json:"value"`
}
type WorkspaceSettingUpsert struct {
Key WorkspaceSettingKey `json:"key"`
Value string `json:"value"`
Key string `json:"key"`
Value string `json:"value"`
}
func (upsert WorkspaceSettingUpsert) Validate() error {
if upsert.Key == WorkspaceDisallowSignUp {
if upsert.Key == store.WorkspaceDisallowSignUp.String() {
value := false
err := json.Unmarshal([]byte(upsert.Value), &value)
if err != nil {
@ -63,7 +48,7 @@ func (s *APIV1Service) registerWorkspaceRoutes(g *echo.Group) {
}
disallowSignUpSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: WorkspaceDisallowSignUp.String(),
Key: store.WorkspaceDisallowSignUp,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to get workspace setting")
@ -97,11 +82,11 @@ func (s *APIV1Service) registerWorkspaceRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post workspace setting request").SetInternal(err)
}
if err := upsert.Validate(); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "system setting invalidate").SetInternal(err)
return echo.NewHTTPError(http.StatusBadRequest, "Invalid system setting key or value").SetInternal(err)
}
workspaceSetting, err := s.Store.UpsertWorkspaceSetting(ctx, &store.WorkspaceSetting{
Key: upsert.Key.String(),
Key: store.WorkspaceSettingKey(upsert.Key),
Value: upsert.Value,
})
if err != nil {
@ -142,7 +127,7 @@ func (s *APIV1Service) registerWorkspaceRoutes(g *echo.Group) {
func convertWorkspaceSettingFromStore(workspaceSetting *store.WorkspaceSetting) *WorkspaceSetting {
return &WorkspaceSetting{
Key: WorkspaceSettingKey(workspaceSetting.Key),
Key: workspaceSetting.Key.String(),
Value: workspaceSetting.Value,
}
}

View File

@ -48,7 +48,7 @@ var (
}
storeInstance := store.New(db.DBInstance, profile)
s, err := server.NewServer(profile, storeInstance)
s, err := server.NewServer(ctx, profile, storeInstance)
if err != nil {
cancel()
fmt.Printf("failed to create server, error: %+v\n", err)

4
go.mod
View File

@ -18,15 +18,12 @@ require (
)
require (
github.com/gorilla/context v1.1.1 // indirect
github.com/labstack/echo/v4 v4.10.1
github.com/labstack/gommon v0.4.0 // indirect
)
require (
github.com/gorilla/securecookie v1.1.1
github.com/gorilla/sessions v1.2.1
github.com/labstack/echo-contrib v0.14.0
github.com/spf13/cobra v1.6.1
github.com/spf13/viper v1.15.0
github.com/stretchr/testify v1.8.4
@ -39,6 +36,7 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect

13
go.sum
View File

@ -47,6 +47,7 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -126,12 +127,8 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
@ -148,11 +145,11 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/labstack/echo-contrib v0.14.0 h1:tVHJjhqOcB183bzAeNDVwKgf1GWRAM6k9PvIVKEjQ/A=
github.com/labstack/echo-contrib v0.14.0/go.mod h1:0tmJZUHWLU7zGvMoxZwotRxHgUqBfW37T6bHg17SgAw=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.10.1 h1:rB+D8In9PWjsp1OpHaqK+t04nQv/SBD1IoIcXCg0lpY=
github.com/labstack/echo/v4 v4.10.1/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
@ -171,6 +168,7 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
@ -181,7 +179,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qq
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=

View File

@ -10,8 +10,6 @@ import (
"github.com/boojack/shortify/store"
"github.com/gorilla/securecookie"
"github.com/gorilla/sessions"
"github.com/labstack/echo-contrib/session"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
@ -23,7 +21,7 @@ type Server struct {
Store *store.Store
}
func NewServer(profile *profile.Profile, store *store.Store) (*Server, error) {
func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store) (*Server, error) {
e := echo.New()
e.Debug = true
e.HideBanner = true
@ -53,12 +51,15 @@ func NewServer(profile *profile.Profile, store *store.Store) (*Server, error) {
embedFrontend(e)
// In dev mode, set the const secret key to make signin session persistence.
secret := "iamshortify"
// In dev mode, we'd like to set the const secret key to make signin session persistence.
secret := "shortify"
if profile.Mode == "prod" {
secret = string(securecookie.GenerateRandomKey(16))
var err error
secret, err = s.getSystemSecretSessionName(ctx)
if err != nil {
return nil, err
}
}
e.Use(session.Middleware(sessions.NewCookieStore([]byte(secret))))
apiGroup := e.Group("")
// Register API v1 routes.
@ -88,3 +89,23 @@ func (s *Server) Shutdown(ctx context.Context) {
fmt.Printf("server stopped properly\n")
}
func (s *Server) getSystemSecretSessionName(ctx context.Context) (string, error) {
secretSessionNameValue, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: store.WorkspaceDisallowSignUp,
})
if err != nil {
return "", err
}
if secretSessionNameValue == nil || secretSessionNameValue.Value == "" {
tempSecret := securecookie.GenerateRandomKey(16)
secretSessionNameValue, err = s.Store.UpsertWorkspaceSetting(ctx, &store.WorkspaceSetting{
Key: store.WorkspaceSecretSessionName,
Value: string(tempSecret),
})
if err != nil {
return "", err
}
}
return secretSessionNameValue.Value, nil
}

View File

@ -6,13 +6,33 @@ import (
"strings"
)
type WorkspaceSettingKey string
const (
// WorkspaceDisallowSignUp is the key type for disallow sign up in workspace level.
WorkspaceDisallowSignUp WorkspaceSettingKey = "disallow-signup"
// WorkspaceSecretSessionName is the key type for secret session name.
WorkspaceSecretSessionName WorkspaceSettingKey = "secret-session-name"
)
// String returns the string format of WorkspaceSettingKey type.
func (key WorkspaceSettingKey) String() string {
switch key {
case WorkspaceDisallowSignUp:
return "disallow-signup"
case WorkspaceSecretSessionName:
return "secret-session-name"
}
return ""
}
type WorkspaceSetting struct {
Key string
Key WorkspaceSettingKey
Value string
}
type FindWorkspaceSetting struct {
Key string
Key WorkspaceSettingKey
}
func (s *Store) UpsertWorkspaceSetting(ctx context.Context, upsert *WorkspaceSetting) (*WorkspaceSetting, error) {

View File

@ -0,0 +1,30 @@
package teststore
import (
"context"
"testing"
"github.com/boojack/shortify/store"
"github.com/gorilla/securecookie"
"github.com/stretchr/testify/require"
)
func TestWorkspaceSettingStore(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
tempSecret := securecookie.GenerateRandomKey(16)
workspaceSetting, err := ts.UpsertWorkspaceSetting(ctx, &store.WorkspaceSetting{
Key: store.WorkspaceSecretSessionName,
Value: string(tempSecret),
})
require.NoError(t, err)
foundWorkspaceSetting, err := ts.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
Key: store.WorkspaceSecretSessionName,
})
require.NoError(t, err)
require.Equal(t, workspaceSetting, foundWorkspaceSetting)
workspaceSettings, err := ts.ListWorkspaceSettings(ctx, &store.FindWorkspaceSetting{})
require.NoError(t, err)
require.Equal(t, 1, len(workspaceSettings))
require.Equal(t, foundWorkspaceSetting, workspaceSettings[0])
}