From dc92f67fb208ccc02849210728b95bc6feca4b99 Mon Sep 17 00:00:00 2001 From: Neel Virdy Date: Mon, 21 Nov 2022 11:47:00 -0500 Subject: [PATCH 1/7] IsSession and admin password check --- api/v1/handlers.go | 12 ++++++++---- constants/constants.go | 3 +++ main.go | 6 ++++++ util/users.go | 1 + 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/api/v1/handlers.go b/api/v1/handlers.go index 533099f2..316796d7 100644 --- a/api/v1/handlers.go +++ b/api/v1/handlers.go @@ -2673,7 +2673,7 @@ func (s *apiV1) handleRegisterUser(c echo.Context) error { } } - authToken, err := s.newAuthTokenForUser(newUser, time.Now().Add(constants.TokenExpiryDurationRegister), nil, TOKEN_LABEL_ON_REGISTER) + authToken, err := s.newAuthTokenForUser(newUser, time.Now().Add(constants.TokenExpiryDurationRegister), nil, TOKEN_LABEL_ON_REGISTER, true) if err != nil { return err } @@ -2740,7 +2740,7 @@ func (s *apiV1) handleLoginUser(c echo.Context) error { } } - authToken, err := s.newAuthTokenForUser(&user, time.Now().Add(constants.TokenExpiryDurationLogin), nil, TOKEN_LABEL_ON_LOGIN) + authToken, err := s.newAuthTokenForUser(&user, time.Now().Add(constants.TokenExpiryDurationLogin), nil, TOKEN_LABEL_ON_LOGIN, true) if err != nil { return err } @@ -2828,7 +2828,7 @@ func (s *apiV1) handleGetUserStats(c echo.Context, u *util.User) error { return c.JSON(http.StatusOK, stats) } -func (s *apiV1) newAuthTokenForUser(user *util.User, expiry time.Time, perms []string, label string) (*util.AuthToken, error) { +func (s *apiV1) newAuthTokenForUser(user *util.User, expiry time.Time, perms []string, label string, isSession bool) (*util.AuthToken, error) { if len(perms) > 1 { return nil, fmt.Errorf("invalid perms") } @@ -2853,6 +2853,7 @@ func (s *apiV1) newAuthTokenForUser(user *util.User, expiry time.Time, perms []s User: user.ID, Expiry: expiry, UploadOnly: uploadOnly, + IsSession: isSession, } if err := s.DB.Create(authToken).Error; err != nil { return nil, err @@ -2930,6 +2931,7 @@ type getApiKeysResp struct { TokenHash string `json:"tokenHash"` Label string `json:"label"` Expiry time.Time `json:"expiry"` + IsSession bool `json:"isSession"` } // handleUserRevokeApiKey godoc @@ -2986,7 +2988,7 @@ func (s *apiV1) handleUserCreateApiKey(c echo.Context, u *util.User) error { label := c.QueryParam("label") - authToken, err := s.newAuthTokenForUser(u, expiry, perms, label) + authToken, err := s.newAuthTokenForUser(u, expiry, perms, label, false) if err != nil { return err } @@ -2996,6 +2998,7 @@ func (s *apiV1) handleUserCreateApiKey(c echo.Context, u *util.User) error { TokenHash: authToken.TokenHash, Label: authToken.Label, Expiry: authToken.Expiry, + IsSession: authToken.IsSession, }) } @@ -3022,6 +3025,7 @@ func (s *apiV1) handleUserGetApiKeys(c echo.Context, u *util.User) error { TokenHash: k.TokenHash, Label: k.Label, Expiry: k.Expiry, + IsSession: k.IsSession, }) } diff --git a/constants/constants.go b/constants/constants.go index 5f10bb9f..86099fff 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -1,6 +1,7 @@ package constants import ( + "regexp" "time" "github.com/filecoin-project/go-state-types/abi" @@ -40,6 +41,8 @@ const TokenExpiryDurationLogin = time.Hour * 24 * 30 // 30 days const TokenExpiryDurationDefault = time.Hour * 24 * 30 // 30 days const TokenExpiryDurationPermanent = time.Hour * 24 * 365 * 100 // 100 years +var PasswordRegex = regexp.MustCompile(`^[A-Za-z\d]{8,}$`) + var DealMaxPrice abi.TokenAmount var VerifiedDealMaxPrice = abi.NewTokenAmount(0) diff --git a/main.go b/main.go index 840ed4d5..9b5ca72e 100644 --- a/main.go +++ b/main.go @@ -528,6 +528,11 @@ func main() { return errors.New("setup password cannot be empty") } + matched := constants.PasswordRegex.MatchString(password) + if !matched { + return errors.New("password must be at least eight characters and contain at least one letter and one number") + } + db, err := setupDatabase(cfg.DatabaseConnString) if err != nil { return err @@ -573,6 +578,7 @@ func main() { Label: TOKEN_LABEL_ADMIN, User: newUser.ID, Expiry: time.Now().Add(constants.TokenExpiryDurationAdmin), + IsSession: false, } if err := db.Create(authToken).Error; err != nil { return fmt.Errorf("admin token creation failed: %w", err) diff --git a/util/users.go b/util/users.go index b171f024..7d1372c4 100644 --- a/util/users.go +++ b/util/users.go @@ -36,6 +36,7 @@ type AuthToken struct { User uint UploadOnly bool Expiry time.Time + IsSession bool } type InviteCode struct { From ddc51e5a66cebe5840857f27adf9a829254364b5 Mon Sep 17 00:00:00 2001 From: Neel Virdy Date: Tue, 10 Jan 2023 16:26:32 -0500 Subject: [PATCH 2/7] Fix admin password check --- constants/constants.go | 20 +++++++++++++++++++- main.go | 4 ++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/constants/constants.go b/constants/constants.go index 86099fff..6e6a04bf 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -41,7 +41,25 @@ const TokenExpiryDurationLogin = time.Hour * 24 * 30 // 30 days const TokenExpiryDurationDefault = time.Hour * 24 * 30 // 30 days const TokenExpiryDurationPermanent = time.Hour * 24 * 365 * 100 // 100 years -var PasswordRegex = regexp.MustCompile(`^[A-Za-z\d]{8,}$`) +var AdminPasswordLengthAndAlphanumericRegex = regexp.MustCompile(`^[A-Za-z\d]{8,}$`) +var AdminPasswordContainsAlphaRegex = regexp.MustCompile(`[A-Za-z]`) +var AdminPasswordContainsNumericRegex = regexp.MustCompile(`\d`) + +var AdminPasswordRegexes = []*regexp.Regexp{ + AdminPasswordLengthAndAlphanumericRegex, + AdminPasswordContainsAlphaRegex, + AdminPasswordContainsNumericRegex, +} + +func IsAdminPasswordValid(password string) bool { + for _, regex := range AdminPasswordRegexes { + ok := regex.MatchString(password) + if !ok { + return false + } + } + return true +} var DealMaxPrice abi.TokenAmount var VerifiedDealMaxPrice = abi.NewTokenAmount(0) diff --git a/main.go b/main.go index 9b5ca72e..68370f33 100644 --- a/main.go +++ b/main.go @@ -528,8 +528,8 @@ func main() { return errors.New("setup password cannot be empty") } - matched := constants.PasswordRegex.MatchString(password) - if !matched { + ok := constants.IsAdminPasswordValid(password) + if !ok { return errors.New("password must be at least eight characters and contain at least one letter and one number") } From 2bcd1e3ab032aa67c9a15abca93757840b29d818 Mon Sep 17 00:00:00 2001 From: Neel Virdy Date: Tue, 10 Jan 2023 16:57:06 -0500 Subject: [PATCH 3/7] Don't create admin token on setup, not needed anymore --- main.go | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/main.go b/main.go index 68370f33..bad0e72f 100644 --- a/main.go +++ b/main.go @@ -570,21 +570,6 @@ func main() { if err := db.Create(newUser).Error; err != nil { return fmt.Errorf("admin user creation failed: %w", err) } - - token := "EST" + uuid.New().String() + "ARY" - authToken := &util.AuthToken{ - Token: token, - TokenHash: util.GetTokenHash(token), - Label: TOKEN_LABEL_ADMIN, - User: newUser.ID, - Expiry: time.Now().Add(constants.TokenExpiryDurationAdmin), - IsSession: false, - } - if err := db.Create(authToken).Error; err != nil { - return fmt.Errorf("admin token creation failed: %w", err) - } - - fmt.Printf("Auth Token: %v\n", authToken.Token) return nil }, }, { From 59a6dde82208547e2fa437d18e5bbeb88d5ad0e4 Mon Sep 17 00:00:00 2001 From: Neel Virdy Date: Tue, 10 Jan 2023 17:13:16 -0500 Subject: [PATCH 4/7] Add admin username validation for bcrypt --- constants/constants.go | 6 ++++++ main.go | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/constants/constants.go b/constants/constants.go index 6e6a04bf..b7323415 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -41,6 +41,12 @@ const TokenExpiryDurationLogin = time.Hour * 24 * 30 // 30 days const TokenExpiryDurationDefault = time.Hour * 24 * 30 // 30 days const TokenExpiryDurationPermanent = time.Hour * 24 * 365 * 100 // 100 years +var AdminUsernameAlphanumericRegex = regexp.MustCompile(`^[A-Za-z\d]{1,32}$`) + +func IsAdminUsernameValid(username string) bool { + return AdminUsernameAlphanumericRegex.MatchString(username) +} + var AdminPasswordLengthAndAlphanumericRegex = regexp.MustCompile(`^[A-Za-z\d]{8,}$`) var AdminPasswordContainsAlphaRegex = regexp.MustCompile(`[A-Za-z]`) var AdminPasswordContainsNumericRegex = regexp.MustCompile(`\d`) diff --git a/main.go b/main.go index bad0e72f..09823b5d 100644 --- a/main.go +++ b/main.go @@ -523,12 +523,17 @@ func main() { return errors.New("setup username cannot be empty") } + ok := constants.IsAdminUsernameValid(username) + if !ok { + return errors.New("username must be alphanumeric and 1-32 characters") + } + password := cctx.String("password") if password == "" { return errors.New("setup password cannot be empty") } - ok := constants.IsAdminPasswordValid(password) + ok = constants.IsAdminPasswordValid(password) if !ok { return errors.New("password must be at least eight characters and contain at least one letter and one number") } From 8accb2c742a11a9c524575f22d3e6435efb3d61f Mon Sep 17 00:00:00 2001 From: Neel Virdy Date: Mon, 16 Jan 2023 16:12:38 -0800 Subject: [PATCH 5/7] Update readme setup instructions --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 58f055d6..072dbefe 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,7 @@ To run locally in a 'dev' environment, first run: ./estuary setup --username= --password= ``` -Save the auth token that this outputs, you will need it for interacting with -and controlling the node. This username and password won't work to log in using the front end (estuary-www), but the auth token will. +Save the credentials you use here, you will need them to login to the estuary-www frontend. NOTE: if you want to use a different database than a sqlite instance stored in your local directory, you will need to configure that with the `--database` flag, like so: `./estuary setup --username= --password= --database=XXXXX` From f56257f915b1026485b4a3d4b365100c1e478c14 Mon Sep 17 00:00:00 2001 From: Neel Virdy Date: Wed, 18 Jan 2023 12:27:28 -0500 Subject: [PATCH 6/7] Re-add admin token gen on setup, make postman-test admin creds valid --- .github/workflows/postman-tests.yml | 2 +- main.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/postman-tests.yml b/.github/workflows/postman-tests.yml index 462d8248..e5c52724 100644 --- a/.github/workflows/postman-tests.yml +++ b/.github/workflows/postman-tests.yml @@ -41,7 +41,7 @@ jobs: npm install - name: Setup - run: echo "APIKEY=$(./estuary setup --username admin --password password | sed -e's/.*EST/EST/g' | tail -n1)" >> $GITHUB_ENV + run: echo "APIKEY=$(./estuary setup --username admin --password password1 | sed -e's/.*EST/EST/g' | tail -n1)" >> $GITHUB_ENV - name: Run Estuary run: | diff --git a/main.go b/main.go index 09823b5d..268d4c87 100644 --- a/main.go +++ b/main.go @@ -575,6 +575,20 @@ func main() { if err := db.Create(newUser).Error; err != nil { return fmt.Errorf("admin user creation failed: %w", err) } + + token := "EST" + uuid.New().String() + "ARY" + authToken := &util.AuthToken{ + Token: token, + TokenHash: util.GetTokenHash(token), + Label: TOKEN_LABEL_ADMIN, + User: newUser.ID, + Expiry: time.Now().Add(constants.TokenExpiryDurationAdmin), + } + if err := db.Create(authToken).Error; err != nil { + return fmt.Errorf("admin token creation failed: %w", err) + } + + fmt.Printf("Auth Token: %v\n", authToken.Token) return nil }, }, { From ab4c5a0c8ccddc3e4f31daafda3e031a77e4f877 Mon Sep 17 00:00:00 2001 From: neelvirdy Date: Wed, 18 Jan 2023 17:28:10 +0000 Subject: [PATCH 7/7] docs: update swagger docs --- docs/docs.go | 3 +++ docs/swagger.json | 3 +++ docs/swagger.yaml | 2 ++ 3 files changed, 8 insertions(+) diff --git a/docs/docs.go b/docs/docs.go index c6fc4bea..0abff7d6 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -3403,6 +3403,9 @@ const docTemplate = `{ "expiry": { "type": "string" }, + "isSession": { + "type": "boolean" + }, "label": { "type": "string" }, diff --git a/docs/swagger.json b/docs/swagger.json index ffa68a26..3d18dc80 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -3396,6 +3396,9 @@ "expiry": { "type": "string" }, + "isSession": { + "type": "boolean" + }, "label": { "type": "string" }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index dc8fbb87..bd3c98d8 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -52,6 +52,8 @@ definitions: properties: expiry: type: string + isSession: + type: boolean label: type: string token: