188 lines
6.3 KiB
Go
188 lines
6.3 KiB
Go
package domain
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
domainAuth "github.com/haydenhargreaves/Potion/internal/domain/auth"
|
|
domainEngagement "github.com/haydenhargreaves/Potion/internal/domain/engagement"
|
|
domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
|
|
domainUser "github.com/haydenhargreaves/Potion/internal/domain/user"
|
|
"github.com/haydenhargreaves/Potion/internal/infrastructure/logging"
|
|
"github.com/joho/godotenv"
|
|
)
|
|
|
|
// EnvironmentConfig stores the configuration of the environment. Anything loaded from the .env
|
|
// or docker environment will be stored here and can be accessed from the InjectedDependencies
|
|
// struct, which this is attached to.
|
|
type EnvironmentConfig struct {
|
|
GoogleClientId string
|
|
GoogleClientSecret string
|
|
JwtSecret string
|
|
DatabaseUrl string
|
|
Environment string
|
|
Domain string
|
|
FrontendDomain string
|
|
}
|
|
|
|
// InjectedDependencies is a collection of dependencies that are injected into the application. They
|
|
// are stored in the context and can be accessed by handlers via the context.
|
|
type InjectedDependencies struct {
|
|
UserService domainUser.UserService
|
|
AuthService domainAuth.AuthService
|
|
RecipeService domainRecipe.RecipeService
|
|
EngagementService domainEngagement.EngagementService
|
|
EnvironmentConfig EnvironmentConfig
|
|
}
|
|
|
|
// JwtClaims is the data stored in the JSON web token. All that is needed is the users ID and their
|
|
// Google email provided.
|
|
type JwtClaims struct {
|
|
UserId int `json:"Id"`
|
|
Email string `json:"Email"`
|
|
jwt.RegisteredClaims
|
|
}
|
|
|
|
// IsLoggedIn checks the cookies in a request and returns whether the user is logged in.
|
|
func IsLoggedIn(ctx *gin.Context) bool {
|
|
_, id := ctx.Get("userId")
|
|
_, email := ctx.Get("userEmail")
|
|
return id && email
|
|
}
|
|
|
|
// LoadEnvironment loads the environment values from either an .env file or docker environment. In
|
|
// the event that required fields are not provided, an error will return and the caller should handle
|
|
// the missing value or panic. Toggles between 'dev', 'prod', etc are also handled by this method,
|
|
// the values can be access assuming they are the proper values based on the provided environment.
|
|
func LoadEnvironment(logs []logging.Logger) (*EnvironmentConfig, error) {
|
|
err := godotenv.Load(".env")
|
|
if err != nil {
|
|
logging.LogAll(logs, logging.LogLevelWarning, "No .env file found or error loading .env: %v. Relying on system environment variables.", err)
|
|
}
|
|
|
|
env := os.Getenv("ENVIRONMENT")
|
|
if env == "" {
|
|
return nil, fmt.Errorf("ENVIRONMENT environment variable is required.")
|
|
}
|
|
|
|
googleClientId := os.Getenv("GOOGLE_CLIENT_ID")
|
|
if googleClientId == "" {
|
|
return nil, fmt.Errorf("GOOGLE_CLIENT_ID environment variable is required.")
|
|
}
|
|
|
|
googleClientSecret := os.Getenv("GOOGLE_CLIENT_SECRET")
|
|
if googleClientSecret == "" {
|
|
return nil, fmt.Errorf("GOOGLE_CLIENT_SECRET environment variable is required.")
|
|
}
|
|
|
|
jwtSecret := os.Getenv("JWT_SECRET")
|
|
if jwtSecret == "" {
|
|
return nil, fmt.Errorf("JWT_SECRET environment variable is required.")
|
|
}
|
|
|
|
var domain string
|
|
var frontendDomain string
|
|
if env == "dev" {
|
|
domain = os.Getenv("DOMAIN_DEV")
|
|
if domain == "" {
|
|
return nil, fmt.Errorf("DOMAIN_DEV environment variable is required when ENVIRONMENT is 'dev'.")
|
|
}
|
|
frontendDomain = os.Getenv("FRONTEND_DOMAIN_DEV")
|
|
if frontendDomain == "" {
|
|
return nil, fmt.Errorf("FRONTEND_DOMAIN_DEV environment variable is required when ENVIRONMENT is 'dev'.")
|
|
}
|
|
} else if env == "prod" {
|
|
domain = os.Getenv("DOMAIN_PROD")
|
|
if domain == "" {
|
|
return nil, fmt.Errorf("DOMAIN_PROD environment variable is required when ENVIRONMENT is 'prod'.")
|
|
}
|
|
frontendDomain = os.Getenv("FRONTEND_DOMAIN_PROD")
|
|
if frontendDomain == "" {
|
|
return nil, fmt.Errorf("FRONTEND_DOMAIN_PROD environment variable is required when ENVIRONMENT is 'dev'.")
|
|
}
|
|
} else {
|
|
return nil, fmt.Errorf("ENVIRONMENT environment variable is required and must be 'dev' or 'prod'.")
|
|
}
|
|
|
|
var dbUrl string
|
|
if env == "dev" {
|
|
dbUrl = os.Getenv("DATABASE_URL_DEV")
|
|
if dbUrl == "" {
|
|
return nil, fmt.Errorf("DATABASE_URL_DEV environment variable is required when ENVIRONMENT is 'dev'.")
|
|
}
|
|
} else if env == "prod" {
|
|
dbUrl = os.Getenv("DATABASE_URL_PROD")
|
|
if dbUrl == "" {
|
|
return nil, fmt.Errorf("DATABASE_URL_PROD environment variable is required when ENVIRONMENT is 'prod'.")
|
|
}
|
|
} else {
|
|
return nil, fmt.Errorf("ENVIRONMENT environment variable is required and must be 'dev' or 'prod'.")
|
|
}
|
|
|
|
cfg := &EnvironmentConfig{
|
|
GoogleClientId: googleClientId,
|
|
GoogleClientSecret: googleClientSecret,
|
|
JwtSecret: jwtSecret,
|
|
DatabaseUrl: dbUrl,
|
|
Environment: env,
|
|
Domain: domain,
|
|
FrontendDomain: frontendDomain,
|
|
}
|
|
|
|
logging.LogAll(logs, logging.LogLevelDebug, "Environment Config: %+v\n", cfg)
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
// SetCookie sets a cookie value with a duration provided. This function handles setting the security
|
|
// configuration as well as the domain. These values are based on the EnvironmentConfig, therefore
|
|
// the value should be set. Nothing is returned by this function, but the cookie will be set.
|
|
//
|
|
// This function can also be used to clear cookies, if a blank value ("") and invalid duration (-1)
|
|
// is provided.
|
|
//
|
|
// If 0 is provided as the duration, then a session cookie is created, which will be cleared when
|
|
// the browser is closed.
|
|
//
|
|
// DEPRECATED: As of September 4th, 2025.
|
|
// func SetCookie(ctx *gin.Context, name, value string, duration time.Duration) {
|
|
// deps := ctx.MustGet("deps").(*InjectedDependencies)
|
|
//
|
|
// var (
|
|
// path string = "/"
|
|
// httpOnly bool = true
|
|
// maxAge int
|
|
// secure bool
|
|
// domain string
|
|
// )
|
|
//
|
|
// if duration < 0 {
|
|
// // Delete the cookie
|
|
// maxAge = -1
|
|
// } else if duration == 0 {
|
|
// // Session cookie, clears when browser is closed
|
|
// maxAge = 0
|
|
// } else {
|
|
// // Normal calculation
|
|
// maxAge = int(time.Now().Add(duration).Sub(time.Now()).Seconds())
|
|
// }
|
|
//
|
|
// if deps.EnvironmentConfig.Environment == "prod" {
|
|
// secure = true
|
|
// domain = deps.EnvironmentConfig.Domain
|
|
//
|
|
// } else if deps.EnvironmentConfig.Environment == "dev" {
|
|
// secure = false
|
|
// domain = deps.EnvironmentConfig.Domain
|
|
//
|
|
// } else {
|
|
// // Defaults
|
|
// secure = false
|
|
// domain = ""
|
|
// }
|
|
//
|
|
// ctx.SetCookie(name, value, maxAge, path, domain, secure, httpOnly)
|
|
// }
|