From d3bb371e9ec6ac769fdb84e5f34859ea442c373d Mon Sep 17 00:00:00 2001 From: David May <1301201+wass3r@users.noreply.github.com> Date: Mon, 11 Jan 2021 18:15:28 +0000 Subject: [PATCH] feat(token): add refresh token info (#87) --- constants/token.go | 11 ++++++ database/user.go | 40 ++++++++++++------- database/user_test.go | 46 ++++++++++++---------- library/login.go | 90 +------------------------------------------ library/login_test.go | 33 ---------------- library/user.go | 41 ++++++++++++++++---- library/user_test.go | 9 +++++ metadata.go | 9 ++++- 8 files changed, 114 insertions(+), 165 deletions(-) create mode 100644 constants/token.go diff --git a/constants/token.go b/constants/token.go new file mode 100644 index 00000000..ec8c9b99 --- /dev/null +++ b/constants/token.go @@ -0,0 +1,11 @@ +// Copyright (c) 2020 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package constants + +// Constants for tokens. +const ( + // RefreshTokenName is the name associated with the refresh token. + RefreshTokenName = "vela_refresh_token" +) diff --git a/database/user.go b/database/user.go index b4aa3e6a..a86be0a3 100644 --- a/database/user.go +++ b/database/user.go @@ -27,6 +27,10 @@ var ( // User type has an empty Name field provided. ErrEmptyUserName = errors.New("empty user name provided") + // ErrEmptyUserRefreshToken defines the error type when a + // User type has an empty RefreshToken field provided. + ErrEmptyUserRefreshToken = errors.New("empty user refresh token provided") + // ErrEmptyUserToken defines the error type when a // User type has an empty Token field provided. ErrEmptyUserToken = errors.New("empty user token provided") @@ -42,13 +46,14 @@ var ( // User is the database representation of a user. type User struct { - ID sql.NullInt64 `sql:"id"` - Name sql.NullString `sql:"name"` - Token sql.NullString `sql:"token"` - Hash sql.NullString `sql:"hash"` - Favorites pq.StringArray `sql:"favorites"` - Active sql.NullBool `sql:"active"` - Admin sql.NullBool `sql:"admin"` + ID sql.NullInt64 `sql:"id"` + Name sql.NullString `sql:"name"` + RefreshToken sql.NullString `sql:"refresh_token"` + Token sql.NullString `sql:"token"` + Hash sql.NullString `sql:"hash"` + Favorites pq.StringArray `sql:"favorites"` + Active sql.NullBool `sql:"active"` + Admin sql.NullBool `sql:"admin"` } // Nullify ensures the valid flag for @@ -72,6 +77,11 @@ func (u *User) Nullify() *User { u.Name.Valid = false } + // check if the RefreshToken field should be false + if len(u.RefreshToken.String) == 0 { + u.RefreshToken.Valid = false + } + // check if the Token field should be false if len(u.Token.String) == 0 { u.Token.Valid = false @@ -92,6 +102,7 @@ func (u *User) ToLibrary() *library.User { user.SetID(u.ID.Int64) user.SetName(u.Name.String) + user.SetRefreshToken(u.RefreshToken.String) user.SetToken(u.Token.String) user.SetHash(u.Hash.String) user.SetActive(u.Active.Bool) @@ -142,13 +153,14 @@ func (u *User) Validate() error { // to a database User type. func UserFromLibrary(u *library.User) *User { user := &User{ - ID: sql.NullInt64{Int64: u.GetID(), Valid: true}, - Name: sql.NullString{String: u.GetName(), Valid: true}, - Token: sql.NullString{String: u.GetToken(), Valid: true}, - Hash: sql.NullString{String: u.GetHash(), Valid: true}, - Active: sql.NullBool{Bool: u.GetActive(), Valid: true}, - Admin: sql.NullBool{Bool: u.GetAdmin(), Valid: true}, - Favorites: u.GetFavorites(), + ID: sql.NullInt64{Int64: u.GetID(), Valid: true}, + Name: sql.NullString{String: u.GetName(), Valid: true}, + RefreshToken: sql.NullString{String: u.GetRefreshToken(), Valid: true}, + Token: sql.NullString{String: u.GetToken(), Valid: true}, + Hash: sql.NullString{String: u.GetHash(), Valid: true}, + Active: sql.NullBool{Bool: u.GetActive(), Valid: true}, + Admin: sql.NullBool{Bool: u.GetAdmin(), Valid: true}, + Favorites: u.GetFavorites(), } return user.Nullify() diff --git a/database/user_test.go b/database/user_test.go index 12659fa2..78e2a19a 100644 --- a/database/user_test.go +++ b/database/user_test.go @@ -18,12 +18,13 @@ func TestDatabase_User_Nullify(t *testing.T) { var u *User want := &User{ - ID: sql.NullInt64{Int64: 0, Valid: false}, - Name: sql.NullString{String: "", Valid: false}, - Token: sql.NullString{String: "", Valid: false}, - Hash: sql.NullString{String: "", Valid: false}, - Active: sql.NullBool{Bool: false, Valid: false}, - Admin: sql.NullBool{Bool: false, Valid: false}, + ID: sql.NullInt64{Int64: 0, Valid: false}, + Name: sql.NullString{String: "", Valid: false}, + RefreshToken: sql.NullString{String: "", Valid: false}, + Token: sql.NullString{String: "", Valid: false}, + Hash: sql.NullString{String: "", Valid: false}, + Active: sql.NullBool{Bool: false, Valid: false}, + Admin: sql.NullBool{Bool: false, Valid: false}, } // setup tests @@ -61,6 +62,7 @@ func TestDatabase_User_ToLibrary(t *testing.T) { want.SetID(1) want.SetName("octocat") + want.SetRefreshToken("superSecretRefreshToken") want.SetToken("superSecretToken") want.SetHash("superSecretHash") want.SetFavorites([]string{"github/octocat"}) @@ -104,18 +106,20 @@ func TestDatabase_User_Validate(t *testing.T) { { // no hash set for user failure: true, user: &User{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - Token: sql.NullString{String: "superSecretToken", Valid: true}, + ID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + RefreshToken: sql.NullString{String: "superSecretRefreshToken", Valid: true}, + Token: sql.NullString{String: "superSecretToken", Valid: true}, }, }, { // invalid name set for user failure: true, user: &User{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - Name: sql.NullString{String: "!@#$%^&*()", Valid: true}, - Token: sql.NullString{String: "superSecretToken", Valid: true}, - Hash: sql.NullString{String: "superSecretHash", Valid: true}, + ID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "!@#$%^&*()", Valid: true}, + RefreshToken: sql.NullString{String: "superSecretRefreshToken", Valid: true}, + Token: sql.NullString{String: "superSecretToken", Valid: true}, + Hash: sql.NullString{String: "superSecretHash", Valid: true}, }, }, { // invalid favorites set for user @@ -154,6 +158,7 @@ func TestDatabase_UserFromLibrary(t *testing.T) { u.SetID(1) u.SetName("octocat") + u.SetRefreshToken("superSecretRefreshToken") u.SetToken("superSecretToken") u.SetHash("superSecretHash") u.SetFavorites([]string{"github/octocat"}) @@ -174,13 +179,14 @@ func TestDatabase_UserFromLibrary(t *testing.T) { // type with all fields set to a fake value. func testUser() *User { return &User{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - Token: sql.NullString{String: "superSecretToken", Valid: true}, - Hash: sql.NullString{String: "superSecretHash", Valid: true}, - Favorites: []string{"github/octocat"}, - Active: sql.NullBool{Bool: true, Valid: true}, - Admin: sql.NullBool{Bool: false, Valid: true}, + ID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + RefreshToken: sql.NullString{String: "superSecretRefreshToken", Valid: true}, + Token: sql.NullString{String: "superSecretToken", Valid: true}, + Hash: sql.NullString{String: "superSecretHash", Valid: true}, + Favorites: []string{"github/octocat"}, + Active: sql.NullBool{Bool: true, Valid: true}, + Admin: sql.NullBool{Bool: false, Valid: true}, } } diff --git a/library/login.go b/library/login.go index 25c5046b..10230e6f 100644 --- a/library/login.go +++ b/library/login.go @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// nolint:dupl // false positive due to similarity with template.go package library import "fmt" @@ -21,49 +20,7 @@ import "fmt" // // swagger:model Login type Login struct { - Username *string `json:"username,omitempty"` - Password *string `json:"password,omitempty"` - OTP *string `json:"otp,omitempty"` - Token *string `json:"token,omitempty"` -} - -// GetUsername returns the Username field. -// -// When the provided Login type is nil, or the field within -// the type is nil, it returns the zero value for the field. -func (l *Login) GetUsername() string { - // return zero value if Login type or Username field is nil - if l == nil || l.Username == nil { - return "" - } - - return *l.Username -} - -// GetPassword returns the Password field. -// -// When the provided Login type is nil, or the field within -// the type is nil, it returns the zero value for the field. -func (l *Login) GetPassword() string { - // return zero value if Login type or Password field is nil - if l == nil || l.Password == nil { - return "" - } - - return *l.Password -} - -// GetOTP returns the Username field. -// -// When the provided Login type is nil, or the field within -// the type is nil, it returns the zero value for the field. -func (l *Login) GetOTP() string { - // return zero value if Login type or OTP field is nil - if l == nil || l.OTP == nil { - return "" - } - - return *l.OTP + Token *string `json:"token,omitempty"` } // GetToken returns the Token field. @@ -79,45 +36,6 @@ func (l *Login) GetToken() string { return *l.Token } -// SetUsername sets the Username field. -// -// When the provided Login type is nil, it -// will set nothing and immediately return. -func (l *Login) SetUsername(v string) { - // return if Login type is nil - if l == nil { - return - } - - l.Username = &v -} - -// SetPassword sets the Password field. -// -// When the provided Login type is nil, it -// will set nothing and immediately return. -func (l *Login) SetPassword(v string) { - // return if Login type is nil - if l == nil { - return - } - - l.Password = &v -} - -// SetOTP sets the OTP field. -// -// When the provided Login type is nil, it -// will set nothing and immediately return. -func (l *Login) SetOTP(v string) { - // return if Login type is nil - if l == nil { - return - } - - l.OTP = &v -} - // SetToken sets the Token field. // // When the provided Login type is nil, it @@ -134,14 +52,8 @@ func (l *Login) SetToken(v string) { // String implements the Stringer interface for the Login type. func (l *Login) String() string { return fmt.Sprintf(`{ - OTP: %s, - Password: %s, Token: %s, - Username: %s, }`, - l.GetOTP(), - l.GetPassword(), l.GetToken(), - l.GetUsername(), ) } diff --git a/library/login_test.go b/library/login_test.go index 5c60a727..146e5c2a 100644 --- a/library/login_test.go +++ b/library/login_test.go @@ -38,18 +38,6 @@ func TestLibrary_Login_Getters(t *testing.T) { // run tests for _, test := range tests { - if test.login.GetUsername() != test.want.GetUsername() { - t.Errorf("GetUsername is %v, want %v", test.login.GetUsername(), test.want.GetUsername()) - } - - if test.login.GetPassword() != test.want.GetPassword() { - t.Errorf("GetPassword is %v, want %v", test.login.GetPassword(), test.want.GetPassword()) - } - - if test.login.GetOTP() != test.want.GetOTP() { - t.Errorf("GetOTP is %v, want %v", test.login.GetOTP(), test.want.GetOTP()) - } - if test.login.GetToken() != test.want.GetToken() { t.Errorf("GetToken is %v, want %v", test.login.GetToken(), test.want.GetToken()) } @@ -77,20 +65,8 @@ func TestLibrary_Login_Setters(t *testing.T) { // run tests for _, test := range tests { - test.login.SetUsername(test.want.GetUsername()) - test.login.SetPassword(test.want.GetPassword()) - test.login.SetOTP(test.want.GetOTP()) test.login.SetToken(test.want.GetToken()) - if test.login.GetUsername() != test.want.GetUsername() { - t.Errorf("SetUsername is %v, want %v", test.login.GetUsername(), test.want.GetUsername()) - } - if test.login.GetPassword() != test.want.GetPassword() { - t.Errorf("SetPassword is %v, want %v", test.login.GetPassword(), test.want.GetPassword()) - } - if test.login.GetOTP() != test.want.GetOTP() { - t.Errorf("SetOTP is %v, want %v", test.login.GetOTP(), test.want.GetOTP()) - } if test.login.GetToken() != test.want.GetToken() { t.Errorf("SetToken is %v, want %v", test.login.GetToken(), test.want.GetToken()) } @@ -102,15 +78,9 @@ func TestLogin_String(t *testing.T) { l := testLogin() want := fmt.Sprintf(`{ - OTP: %s, - Password: %s, Token: %s, - Username: %s, }`, - l.GetOTP(), - l.GetPassword(), l.GetToken(), - l.GetUsername(), ) // run test @@ -126,9 +96,6 @@ func TestLogin_String(t *testing.T) { func testLogin() *Login { l := new(Login) - l.SetUsername("octocat") - l.SetPassword("superSecretPassword") - l.SetOTP("123456") l.SetToken("superSecretToken") return l diff --git a/library/user.go b/library/user.go index 325490e7..18386eda 100644 --- a/library/user.go +++ b/library/user.go @@ -10,13 +10,14 @@ import "fmt" // // swagger:model User type User struct { - ID *int64 `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - Token *string `json:"token,omitempty"` - Hash *string `json:"-"` - Favorites *[]string `json:"favorites,omitempty"` - Active *bool `json:"active,omitempty"` - Admin *bool `json:"admin,omitempty"` + ID *int64 `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + RefreshToken *string `json:"-"` + Token *string `json:"-"` + Hash *string `json:"-"` + Favorites *[]string `json:"favorites,omitempty"` + Active *bool `json:"active,omitempty"` + Admin *bool `json:"admin,omitempty"` } // Environment returns a list of environment variables @@ -56,6 +57,19 @@ func (u *User) GetName() string { return *u.Name } +// GetRefreshToken returns the RefreshToken field. +// +// When the provided User type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (u *User) GetRefreshToken() string { + // return zero value if User type or RefreshToken field is nil + if u == nil || u.RefreshToken == nil { + return "" + } + + return *u.RefreshToken +} + // GetToken returns the Token field. // // When the provided User type is nil, or the field within @@ -147,6 +161,19 @@ func (u *User) SetName(v string) { u.Name = &v } +// SetRefreshToken sets the RefreshToken field. +// +// When the provided User type is nil, it +// will set nothing and immediately return. +func (u *User) SetRefreshToken(v string) { + // return if User type is nil + if u == nil { + return + } + + u.RefreshToken = &v +} + // SetToken sets the Token field. // // When the provided User type is nil, it diff --git a/library/user_test.go b/library/user_test.go index 221973ea..39c6fddb 100644 --- a/library/user_test.go +++ b/library/user_test.go @@ -53,6 +53,10 @@ func TestLibrary_User_Getters(t *testing.T) { t.Errorf("GetName is %v, want %v", test.user.GetName(), test.want.GetName()) } + if test.user.GetRefreshToken() != test.want.GetRefreshToken() { + t.Errorf("GetRefreshToken is %v, want %v", test.user.GetRefreshToken(), test.want.GetRefreshToken()) + } + if test.user.GetToken() != test.want.GetToken() { t.Errorf("GetToken is %v, want %v", test.user.GetToken(), test.want.GetToken()) } @@ -98,6 +102,7 @@ func TestLibrary_User_Setters(t *testing.T) { for _, test := range tests { test.user.SetID(test.want.GetID()) test.user.SetName(test.want.GetName()) + test.user.SetRefreshToken(test.want.GetRefreshToken()) test.user.SetToken(test.want.GetToken()) test.user.SetHash(test.want.GetHash()) test.user.SetFavorites(test.want.GetFavorites()) @@ -112,6 +117,10 @@ func TestLibrary_User_Setters(t *testing.T) { t.Errorf("SetName is %v, want %v", test.user.GetName(), test.want.GetName()) } + if test.user.GetRefreshToken() != test.want.GetRefreshToken() { + t.Errorf("SetRefreshToken is %v, want %v", test.user.GetRefreshToken(), test.want.GetRefreshToken()) + } + if test.user.GetToken() != test.want.GetToken() { t.Errorf("SetToken is %v, want %v", test.user.GetToken(), test.want.GetToken()) } diff --git a/metadata.go b/metadata.go index 7812a910..1a27d400 100644 --- a/metadata.go +++ b/metadata.go @@ -4,6 +4,8 @@ package types +import "time" + type ( // Database is the extra set of database data passed to the compiler. Database struct { @@ -26,8 +28,11 @@ type ( // Vela is the extra set of Vela data passed to the compiler. Vela struct { - Address string `json:"address"` - WebAddress string `json:"web_address"` + Address string `json:"address"` + WebAddress string `json:"web_address"` + WebOauthCallbackPath string `json:"web_oauth_callback_path"` + AccessTokenDuration time.Duration `json:"access_token_duration"` + RefreshTokenDuration time.Duration `json:"refresh_token_duration"` } // Metadata is the extra set of data passed to the compiler for