Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leverage Mattress | Refactor Config #164

Merged
merged 4 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion backend/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/GenerateNU/sac/backend

go 1.21.1
go 1.21.6

require (
github.com/go-playground/validator/v10 v10.17.0
Expand All @@ -13,6 +13,11 @@ require (
gorm.io/gorm v1.25.6
)

require (
github.com/awnumar/memcall v0.2.0 // indirect
github.com/awnumar/memguard v0.22.4 // indirect
)

require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
Expand All @@ -21,6 +26,7 @@ require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/garrettladley/mattress v0.2.0
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/spec v0.20.4 // indirect
Expand Down
7 changes: 7 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/awnumar/memcall v0.2.0 h1:sRaogqExTOOkkNwO9pzJsL8jrOV29UuUW7teRMfbqtI=
github.com/awnumar/memcall v0.2.0/go.mod h1:S911igBPR9CThzd/hYQQmTc9SWNu3ZHIlCGaWsWsoJo=
github.com/awnumar/memguard v0.22.4 h1:1PLgKcgGPeExPHL8dCOWGVjIbQUBgJv9OL0F/yE1PqQ=
github.com/awnumar/memguard v0.22.4/go.mod h1:+APmZGThMBWjnMlKiSM1X7MVpbIVewen2MTkqWkA/zE=
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -17,6 +21,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/garrettladley/mattress v0.2.0 h1:+XUdsv9NO2s4JL+8exvAFziw0b1kv/0WlQo2Dlxat+w=
github.com/garrettladley/mattress v0.2.0/go.mod h1:OWKIRc9wC3gtD3Ng/nUuNEiR1TJvRYLmn/KZYw9nl5Q=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
Expand Down Expand Up @@ -153,6 +159,7 @@ golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
49 changes: 25 additions & 24 deletions backend/src/auth/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ import (
"github.com/GenerateNU/sac/backend/src/errors"
"github.com/GenerateNU/sac/backend/src/types"

m "github.com/garrettladley/mattress"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt"
)

func CreateTokenPair(id string, role string, authSettings config.AuthSettings) (*string, *string, *errors.Error) {
accessToken, catErr := CreateAccessToken(id, role, authSettings.AccessTokenExpiry, authSettings.AccessToken)
accessToken, catErr := CreateAccessToken(id, role, authSettings.AccessTokenExpiry, authSettings.AccessKey)
if catErr != nil {
return nil, nil, catErr
}

refreshToken, crtErr := CreateRefreshToken(id, authSettings.RefreshTokenExpiry, authSettings.RefreshToken)
refreshToken, crtErr := CreateRefreshToken(id, authSettings.RefreshTokenExpiry, authSettings.RefreshKey)
if crtErr != nil {
return nil, nil, crtErr
}
Expand All @@ -26,7 +27,7 @@ func CreateTokenPair(id string, role string, authSettings config.AuthSettings) (
}

// CreateAccessToken creates a new access token for the user
func CreateAccessToken(id string, role string, accessExpiresAfter uint, accessTokenSecret string) (*string, *errors.Error) {
func CreateAccessToken(id string, role string, accessExpiresAfter uint, accessToken *m.Secret[string]) (*string, *errors.Error) {
if id == "" || role == "" {
return nil, &errors.FailedToCreateAccessToken
}
Expand All @@ -40,16 +41,16 @@ func CreateAccessToken(id string, role string, accessExpiresAfter uint, accessTo
Role: role,
})

accessToken, err := SignToken(accessTokenClaims, accessTokenSecret)
returnedAccessToken, err := SignToken(accessTokenClaims, accessToken)
if err != nil {
return nil, err
}

return accessToken, nil
return returnedAccessToken, nil
}

// CreateRefreshToken creates a new refresh token for the user
func CreateRefreshToken(id string, refreshExpiresAfter uint, refreshTokenSecret string) (*string, *errors.Error) {
func CreateRefreshToken(id string, refreshExpiresAfter uint, refreshKey *m.Secret[string]) (*string, *errors.Error) {
if id == "" {
return nil, &errors.FailedToCreateRefreshToken
}
Expand All @@ -60,20 +61,20 @@ func CreateRefreshToken(id string, refreshExpiresAfter uint, refreshTokenSecret
ExpiresAt: time.Now().Add(time.Hour * 24 * time.Duration(refreshExpiresAfter)).Unix(),
})

refreshToken, err := SignToken(refreshTokenClaims, refreshTokenSecret)
returnedRefreshToken, err := SignToken(refreshTokenClaims, refreshKey)
if err != nil {
return nil, err
}

return refreshToken, nil
return returnedRefreshToken, nil
}

func SignToken(token *jwt.Token, secret string) (*string, *errors.Error) {
if token == nil || secret == "" {
func SignToken(token *jwt.Token, key *m.Secret[string]) (*string, *errors.Error) {
if token == nil || key.Expose() == "" {
return nil, &errors.FailedToSignToken
}

tokenString, err := token.SignedString([]byte(secret))
tokenString, err := token.SignedString([]byte(key.Expose()))
if err != nil {
return nil, &errors.FailedToSignToken
}
Expand Down Expand Up @@ -101,9 +102,9 @@ func ExpireCookie(name string) *fiber.Cookie {
}

// RefreshAccessToken refreshes the access token
func RefreshAccessToken(refreshCookie string, role string, refreshTokenSecret string, accessExpiresAfter uint, accessTokenSecret string) (*string, *errors.Error) {
func RefreshAccessToken(refreshCookie string, role string, refreshKey *m.Secret[string], accessExpiresAfter uint, accessKey *m.Secret[string]) (*string, *errors.Error) {
// Parse the refresh token
refreshToken, err := ParseRefreshToken(refreshCookie, refreshTokenSecret)
refreshToken, err := ParseRefreshToken(refreshCookie, refreshKey)
if err != nil {
return nil, &errors.FailedToParseRefreshToken
}
Expand All @@ -115,7 +116,7 @@ func RefreshAccessToken(refreshCookie string, role string, refreshTokenSecret st
}

// Create a new access token
accessToken, catErr := CreateAccessToken(claims.Issuer, role, accessExpiresAfter, accessTokenSecret)
accessToken, catErr := CreateAccessToken(claims.Issuer, role, accessExpiresAfter, accessKey)
if catErr != nil {
return nil, &errors.FailedToCreateAccessToken
}
Expand All @@ -124,22 +125,22 @@ func RefreshAccessToken(refreshCookie string, role string, refreshTokenSecret st
}

// ParseAccessToken parses the access token
func ParseAccessToken(cookie string, accessTokenSecret string) (*jwt.Token, error) {
func ParseAccessToken(cookie string, accessKey *m.Secret[string]) (*jwt.Token, error) {
return jwt.ParseWithClaims(cookie, &types.CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(accessTokenSecret), nil
return []byte(accessKey.Expose()), nil
})
}

// ParseRefreshToken parses the refresh token
func ParseRefreshToken(cookie string, refreshTokenSecret string) (*jwt.Token, error) {
func ParseRefreshToken(cookie string, refreshKey *m.Secret[string]) (*jwt.Token, error) {
return jwt.ParseWithClaims(cookie, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(refreshTokenSecret), nil
return []byte(refreshKey.Expose()), nil
})
}

// GetRoleFromToken gets the role from the custom claims
func GetRoleFromToken(tokenString string, accessTokenSecret string) (*string, error) {
token, err := ParseAccessToken(tokenString, accessTokenSecret)
func GetRoleFromToken(tokenString string, accessKey *m.Secret[string]) (*string, error) {
token, err := ParseAccessToken(tokenString, accessKey)
if err != nil {
return nil, err
}
Expand All @@ -153,8 +154,8 @@ func GetRoleFromToken(tokenString string, accessTokenSecret string) (*string, er
}

// ExtractClaims extracts the claims from the token
func ExtractAccessClaims(tokenString string, accessTokenSecret string) (*types.CustomClaims, *errors.Error) {
token, err := ParseAccessToken(tokenString, accessTokenSecret)
func ExtractAccessClaims(tokenString string, accessKey *m.Secret[string]) (*types.CustomClaims, *errors.Error) {
token, err := ParseAccessToken(tokenString, accessKey)
if err != nil {
return nil, &errors.FailedToParseAccessToken
}
Expand All @@ -168,8 +169,8 @@ func ExtractAccessClaims(tokenString string, accessTokenSecret string) (*types.C
}

// ExtractClaims extracts the claims from the token
func ExtractRefreshClaims(tokenString string, refreshTokenSecret string) (*jwt.StandardClaims, *errors.Error) {
token, err := ParseRefreshToken(tokenString, refreshTokenSecret)
func ExtractRefreshClaims(tokenString string, refreshKey *m.Secret[string]) (*jwt.StandardClaims, *errors.Error) {
token, err := ParseRefreshToken(tokenString, refreshKey)
if err != nil {
return nil, &errors.FailedToParseRefreshToken
}
Expand Down
7 changes: 7 additions & 0 deletions backend/src/config/application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package config

type ApplicationSettings struct {
Port uint16 `yaml:"port"`
Host string `yaml:"host"`
BaseUrl string `yaml:"baseurl"`
}
40 changes: 40 additions & 0 deletions backend/src/config/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package config

import (
"errors"

m "github.com/garrettladley/mattress"
)

type AuthSettings struct {
AccessKey *m.Secret[string]
RefreshKey *m.Secret[string]
AccessTokenExpiry uint
RefreshTokenExpiry uint
}

type intermediateAuthSettings struct {
AccessKey string `yaml:"accesskey"`
RefreshKey string `yaml:"refreshkey"`
AccessTokenExpiry uint `yaml:"accesstokenexpiry"`
RefreshTokenExpiry uint `yaml:"refreshtokenexpiry"`
}

func (int *intermediateAuthSettings) into() (*AuthSettings, error) {
accessToken, err := m.NewSecret(int.AccessKey)
if err != nil {
return nil, errors.New("failed to create secret from access key")
}

refreshToken, err := m.NewSecret(int.RefreshKey)
if err != nil {
return nil, errors.New("failed to create secret from refresh key")
}

return &AuthSettings{
AccessKey: accessToken,
RefreshKey: refreshToken,
AccessTokenExpiry: int.AccessTokenExpiry,
RefreshTokenExpiry: int.RefreshTokenExpiry,
}, nil
}
Loading
Loading