feat: persist encrypted env
This commit is contained in:
@@ -17,7 +17,7 @@ import (
|
||||
)
|
||||
|
||||
func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (string, int64, error) {
|
||||
t := jwt.New(jwt.GetSigningMethod(constants.JWT_TYPE))
|
||||
t := jwt.New(jwt.GetSigningMethod(constants.EnvData.JWT_TYPE))
|
||||
expiryBound := time.Hour
|
||||
if tokenType == enum.RefreshToken {
|
||||
// expires in 1 year
|
||||
@@ -32,11 +32,11 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st
|
||||
json.Unmarshal(userBytes, &userMap)
|
||||
|
||||
customClaims := jwt.MapClaims{
|
||||
"exp": expiresAt,
|
||||
"iat": time.Now().Unix(),
|
||||
"token_type": tokenType.String(),
|
||||
"allowed_roles": strings.Split(user.Roles, ","),
|
||||
constants.JWT_ROLE_CLAIM: roles,
|
||||
"exp": expiresAt,
|
||||
"iat": time.Now().Unix(),
|
||||
"token_type": tokenType.String(),
|
||||
"allowed_roles": strings.Split(user.Roles, ","),
|
||||
constants.EnvData.JWT_ROLE_CLAIM: roles,
|
||||
}
|
||||
|
||||
for k, v := range userMap {
|
||||
@@ -77,7 +77,7 @@ func CreateAuthToken(user db.User, tokenType enum.TokenType, roles []string) (st
|
||||
|
||||
t.Claims = customClaims
|
||||
|
||||
token, err := t.SignedString([]byte(constants.JWT_SECRET))
|
||||
token, err := t.SignedString([]byte(constants.EnvData.JWT_SECRET))
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
@@ -89,7 +89,6 @@ func GetAuthToken(gc *gin.Context) (string, error) {
|
||||
token, err := GetCookie(gc)
|
||||
if err != nil || token == "" {
|
||||
// try to check in auth header for cookie
|
||||
log.Println("cookie not found checking headers")
|
||||
auth := gc.Request.Header.Get("Authorization")
|
||||
if auth == "" {
|
||||
return "", fmt.Errorf(`unauthorized`)
|
||||
@@ -105,7 +104,7 @@ func VerifyAuthToken(token string) (map[string]interface{}, error) {
|
||||
claims := jwt.MapClaims{}
|
||||
|
||||
_, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(constants.JWT_SECRET), nil
|
||||
return []byte(constants.EnvData.JWT_SECRET), nil
|
||||
})
|
||||
if err != nil {
|
||||
return res, err
|
||||
@@ -126,7 +125,7 @@ func VerifyAuthToken(token string) (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
func CreateAdminAuthToken(tokenType enum.TokenType, c *gin.Context) (string, int64, error) {
|
||||
t := jwt.New(jwt.GetSigningMethod(constants.JWT_TYPE))
|
||||
t := jwt.New(jwt.GetSigningMethod(constants.EnvData.JWT_TYPE))
|
||||
expiryBound := time.Hour
|
||||
if tokenType == enum.RefreshToken {
|
||||
// expires in 1 year
|
||||
@@ -146,9 +145,23 @@ func CreateAdminAuthToken(tokenType enum.TokenType, c *gin.Context) (string, int
|
||||
|
||||
t.Claims = customClaims
|
||||
|
||||
token, err := t.SignedString([]byte(constants.JWT_SECRET))
|
||||
token, err := t.SignedString([]byte(constants.EnvData.JWT_SECRET))
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
return token, expiresAt, nil
|
||||
}
|
||||
|
||||
func GetAdminAuthToken(gc *gin.Context) (string, error) {
|
||||
token, err := GetAdminCookie(gc)
|
||||
if err != nil || token == "" {
|
||||
// try to check in auth header for cookie
|
||||
auth := gc.Request.Header.Get("Authorization")
|
||||
if auth == "" {
|
||||
return "", fmt.Errorf(`unauthorized`)
|
||||
}
|
||||
|
||||
token = strings.TrimPrefix(auth, "Bearer ")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
@@ -10,21 +10,21 @@ import (
|
||||
func SetCookie(gc *gin.Context, token string) {
|
||||
secure := true
|
||||
httpOnly := true
|
||||
host, _ := GetHostParts(constants.AUTHORIZER_URL)
|
||||
domain := GetDomainName(constants.AUTHORIZER_URL)
|
||||
host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
|
||||
domain := GetDomainName(constants.EnvData.AUTHORIZER_URL)
|
||||
if domain != "localhost" {
|
||||
domain = "." + domain
|
||||
}
|
||||
|
||||
gc.SetSameSite(http.SameSiteNoneMode)
|
||||
gc.SetCookie(constants.COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(constants.COOKIE_NAME+"-client", token, 3600, "/", domain, secure, httpOnly)
|
||||
gc.SetCookie(constants.EnvData.COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(constants.EnvData.COOKIE_NAME+"-client", token, 3600, "/", domain, secure, httpOnly)
|
||||
}
|
||||
|
||||
func GetCookie(gc *gin.Context) (string, error) {
|
||||
cookie, err := gc.Request.Cookie(constants.COOKIE_NAME)
|
||||
cookie, err := gc.Request.Cookie(constants.EnvData.COOKIE_NAME)
|
||||
if err != nil {
|
||||
cookie, err = gc.Request.Cookie(constants.COOKIE_NAME + "-client")
|
||||
cookie, err = gc.Request.Cookie(constants.EnvData.COOKIE_NAME + "-client")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -37,29 +37,37 @@ func DeleteCookie(gc *gin.Context) {
|
||||
secure := true
|
||||
httpOnly := true
|
||||
|
||||
host, _ := GetHostParts(constants.AUTHORIZER_URL)
|
||||
domain := GetDomainName(constants.AUTHORIZER_URL)
|
||||
host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
|
||||
domain := GetDomainName(constants.EnvData.AUTHORIZER_URL)
|
||||
if domain != "localhost" {
|
||||
domain = "." + domain
|
||||
}
|
||||
|
||||
gc.SetSameSite(http.SameSiteNoneMode)
|
||||
gc.SetCookie(constants.COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(constants.COOKIE_NAME+"-client", "", -1, "/", domain, secure, httpOnly)
|
||||
gc.SetCookie(constants.EnvData.COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(constants.EnvData.COOKIE_NAME+"-client", "", -1, "/", domain, secure, httpOnly)
|
||||
}
|
||||
|
||||
func SetAdminCookie(gc *gin.Context, token string) {
|
||||
secure := true
|
||||
httpOnly := true
|
||||
host, _ := GetHostParts(constants.AUTHORIZER_URL)
|
||||
host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
|
||||
|
||||
gc.SetCookie("authorizer-admin", token, 3600, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(constants.EnvData.ADMIN_COOKIE_NAME, token, 3600, "/", host, secure, httpOnly)
|
||||
}
|
||||
|
||||
func GetAdminCookie(gc *gin.Context) (string, error) {
|
||||
cookie, err := gc.Request.Cookie(constants.EnvData.ADMIN_COOKIE_NAME)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return cookie.Value, nil
|
||||
}
|
||||
|
||||
func DeleteAdminCookie(gc *gin.Context, token string) {
|
||||
secure := true
|
||||
httpOnly := true
|
||||
host, _ := GetHostParts(constants.AUTHORIZER_URL)
|
||||
host, _ := GetHostParts(constants.EnvData.AUTHORIZER_URL)
|
||||
|
||||
gc.SetCookie("authorizer-admin", "", -1, "/", host, secure, httpOnly)
|
||||
gc.SetCookie(constants.EnvData.ADMIN_COOKIE_NAME, "", -1, "/", host, secure, httpOnly)
|
||||
}
|
||||
|
83
server/utils/crypto.go
Normal file
83
server/utils/crypto.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
)
|
||||
|
||||
func EncryptB64(text string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(text))
|
||||
}
|
||||
|
||||
func DecryptB64(s string) (string, error) {
|
||||
data, err := base64.StdEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func EncryptAES(text []byte) ([]byte, error) {
|
||||
key := []byte(constants.EnvData.ENCRYPTION_KEY)
|
||||
c, err := aes.NewCipher(key)
|
||||
var res []byte
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// gcm or Galois/Counter Mode, is a mode of operation
|
||||
// for symmetric key cryptographic block ciphers
|
||||
// - https://en.wikipedia.org/wiki/Galois/Counter_Mode
|
||||
gcm, err := cipher.NewGCM(c)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// creates a new byte array the size of the nonce
|
||||
// which must be passed to Seal
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
// populates our nonce with a cryptographically secure
|
||||
// random sequence
|
||||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// here we encrypt our text using the Seal function
|
||||
// Seal encrypts and authenticates plaintext, authenticates the
|
||||
// additional data and appends the result to dst, returning the updated
|
||||
// slice. The nonce must be NonceSize() bytes long and unique for all
|
||||
// time, for a given key.
|
||||
return gcm.Seal(nonce, nonce, text, nil), nil
|
||||
}
|
||||
|
||||
func DecryptAES(ciphertext []byte) ([]byte, error) {
|
||||
key := []byte(constants.EnvData.ENCRYPTION_KEY)
|
||||
c, err := aes.NewCipher(key)
|
||||
var res []byte
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(c)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
nonceSize := gcm.NonceSize()
|
||||
if len(ciphertext) < nonceSize {
|
||||
return res, err
|
||||
}
|
||||
|
||||
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
|
||||
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
return plaintext, nil
|
||||
}
|
@@ -100,7 +100,7 @@ func SendVerificationMail(toEmail, token string) error {
|
||||
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
|
||||
</body>
|
||||
</html>
|
||||
`, constants.ORGANIZATION_LOGO, constants.ORGANIZATION_NAME, constants.AUTHORIZER_URL+"/verify_email"+"?token="+token)
|
||||
`, constants.EnvData.ORGANIZATION_LOGO, constants.EnvData.ORGANIZATION_NAME, constants.EnvData.AUTHORIZER_URL+"/verify_email"+"?token="+token)
|
||||
bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
|
||||
|
||||
return sender.SendMail(Receiver, Subject, bodyMessage)
|
||||
@@ -108,8 +108,8 @@ func SendVerificationMail(toEmail, token string) error {
|
||||
|
||||
// SendForgotPasswordMail to send verification email
|
||||
func SendForgotPasswordMail(toEmail, token, host string) error {
|
||||
if constants.RESET_PASSWORD_URL == "" {
|
||||
constants.RESET_PASSWORD_URL = constants.AUTHORIZER_URL + "/app/reset-password"
|
||||
if constants.EnvData.RESET_PASSWORD_URL == "" {
|
||||
constants.EnvData.RESET_PASSWORD_URL = constants.EnvData.AUTHORIZER_URL + "/app/reset-password"
|
||||
}
|
||||
|
||||
sender := email.NewSender()
|
||||
@@ -204,7 +204,7 @@ func SendForgotPasswordMail(toEmail, token, host string) error {
|
||||
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
|
||||
</body>
|
||||
</html>
|
||||
`, constants.ORGANIZATION_LOGO, toEmail, constants.RESET_PASSWORD_URL+"?token="+token)
|
||||
`, constants.EnvData.ORGANIZATION_LOGO, toEmail, constants.EnvData.RESET_PASSWORD_URL+"?token="+token)
|
||||
|
||||
bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
|
||||
|
||||
|
@@ -9,12 +9,12 @@ import (
|
||||
// version,
|
||||
func GetMetaInfo() model.Meta {
|
||||
return model.Meta{
|
||||
Version: constants.VERSION,
|
||||
IsGoogleLoginEnabled: constants.GOOGLE_CLIENT_ID != "" && constants.GOOGLE_CLIENT_SECRET != "",
|
||||
IsGithubLoginEnabled: constants.GITHUB_CLIENT_ID != "" && constants.GOOGLE_CLIENT_SECRET != "",
|
||||
IsFacebookLoginEnabled: constants.FACEBOOK_CLIENT_ID != "" && constants.FACEBOOK_CLIENT_SECRET != "",
|
||||
IsBasicAuthenticationEnabled: !constants.DISABLE_BASIC_AUTHENTICATION,
|
||||
IsEmailVerificationEnabled: !constants.DISABLE_EMAIL_VERIFICATION,
|
||||
IsMagicLinkLoginEnabled: !constants.DISABLE_MAGIC_LINK_LOGIN,
|
||||
Version: constants.EnvData.VERSION,
|
||||
IsGoogleLoginEnabled: constants.EnvData.GOOGLE_CLIENT_ID != "" && constants.EnvData.GOOGLE_CLIENT_SECRET != "",
|
||||
IsGithubLoginEnabled: constants.EnvData.GITHUB_CLIENT_ID != "" && constants.EnvData.GOOGLE_CLIENT_SECRET != "",
|
||||
IsFacebookLoginEnabled: constants.EnvData.FACEBOOK_CLIENT_ID != "" && constants.EnvData.FACEBOOK_CLIENT_SECRET != "",
|
||||
IsBasicAuthenticationEnabled: !constants.EnvData.DISABLE_BASIC_AUTHENTICATION,
|
||||
IsEmailVerificationEnabled: !constants.EnvData.DISABLE_EMAIL_VERIFICATION,
|
||||
IsMagicLinkLoginEnabled: !constants.EnvData.DISABLE_MAGIC_LINK_LOGIN,
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ func IsValidEmail(email string) bool {
|
||||
}
|
||||
|
||||
func IsValidOrigin(url string) bool {
|
||||
if len(constants.ALLOWED_ORIGINS) == 1 && constants.ALLOWED_ORIGINS[0] == "*" {
|
||||
if len(constants.EnvData.ALLOWED_ORIGINS) == 1 && constants.EnvData.ALLOWED_ORIGINS[0] == "*" {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func IsValidOrigin(url string) bool {
|
||||
hostName, port := GetHostParts(url)
|
||||
currentOrigin := hostName + ":" + port
|
||||
|
||||
for _, origin := range constants.ALLOWED_ORIGINS {
|
||||
for _, origin := range constants.EnvData.ALLOWED_ORIGINS {
|
||||
replacedString := origin
|
||||
// if has regex whitelisted domains
|
||||
if strings.Contains(origin, "*") {
|
||||
@@ -50,12 +50,17 @@ func IsValidOrigin(url string) bool {
|
||||
}
|
||||
|
||||
func IsSuperAdmin(gc *gin.Context) bool {
|
||||
secret := gc.Request.Header.Get("x-authorizer-admin-secret")
|
||||
if secret == "" {
|
||||
return false
|
||||
token, err := GetAdminAuthToken(gc)
|
||||
if err != nil {
|
||||
secret := gc.Request.Header.Get("x-authorizer-admin-secret")
|
||||
if secret == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return secret == constants.EnvData.ADMIN_SECRET
|
||||
}
|
||||
|
||||
return secret == constants.ADMIN_SECRET
|
||||
return token != ""
|
||||
}
|
||||
|
||||
func IsValidRoles(userRoles []string, roles []string) bool {
|
||||
|
@@ -20,23 +20,23 @@ type CustomClaim struct {
|
||||
}
|
||||
|
||||
func CreateVerificationToken(email string, tokenType string) (string, error) {
|
||||
t := jwt.New(jwt.GetSigningMethod(constants.JWT_TYPE))
|
||||
t := jwt.New(jwt.GetSigningMethod(constants.EnvData.JWT_TYPE))
|
||||
|
||||
t.Claims = &CustomClaim{
|
||||
&jwt.StandardClaims{
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
},
|
||||
tokenType,
|
||||
UserInfo{Email: email, Host: constants.AUTHORIZER_URL, RedirectURL: constants.APP_URL},
|
||||
UserInfo{Email: email, Host: constants.EnvData.AUTHORIZER_URL, RedirectURL: constants.EnvData.APP_URL},
|
||||
}
|
||||
|
||||
return t.SignedString([]byte(constants.JWT_SECRET))
|
||||
return t.SignedString([]byte(constants.EnvData.JWT_SECRET))
|
||||
}
|
||||
|
||||
func VerifyVerificationToken(token string) (*CustomClaim, error) {
|
||||
claims := &CustomClaim{}
|
||||
_, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(constants.JWT_SECRET), nil
|
||||
return []byte(constants.EnvData.JWT_SECRET), nil
|
||||
})
|
||||
if err != nil {
|
||||
return claims, err
|
||||
|
Reference in New Issue
Block a user