1066 lines
35 KiB
Go
1066 lines
35 KiB
Go
package config
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
)
|
|
|
|
type Config struct {
|
|
Server ServerConfig `mapstructure:"server"`
|
|
Databases map[string]DatabaseConfig `mapstructure:"databases"`
|
|
ReadReplicas map[string][]DatabaseConfig `mapstructure:"read_replicas"`
|
|
Auth AuthConfig `mapstructure:"auth"`
|
|
Keycloak KeycloakConfig `mapstructure:"keycloak"`
|
|
Bpjs BpjsConfig `mapstructure:"bpjs"`
|
|
SatuSehat SatuSehatConfig `mapstructure:"satu_sehat"`
|
|
Swagger SwaggerConfig `mapstructure:"swagger"`
|
|
Security SecurityConfig `mapstructure:"security"`
|
|
Cache CacheConfig `mapstructure:"cache"` // Tambahkan ini
|
|
Logger LoggerConfig `mapstructure:"logger"` // Tambahkan ini
|
|
Minio MinioConfig `mapstructure:"minio"`
|
|
Validator *validator.Validate `mapstructure:"-"`
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
REST ServerRESTConfig `mapstructure:"rest"`
|
|
GRPC ServerGRPCConfig `mapstructure:"grpc"`
|
|
Port int `mapstructure:"port"`
|
|
Mode string `mapstructure:"mode"`
|
|
ReadTimeout int `mapstructure:"read_timeout"`
|
|
WriteTimeout int `mapstructure:"write_timeout"`
|
|
}
|
|
|
|
type ServerRESTConfig struct {
|
|
Enabled bool `mapstructure:"enabled" validate:"required"`
|
|
Port int `mapstructure:"port" validate:"required,min=1,max=65535"`
|
|
}
|
|
|
|
type ServerGRPCConfig struct {
|
|
Enabled bool `mapstructure:"enabled" validate:"required"`
|
|
Port int `mapstructure:"port" validate:"required,min=1,max=65535"`
|
|
}
|
|
|
|
// GRPCConfig untuk pengaturan spesifik server gRPC.
|
|
type GRPCConfig struct {
|
|
ReflectionEnabled bool `mapstructure:"reflection_enabled"`
|
|
Timeout time.Duration `mapstructure:"timeout" validate:"required"`
|
|
}
|
|
|
|
type DatabaseConfig struct {
|
|
Name string `mapstructure:"name"`
|
|
Type string `mapstructure:"type"`
|
|
Host string `mapstructure:"host"`
|
|
Port int `mapstructure:"port"`
|
|
Username string `mapstructure:"username"`
|
|
Password string `mapstructure:"password"`
|
|
Database string `mapstructure:"database"`
|
|
Schema string `mapstructure:"schema"`
|
|
SSLMode string `mapstructure:"ssl_mode"`
|
|
Path string `mapstructure:"path"`
|
|
Options string `mapstructure:"options"`
|
|
MaxOpenConns int `mapstructure:"max_open_conns"`
|
|
MaxIdleConns int `mapstructure:"max_idle_conns"`
|
|
ConnMaxLifetime time.Duration `mapstructure:"conn_max_lifetime"`
|
|
// Security settings
|
|
RequireSSL bool `mapstructure:"require_ssl"`
|
|
SSLRootCert string `mapstructure:"ssl_root_cert"`
|
|
SSLCert string `mapstructure:"ssl_cert"`
|
|
SSLKey string `mapstructure:"ssl_key"`
|
|
Timeout time.Duration `mapstructure:"timeout"`
|
|
ConnectTimeout time.Duration `mapstructure:"connect_timeout"`
|
|
ReadTimeout time.Duration `mapstructure:"read_timeout"`
|
|
WriteTimeout time.Duration `mapstructure:"write_timeout"`
|
|
StatementTimeout time.Duration `mapstructure:"statement_timeout"`
|
|
// Connection pool settings
|
|
MaxLifetime time.Duration `mapstructure:"max_lifetime"`
|
|
MaxIdleTime time.Duration `mapstructure:"max_idle_time"`
|
|
HealthCheckPeriod time.Duration `mapstructure:"health_check_period"`
|
|
IsActive bool `mapstructure:"is_active"`
|
|
}
|
|
|
|
type AuthConfig struct {
|
|
Type string `mapstructure:"type"`
|
|
StaticTokens []string `mapstructure:"static_tokens"`
|
|
FallbackTo string `mapstructure:"fallback_to"`
|
|
}
|
|
|
|
type KeycloakConfig struct {
|
|
Enabled bool `mapstructure:"enabled"`
|
|
URL string `mapstructure:"url"` // URL base Keycloak, e.g., http://localhost:8080
|
|
Realm string `mapstructure:"realm"` // Realm yang digunakan
|
|
ClientID string `mapstructure:"client_id"` // Client ID dari service-account
|
|
ClientSecret string `mapstructure:"client_secret"` // Client Secret
|
|
// Fields untuk validasi token (jika service ini juga memvalidasi)
|
|
Issuer string `mapstructure:"issuer"` // e.g., http://localhost:8080/realms/my-realm
|
|
Audience string `mapstructure:"audience"` // Biasanya sama dengan ClientID
|
|
JwksURL string `mapstructure:"jwks_url"` // URL untuk mengambil public keys
|
|
}
|
|
|
|
type BpjsConfig struct {
|
|
Enabled bool `mapstructure:"enabled"`
|
|
KdPpk string `mapstructure:"kd_ppk"`
|
|
BaseURL string `mapstructure:"base_url"`
|
|
ServiceName string `mapstructure:"service_name"`
|
|
ConsID string `mapstructure:"cons_id"`
|
|
SecretKey string `mapstructure:"secret_key"`
|
|
ApotekConsID string `mapstructure:"apotek_cons_id"`
|
|
ApotekSecretKey string `mapstructure:"apotek_secret_key"`
|
|
UserKey string `mapstructure:"user_key"` // Internal active UserKey
|
|
VclaimUserKey string `mapstructure:"vclaim_user_key"`
|
|
AntrolUserKey string `mapstructure:"antrol_user_key"` // Tambahan untuk Antrean RS
|
|
ApotekUserKey string `mapstructure:"apotek_user_key"` // Tambahan untuk Apotek
|
|
AplicareUserKey string `mapstructure:"aplicare_user_key"` // Tambahan untuk Aplicares
|
|
IhsUserKey string `mapstructure:"ihs_user_key"` // Tambahan untuk IHS / e-Rekam Medis
|
|
Timeout time.Duration `mapstructure:"timeout"`
|
|
}
|
|
|
|
type SatuSehatConfig struct {
|
|
Enabled bool `mapstructure:"enabled"`
|
|
OrgID string `mapstructure:"org_id"`
|
|
FasyakesID string `mapstructure:"fasyakes_id"`
|
|
ClientID string `mapstructure:"client_id"`
|
|
ClientSecret string `mapstructure:"client_secret"`
|
|
AuthURL string `mapstructure:"auth_url"`
|
|
BaseURL string `mapstructure:"base_url"`
|
|
ConsentURL string `mapstructure:"consent_url"`
|
|
KFAURL string `mapstructure:"kfa_url"`
|
|
Timeout time.Duration `mapstructure:"timeout"`
|
|
}
|
|
|
|
type SwaggerConfig struct {
|
|
Title string `mapstructure:"title"`
|
|
Description string `mapstructure:"description"`
|
|
Version string `mapstructure:"version"`
|
|
TermsOfService string `mapstructure:"terms_of_service"`
|
|
ContactName string `mapstructure:"contact_name"`
|
|
ContactURL string `mapstructure:"contact_url"`
|
|
ContactEmail string `mapstructure:"contact_email"`
|
|
LicenseName string `mapstructure:"license_name"`
|
|
LicenseURL string `mapstructure:"license_url"`
|
|
Host string `mapstructure:"host"`
|
|
BasePath string `mapstructure:"base_path"`
|
|
Schemes []string `mapstructure:"schemes"`
|
|
}
|
|
|
|
type SecurityConfig struct {
|
|
TrustedOrigins []string `mapstructure:"trusted_origins"`
|
|
RateLimit RateLimitConfig `mapstructure:"rate_limit"`
|
|
MaxInputLength int `mapstructure:"max_input_length"`
|
|
}
|
|
|
|
type RateLimitConfig struct {
|
|
RequestsPerMinute int `mapstructure:"requests_per_minute"`
|
|
Redis RedisConfig `mapstructure:"redis"`
|
|
}
|
|
|
|
type RedisConfig struct {
|
|
Host string `mapstructure:"host" env:"CACHE_REDIS_HOST"`
|
|
Port int `mapstructure:"port" env:"CACHE_REDIS_PORT"`
|
|
Password string `mapstructure:"password" env:"REDIS_PASSWORD"`
|
|
DB int `mapstructure:"db" env:"REDIS_DB"`
|
|
}
|
|
|
|
type CacheConfig struct {
|
|
Enabled bool `mapstructure:"enabled"`
|
|
DefaultTTL time.Duration `mapstructure:"default_ttl"`
|
|
SessionTTL time.Duration `mapstructure:"session_ttl"`
|
|
RateLimitTTL time.Duration `mapstructure:"rate_limit_ttl"`
|
|
CleanupInterval time.Duration `mapstructure:"cleanup_interval"`
|
|
MaxRetries int `mapstructure:"max_retries"`
|
|
RetryDelay time.Duration `mapstructure:"retry_delay"`
|
|
Redis RedisConfig `mapstructure:"redis"`
|
|
}
|
|
|
|
type LoggerConfig struct {
|
|
Level string `mapstructure:"level"`
|
|
Format string `mapstructure:"format"`
|
|
}
|
|
|
|
type MinioConfig struct {
|
|
Endpoint string `mapstructure:"endpoint"`
|
|
Region string `mapstructure:"region"`
|
|
AccessKey string `mapstructure:"access_key"`
|
|
SecretKey string `mapstructure:"secret_key"`
|
|
UseSSL bool `mapstructure:"use_ssl"`
|
|
BucketName []string `mapstructure:"bucket_name"`
|
|
}
|
|
|
|
func (cfg BpjsConfig) SetHeader() (string, string, string, string, string) {
|
|
timenow := time.Now().UTC()
|
|
t, err := time.Parse(time.RFC3339, "1970-01-01T00:00:00Z")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
tstamp := timenow.Unix() - t.Unix()
|
|
secret := []byte(cfg.SecretKey)
|
|
message := []byte(cfg.ConsID + "&" + fmt.Sprint(tstamp))
|
|
hash := hmac.New(sha256.New, secret)
|
|
hash.Write(message)
|
|
|
|
// to base64
|
|
xSignature := base64.StdEncoding.EncodeToString(hash.Sum(nil))
|
|
|
|
// Gunakan Active UserKey alih-alih selalu menembak VClaim
|
|
return cfg.ConsID, cfg.SecretKey, cfg.UserKey, fmt.Sprint(tstamp), xSignature
|
|
}
|
|
|
|
type ConfigBpjs struct {
|
|
Cons_id string
|
|
Secret_key string
|
|
User_key string
|
|
}
|
|
|
|
// SetHeader for backward compatibility
|
|
func (cfg ConfigBpjs) SetHeader() (string, string, string, string, string) {
|
|
bpjsConfig := BpjsConfig{
|
|
ConsID: cfg.Cons_id,
|
|
SecretKey: cfg.Secret_key,
|
|
UserKey: cfg.User_key,
|
|
}
|
|
return bpjsConfig.SetHeader()
|
|
}
|
|
|
|
func LoadConfig() *Config {
|
|
config := &Config{
|
|
Server: ServerConfig{
|
|
// Baca dari env untuk konfigurasi umum
|
|
Port: getEnvAsInt("SERVER_PORT", 8080), // Fallback jika REST port tidak set
|
|
Mode: getEnv("GIN_MODE", "debug"),
|
|
ReadTimeout: getEnvAsInt("SERVER_READ_TIMEOUT", 10),
|
|
WriteTimeout: getEnvAsInt("SERVER_WRITE_TIMEOUT", 10),
|
|
|
|
REST: ServerRESTConfig{
|
|
Enabled: getEnvAsBool("SERVER_REST_ENABLED", true),
|
|
Port: getEnvAsInt("SERVER_REST_PORT", 8080),
|
|
},
|
|
GRPC: ServerGRPCConfig{
|
|
Enabled: getEnvAsBool("SERVER_GRPC_ENABLED", false),
|
|
Port: getEnvAsInt("SERVER_GRPC_PORT", 50051),
|
|
},
|
|
},
|
|
Databases: make(map[string]DatabaseConfig),
|
|
ReadReplicas: make(map[string][]DatabaseConfig),
|
|
Auth: loadAuthConfig(),
|
|
Keycloak: loadKeycloakConfig(),
|
|
|
|
// ... (Config BPJS, SatuSehat, dll tetap sama seperti kode asli Anda)
|
|
Bpjs: BpjsConfig{
|
|
Enabled: getEnvAsBool("BPJS_ENABLED", false),
|
|
KdPpk: strings.TrimSpace(getEnv("BPJS_KDPPK", "")),
|
|
BaseURL: strings.TrimSpace(getEnv("BPJS_BASEURL", "https://apijkn.bpjs-kesehatan.go.id")),
|
|
ServiceName: strings.TrimSpace(getEnv("BPJS_SERVICE_NAME", "")),
|
|
ConsID: strings.TrimSpace(getEnv("BPJS_CONSID", "")),
|
|
SecretKey: strings.TrimSpace(getEnv("BPJS_SECRETKEY", "")),
|
|
ApotekConsID: strings.TrimSpace(getEnv("BPJS_APOTEK_CONSID", "")),
|
|
ApotekSecretKey: strings.TrimSpace(getEnv("BPJS_APOTEK_SECRETKEY", "")),
|
|
VclaimUserKey: strings.TrimSpace(getEnv("BPJS_VCLAIM_USERKEY", getEnv("BPJS_USERKEY", ""))),
|
|
AntrolUserKey: strings.TrimSpace(getEnv("BPJS_ANTROL_USERKEY", "")),
|
|
ApotekUserKey: strings.TrimSpace(getEnv("BPJS_APOTEK_USERKEY", "")),
|
|
AplicareUserKey: strings.TrimSpace(getEnv("BPJS_APLICARE_USERKEY", "")),
|
|
IhsUserKey: strings.TrimSpace(getEnv("BPJS_IHS_USERKEY", "")),
|
|
Timeout: parseDuration(getEnv("BPJS_TIMEOUT", "30s")),
|
|
},
|
|
SatuSehat: SatuSehatConfig{
|
|
Enabled: getEnvAsBool("SATUSEHAT_ENABLED", getEnvAsBool("SATU_SEHAT_ENABLED", false)),
|
|
OrgID: getEnv("SATUSEHAT_ORG_ID", getEnv("BRIDGING_SATUSEHAT_ORG_ID", "")),
|
|
FasyakesID: getEnv("SATUSEHAT_FASYAKES_ID", getEnv("BRIDGING_SATUSEHAT_FASYAKES_ID", "")),
|
|
ClientID: getEnv("SATUSEHAT_CLIENT_ID", getEnv("BRIDGING_SATUSEHAT_CLIENT_ID", "")),
|
|
ClientSecret: getEnv("SATUSEHAT_CLIENT_SECRET", getEnv("BRIDGING_SATUSEHAT_CLIENT_SECRET", "")),
|
|
AuthURL: getEnv("SATUSEHAT_AUTH_URL", getEnv("BRIDGING_SATUSEHAT_AUTH_URL", "https://api-satusehat.kemkes.go.id/oauth2/v1")),
|
|
BaseURL: getEnv("SATUSEHAT_BASE_URL", getEnv("BRIDGING_SATUSEHAT_BASE_URL", "https://api-satusehat.kemkes.go.id/fhir-r4/v1")),
|
|
ConsentURL: getEnv("SATUSEHAT_CONSENT_URL", getEnv("BRIDGING_SATUSEHAT_CONSENT_URL", "https://api-satusehat.dto.kemkes.go.id/consent/v1")),
|
|
KFAURL: getEnv("SATUSEHAT_KFA_URL", getEnv("BRIDGING_SATUSEHAT_KFA_URL", "https://api-satusehat.kemkes.go.id/kfa-v2")),
|
|
Timeout: parseDuration(getEnv("SATUSEHAT_TIMEOUT", getEnv("BRIDGING_SATUSEHAT_TIMEOUT", "30s"))),
|
|
},
|
|
Swagger: SwaggerConfig{
|
|
Title: getEnv("SWAGGER_TITLE", "SERVICE API"),
|
|
Description: getEnv("SWAGGER_DESCRIPTION", "CUSTUM SERVICE API"),
|
|
Version: getEnv("SWAGGER_VERSION", "1.0.0"),
|
|
TermsOfService: getEnv("SWAGGER_TERMS_OF_SERVICE", "http://swagger.io/terms/"),
|
|
ContactName: getEnv("SWAGGER_CONTACT_NAME", "API Support"),
|
|
ContactURL: getEnv("SWAGGER_CONTACT_URL", "http://rssa.example.com/support"),
|
|
ContactEmail: getEnv("SWAGGER_CONTACT_EMAIL", "[email protected]"),
|
|
LicenseName: getEnv("SWAGGER_LICENSE_NAME", "Apache 2.0"),
|
|
LicenseURL: getEnv("SWAGGER_LICENSE_URL", "http://www.apache.org/licenses/LICENSE-2.0.html"),
|
|
Host: getEnv("SWAGGER_HOST", "localhost:8080"),
|
|
BasePath: getEnv("SWAGGER_BASE_PATH", "/api/v1"),
|
|
Schemes: parseSchemes(getEnv("SWAGGER_SCHEMES", "http,https")),
|
|
},
|
|
Security: SecurityConfig{
|
|
TrustedOrigins: parseOrigins(getEnv("SECURITY_TRUSTED_ORIGINS", "http://localhost:3000,http://localhost:8080")),
|
|
MaxInputLength: getEnvAsInt("SECURITY_MAX_INPUT_LENGTH", 500),
|
|
RateLimit: RateLimitConfig{
|
|
RequestsPerMinute: getEnvAsInt("RATE_LIMIT_REQUESTS_PER_MINUTE", 60),
|
|
Redis: RedisConfig{
|
|
Host: getEnv("CACHE_REDIS_HOST", "localhost"),
|
|
Port: getEnvAsInt("CACHE_REDIS_PORT", 6379),
|
|
Password: getEnv("REDIS_PASSWORD", ""),
|
|
DB: getEnvAsInt("CACHE_REDIS_DB", 0),
|
|
},
|
|
},
|
|
},
|
|
Cache: CacheConfig{
|
|
Enabled: getEnvAsBool("CACHE_ENABLED", true),
|
|
DefaultTTL: parseDuration(getEnv("CACHE_DEFAULT_TTL", "1h")),
|
|
SessionTTL: parseDuration(getEnv("CACHE_SESSION_TTL", "24h")),
|
|
RateLimitTTL: parseDuration(getEnv("CACHE_RATE_LIMIT_TTL", "1m")),
|
|
CleanupInterval: parseDuration(getEnv("CACHE_CLEANUP_INTERVAL", "5m")),
|
|
MaxRetries: getEnvAsInt("CACHE_MAX_RETRIES", 3),
|
|
RetryDelay: parseDuration(getEnv("CACHE_RETRY_DELAY", "100ms")),
|
|
Redis: RedisConfig{
|
|
Host: getEnv("CACHE_REDIS_HOST", "localhost"),
|
|
Port: getEnvAsInt("CACHE_REDIS_PORT", 6379),
|
|
Password: getEnv("REDIS_PASSWORD", ""),
|
|
DB: getEnvAsInt("CACHE_REDIS_DB", 1),
|
|
},
|
|
},
|
|
Logger: LoggerConfig{
|
|
Level: getEnv("LOGGER_LEVEL", "info"),
|
|
Format: getEnv("LOGGER_FORMAT", "text"),
|
|
},
|
|
Minio: MinioConfig{
|
|
Endpoint: getEnv("MINIO_ENDPOINT", ""),
|
|
Region: getEnv("MINIO_REGION", ""),
|
|
AccessKey: getEnv("MINIO_ACCESSKEY", ""),
|
|
SecretKey: getEnv("MINIO_SECRETKEY", ""),
|
|
UseSSL: getEnvAsBool("MINIO_USESSL", false),
|
|
BucketName: parseStaticTokens(getEnv("MINIO_BUCKETNAME", "")), // Pisahkan berdasarkan koma
|
|
},
|
|
}
|
|
// Initialize validator
|
|
config.Validator = validator.New()
|
|
|
|
// Load database configurations
|
|
config.loadDatabaseConfigs()
|
|
|
|
// Load read replica configurations
|
|
config.loadReadReplicaConfigs()
|
|
|
|
return config
|
|
}
|
|
|
|
func (c *Config) Validate() error {
|
|
var errs []string
|
|
|
|
if len(c.Databases) == 0 {
|
|
errs = append(errs, "at least one database configuration is required")
|
|
}
|
|
|
|
for name, db := range c.Databases {
|
|
if db.Type != "sqlite" && db.Host == "" {
|
|
errs = append(errs, fmt.Sprintf("database host is required for %s", name))
|
|
}
|
|
if db.Type != "sqlite" && db.Username == "" {
|
|
errs = append(errs, fmt.Sprintf("database username is required for %s", name))
|
|
}
|
|
// Opsional: Matikan validasi password mutlak jika Anda menggunakan database lokal tanpa password
|
|
// if db.Type != "sqlite" && db.Password == "" {
|
|
// errs = append(errs, fmt.Sprintf("database password is required for %s", name))
|
|
// }
|
|
if db.Type == "sqlite" && db.Path == "" {
|
|
errs = append(errs, fmt.Sprintf("database path is required for SQLite database %s", name))
|
|
}
|
|
if db.Type != "sqlite" && db.Database == "" {
|
|
errs = append(errs, fmt.Sprintf("database name is required for %s", name))
|
|
}
|
|
}
|
|
|
|
if c.Bpjs.Enabled {
|
|
if c.Bpjs.BaseURL == "" {
|
|
errs = append(errs, "BPJS Base URL is required when BPJS is enabled")
|
|
}
|
|
if c.Bpjs.ConsID == "" && c.Bpjs.ApotekConsID == "" {
|
|
errs = append(errs, "At least one BPJS Consumer ID (Default or Apotek) is required when BPJS is enabled")
|
|
}
|
|
if c.Bpjs.SecretKey == "" && c.Bpjs.ApotekSecretKey == "" {
|
|
errs = append(errs, "At least one BPJS Secret Key (Default or Apotek) is required when BPJS is enabled")
|
|
}
|
|
if c.Bpjs.ServiceName == "" {
|
|
errs = append(errs, "BPJS Service Name is required when BPJS is enabled")
|
|
}
|
|
}
|
|
|
|
// Validate authentication configuration (auth.type is already loaded from env)
|
|
switch c.Auth.Type {
|
|
case "keycloak":
|
|
if !c.Keycloak.Enabled {
|
|
errs = append(errs, "keycloak.enabled must be true when auth.type is 'keycloak'")
|
|
}
|
|
if c.Keycloak.Issuer == "" {
|
|
errs = append(errs, "keycloak.issuer is required when auth.type is 'keycloak'")
|
|
}
|
|
if c.Keycloak.Audience == "" {
|
|
errs = append(errs, "keycloak.audience is required when auth.type is 'keycloak'")
|
|
}
|
|
if c.Keycloak.JwksURL == "" {
|
|
errs = append(errs, "keycloak.jwks_url is required when auth.type is 'keycloak'")
|
|
}
|
|
case "static":
|
|
if len(c.Auth.StaticTokens) == 0 {
|
|
errs = append(errs, "auth.static_tokens is required when auth.type is 'static'")
|
|
}
|
|
case "hybrid":
|
|
if c.Auth.FallbackTo == "" {
|
|
errs = append(errs, "auth.fallback_to is required when auth.type is 'hybrid'")
|
|
}
|
|
// Validate fallback configuration
|
|
switch c.Auth.FallbackTo {
|
|
case "keycloak":
|
|
if !c.Keycloak.Enabled {
|
|
errs = append(errs, "keycloak.enabled must be true when auth.fallback_to is 'keycloak'")
|
|
}
|
|
case "static":
|
|
if len(c.Auth.StaticTokens) == 0 {
|
|
errs = append(errs, "auth.static_tokens is required when auth.fallback_to is 'static'")
|
|
}
|
|
}
|
|
}
|
|
|
|
// Legacy validation for backward compatibility
|
|
if c.Auth.Type != "keycloak" && c.Keycloak.Enabled {
|
|
if c.Keycloak.Issuer == "" {
|
|
errs = append(errs, "Keycloak issuer is required when Keycloak is enabled")
|
|
}
|
|
if c.Keycloak.Audience == "" {
|
|
errs = append(errs, "Keycloak audience is required when Keycloak is enabled")
|
|
}
|
|
if c.Keycloak.JwksURL == "" {
|
|
errs = append(errs, "Keycloak JWKS URL is required when Keycloak is enabled")
|
|
}
|
|
}
|
|
|
|
// Validate SatuSehat configuration
|
|
if c.SatuSehat.Enabled {
|
|
if c.SatuSehat.OrgID == "" {
|
|
errs = append(errs, "SatuSehat Organization ID is required when SatuSehat is enabled")
|
|
}
|
|
if c.SatuSehat.FasyakesID == "" {
|
|
errs = append(errs, "SatuSehat Fasyankes ID is required when SatuSehat is enabled")
|
|
}
|
|
if c.SatuSehat.ClientID == "" {
|
|
errs = append(errs, "SatuSehat Client ID is required when SatuSehat is enabled")
|
|
}
|
|
if c.SatuSehat.ClientSecret == "" {
|
|
errs = append(errs, "SatuSehat Client Secret is required when SatuSehat is enabled")
|
|
}
|
|
if c.SatuSehat.AuthURL == "" {
|
|
errs = append(errs, "SatuSehat Auth URL is required when SatuSehat is enabled")
|
|
}
|
|
if c.SatuSehat.BaseURL == "" {
|
|
errs = append(errs, "SatuSehat Base URL is required when SatuSehat is enabled")
|
|
}
|
|
}
|
|
|
|
if len(errs) > 0 {
|
|
return fmt.Errorf("configuration validation failed: %s", strings.Join(errs, "; "))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Additional helper functions for configuration validation
|
|
func (c *Config) IsJWTAuthEnabled() bool {
|
|
return c.Auth.Type == "jwt"
|
|
}
|
|
|
|
func (c *Config) IsKeycloakAuthEnabled() bool {
|
|
return c.Auth.Type == "keycloak" && c.Keycloak.Enabled
|
|
}
|
|
|
|
func (c *Config) IsStaticAuthEnabled() bool {
|
|
return c.Auth.Type == "static"
|
|
}
|
|
|
|
func (c *Config) IsHybridAuthEnabled() bool {
|
|
return c.Auth.Type == "hybrid"
|
|
}
|
|
|
|
func (c *Config) IsBPJSEnabled() bool {
|
|
hasCons := c.Bpjs.ConsID != "" || c.Bpjs.ApotekConsID != ""
|
|
return c.Bpjs.Enabled && c.Bpjs.BaseURL != "" && c.Bpjs.ServiceName != "" && hasCons
|
|
}
|
|
|
|
func (c *Config) IsSatuSehatEnabled() bool {
|
|
return c.SatuSehat.Enabled && c.SatuSehat.BaseURL != "" && c.SatuSehat.ClientID != "" && c.SatuSehat.ClientSecret != ""
|
|
}
|
|
|
|
func (c *Config) IsProductionMode() bool {
|
|
return strings.ToLower(c.Server.Mode) == "release"
|
|
}
|
|
|
|
func (c *Config) IsDevelopmentMode() bool {
|
|
return strings.ToLower(c.Server.Mode) == "debug" || strings.ToLower(c.Server.Mode) == "test"
|
|
}
|
|
|
|
func (c *Config) GetLogLevel() string {
|
|
if c.IsProductionMode() {
|
|
return "info"
|
|
}
|
|
return "debug"
|
|
}
|
|
|
|
func (c *Config) ShouldUseHTTPS() bool {
|
|
return c.IsProductionMode() || strings.Contains(strings.ToLower(c.Server.Mode), "prod")
|
|
}
|
|
|
|
func (c *Config) GetServerPorts() (int, int) {
|
|
return c.Server.REST.Port, c.Server.GRPC.Port
|
|
}
|
|
|
|
func (c *Config) GetMaxUploadSize() int64 {
|
|
sizeStr := os.Getenv("MAX_UPLOAD_SIZE")
|
|
if sizeStr == "" {
|
|
sizeStr = "10485760" // 10MB default
|
|
}
|
|
if size, err := strconv.ParseInt(sizeStr, 10, 64); err == nil {
|
|
return size
|
|
}
|
|
return 10485760
|
|
}
|
|
|
|
func (c *Config) GetRateLimitConfig() (int, int) {
|
|
requestsPerMinute := c.Security.RateLimit.RequestsPerMinute
|
|
if requestsPerMinute <= 0 {
|
|
requestsPerMinute = 60 // Default 60 requests per minute
|
|
}
|
|
burstSize := 10 // Default burst size
|
|
return requestsPerMinute, burstSize
|
|
}
|
|
|
|
func (c *Config) GetTrustedOrigins() []string {
|
|
origins := make([]string, len(c.Security.TrustedOrigins))
|
|
for i, origin := range c.Security.TrustedOrigins {
|
|
origins[i] = strings.TrimSpace(origin)
|
|
}
|
|
return origins
|
|
}
|
|
|
|
func (c *Config) IsOriginTrusted(origin string) bool {
|
|
for _, trusted := range c.GetTrustedOrigins() {
|
|
if origin == trusted {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Helper functions for environment variables
|
|
func getEnv(key, defaultValue string) string {
|
|
if value := os.Getenv(key); value != "" {
|
|
return value
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
func getEnvAsInt(key string, defaultValue int) int {
|
|
valueStr := getEnv(key, "")
|
|
if value, err := strconv.Atoi(valueStr); err == nil {
|
|
return value
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
func getEnvAsBool(key string, defaultValue bool) bool {
|
|
valueStr := getEnv(key, "")
|
|
if value, err := strconv.ParseBool(valueStr); err == nil {
|
|
return value
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
func parseDuration(durationStr string) time.Duration {
|
|
if duration, err := time.ParseDuration(durationStr); err == nil {
|
|
return duration
|
|
}
|
|
return 5 * time.Minute
|
|
}
|
|
|
|
func parseSchemes(schemesStr string) []string {
|
|
if schemesStr == "" {
|
|
return []string{"http"}
|
|
}
|
|
|
|
schemes := strings.Split(schemesStr, ",")
|
|
for i, scheme := range schemes {
|
|
schemes[i] = strings.TrimSpace(scheme)
|
|
}
|
|
return schemes
|
|
}
|
|
|
|
func parseStaticTokens(tokensStr string) []string {
|
|
if tokensStr == "" {
|
|
return []string{}
|
|
}
|
|
|
|
tokens := strings.Split(tokensStr, ",")
|
|
for i, token := range tokens {
|
|
tokens[i] = strings.TrimSpace(token)
|
|
// Remove empty tokens
|
|
if tokens[i] == "" {
|
|
tokens = append(tokens[:i], tokens[i+1:]...)
|
|
i--
|
|
}
|
|
}
|
|
return tokens
|
|
}
|
|
|
|
func parseOrigins(originsStr string) []string {
|
|
if originsStr == "" {
|
|
return []string{"http://localhost:8080"} // Default untuk pengembangan
|
|
}
|
|
origins := strings.Split(originsStr, ",")
|
|
for i, origin := range origins {
|
|
origins[i] = strings.TrimSpace(origin)
|
|
}
|
|
return origins
|
|
}
|
|
|
|
// Additional database loading functions would go here...
|
|
func (c *Config) loadDatabaseConfigs() {
|
|
// Load PostgreSQL configurations
|
|
c.addPostgreSQLConfigs()
|
|
|
|
// Load MySQL configurations
|
|
c.addMySQLConfigs()
|
|
|
|
// Load MongoDB configurations
|
|
c.addMongoDBConfigs()
|
|
|
|
// Load SQLite configurations
|
|
c.addSQLiteConfigs()
|
|
// Load SQL Server configurations
|
|
c.addSQLServerConfigs()
|
|
// Load custom database configurations from environment variables
|
|
c.loadCustomDatabaseConfigs()
|
|
|
|
// Remove duplicate database configurations
|
|
c.removeDuplicateDatabases()
|
|
}
|
|
|
|
func (c *Config) addPostgreSQLConfigs() {
|
|
envVars := os.Environ()
|
|
for _, envVar := range envVars {
|
|
parts := strings.SplitN(envVar, "=", 2)
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
|
|
key := parts[0]
|
|
|
|
// Format yang diharapkan: POSTGRES_[NAMA_DB]_[PROPERTY]
|
|
// Contoh: POSTGRES_DEFAULT_HOST
|
|
if strings.HasPrefix(key, "POSTGRES_") && strings.Count(key, "_") >= 2 {
|
|
segments := strings.Split(key, "_")
|
|
// segments[0] = "POSTGRES"
|
|
// segments[1...n-1] = Nama Database
|
|
// segments[n] = Property (HOST, PORT, dll)
|
|
|
|
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
|
|
property := strings.ToLower(segments[len(segments)-1])
|
|
value := parts[1]
|
|
|
|
// Ambil config yang sudah ada, atau buat baru
|
|
dbCfg, exists := c.Databases[dbName]
|
|
if !exists {
|
|
dbCfg = DatabaseConfig{
|
|
Name: dbName,
|
|
Type: "postgres",
|
|
Host: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_HOST", "localhost"),
|
|
Port: getEnvAsInt("POSTGRES_"+strings.ToUpper(dbName)+"_PORT", 5432),
|
|
Username: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_USERNAME", ""),
|
|
Password: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_PASSWORD", ""),
|
|
Database: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_DATABASE", dbName),
|
|
Schema: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_SCHEMA", "public"),
|
|
SSLMode: getEnv("POSTGRES_"+strings.ToUpper(dbName)+"_SSLMODE", "disable"),
|
|
MaxOpenConns: 25,
|
|
MaxIdleConns: 25,
|
|
ConnMaxLifetime: 5 * time.Minute,
|
|
IsActive: true,
|
|
}
|
|
}
|
|
|
|
// Logic update dinamis berdasarkan property yang sedang dibaca
|
|
// Ini penting agar Host, Port, dan Password terisi dengan benar
|
|
switch property {
|
|
case "host":
|
|
dbCfg.Host = value
|
|
case "port":
|
|
if port, err := strconv.Atoi(value); err == nil {
|
|
dbCfg.Port = port
|
|
}
|
|
case "username":
|
|
dbCfg.Username = value
|
|
case "password":
|
|
dbCfg.Password = value
|
|
case "database":
|
|
dbCfg.Database = value
|
|
case "schema":
|
|
dbCfg.Schema = value
|
|
case "sslmode":
|
|
dbCfg.SSLMode = value
|
|
}
|
|
|
|
c.Databases[dbName] = dbCfg
|
|
}
|
|
}
|
|
}
|
|
|
|
// Additional helper functions would be implemented here...
|
|
func (c *Config) addMySQLConfigs() {
|
|
envVars := os.Environ()
|
|
for _, envVar := range envVars {
|
|
parts := strings.SplitN(envVar, "=", 2)
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
|
|
key := parts[0]
|
|
if strings.HasPrefix(key, "MYSQL_") && strings.Count(key, "_") >= 2 {
|
|
segments := strings.Split(key, "_")
|
|
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
|
|
property := strings.ToLower(segments[len(segments)-1])
|
|
value := parts[1]
|
|
|
|
dbCfg, exists := c.Databases[dbName]
|
|
if !exists {
|
|
dbCfg = DatabaseConfig{
|
|
Name: dbName,
|
|
Type: "mysql",
|
|
Host: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_HOST", "localhost"),
|
|
Port: getEnvAsInt("MYSQL_"+strings.ToUpper(dbName)+"_PORT", 3306),
|
|
Username: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_USERNAME", ""),
|
|
Password: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_PASSWORD", ""),
|
|
Database: getEnv("MYSQL_"+strings.ToUpper(dbName)+"_DATABASE", dbName),
|
|
MaxOpenConns: 25,
|
|
MaxIdleConns: 25,
|
|
ConnMaxLifetime: 5 * time.Minute,
|
|
IsActive: true,
|
|
}
|
|
}
|
|
|
|
switch property {
|
|
case "host":
|
|
dbCfg.Host = value
|
|
case "port":
|
|
if port, err := strconv.Atoi(value); err == nil {
|
|
dbCfg.Port = port
|
|
}
|
|
case "username":
|
|
dbCfg.Username = value
|
|
case "password":
|
|
dbCfg.Password = value
|
|
case "database":
|
|
dbCfg.Database = value
|
|
}
|
|
c.Databases[dbName] = dbCfg
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) addMongoDBConfigs() {
|
|
envVars := os.Environ()
|
|
for _, envVar := range envVars {
|
|
parts := strings.SplitN(envVar, "=", 2)
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
|
|
key := parts[0]
|
|
if strings.HasPrefix(key, "MONGODB_") && strings.Count(key, "_") >= 2 {
|
|
segments := strings.Split(key, "_")
|
|
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
|
|
property := strings.ToLower(segments[len(segments)-1])
|
|
value := parts[1]
|
|
|
|
dbCfg, exists := c.Databases[dbName]
|
|
if !exists {
|
|
dbCfg = DatabaseConfig{
|
|
Name: dbName,
|
|
Type: "mongodb",
|
|
Host: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_HOST", "localhost"),
|
|
Port: getEnvAsInt("MONGODB_"+strings.ToUpper(dbName)+"_PORT", 27017),
|
|
Username: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_USERNAME", ""),
|
|
Password: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_PASSWORD", ""),
|
|
Database: getEnv("MONGODB_"+strings.ToUpper(dbName)+"_DATABASE", dbName),
|
|
IsActive: true,
|
|
}
|
|
}
|
|
|
|
switch property {
|
|
case "host":
|
|
dbCfg.Host = value
|
|
case "port":
|
|
if port, err := strconv.Atoi(value); err == nil {
|
|
dbCfg.Port = port
|
|
}
|
|
case "username":
|
|
dbCfg.Username = value
|
|
case "password":
|
|
dbCfg.Password = value
|
|
case "database":
|
|
dbCfg.Database = value
|
|
}
|
|
c.Databases[dbName] = dbCfg
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) addSQLiteConfigs() {
|
|
envVars := os.Environ()
|
|
for _, envVar := range envVars {
|
|
parts := strings.SplitN(envVar, "=", 2)
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
|
|
key := parts[0]
|
|
if strings.HasPrefix(key, "SQLITE_") && strings.Count(key, "_") >= 2 {
|
|
segments := strings.Split(key, "_")
|
|
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
|
|
property := strings.ToLower(segments[len(segments)-1])
|
|
value := parts[1]
|
|
|
|
dbCfg, exists := c.Databases[dbName]
|
|
if !exists {
|
|
dbCfg = DatabaseConfig{
|
|
Name: dbName,
|
|
Type: "sqlite",
|
|
Path: getEnv("SQLITE_"+strings.ToUpper(dbName)+"_PATH", "./"+dbName+".db"),
|
|
IsActive: true,
|
|
}
|
|
}
|
|
|
|
if property == "path" {
|
|
dbCfg.Path = value
|
|
}
|
|
c.Databases[dbName] = dbCfg
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) addSQLServerConfigs() {
|
|
envVars := os.Environ()
|
|
for _, envVar := range envVars {
|
|
parts := strings.SplitN(envVar, "=", 2)
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
|
|
key := parts[0]
|
|
|
|
// Format yang diharapkan: SQLSERVER_[NAMA_DB]_[PROPERTY]
|
|
// Contoh: SQLSERVER_FARMASI_HOST
|
|
if strings.HasPrefix(key, "SQLSERVER_") && strings.Count(key, "_") >= 2 {
|
|
segments := strings.Split(key, "_")
|
|
// segments[0] = "SQLSERVER"
|
|
// segments[1...n-1] = Nama Database
|
|
// segments[n] = Property (HOST, PORT, dll)
|
|
|
|
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
|
|
property := strings.ToLower(segments[len(segments)-1])
|
|
value := parts[1]
|
|
|
|
// Ambil config yang sudah ada, atau buat baru
|
|
dbCfg, exists := c.Databases[dbName]
|
|
if !exists {
|
|
dbCfg = DatabaseConfig{
|
|
Name: dbName,
|
|
Type: "sqlserver",
|
|
Host: getEnv("SQLSERVER_"+strings.ToUpper(dbName)+"_HOST", "localhost"),
|
|
Port: getEnvAsInt("SQLSERVER_"+strings.ToUpper(dbName)+"_PORT", 1433),
|
|
Username: getEnv("SQLSERVER_"+strings.ToUpper(dbName)+"_USERNAME", ""),
|
|
Password: getEnv("SQLSERVER_"+strings.ToUpper(dbName)+"_PASSWORD", ""),
|
|
Database: getEnv("SQLSERVER_"+strings.ToUpper(dbName)+"_DATABASE", dbName),
|
|
SSLMode: getEnv("SQLSERVER_"+strings.ToUpper(dbName)+"_SSLMODE", "disable"),
|
|
MaxOpenConns: 25,
|
|
MaxIdleConns: 25,
|
|
ConnMaxLifetime: 5 * time.Minute,
|
|
}
|
|
}
|
|
|
|
// Update field berdasarkan property
|
|
switch property {
|
|
case "host":
|
|
dbCfg.Host = value
|
|
case "port":
|
|
if port, err := strconv.Atoi(value); err == nil {
|
|
dbCfg.Port = port
|
|
}
|
|
case "username":
|
|
dbCfg.Username = value
|
|
case "password":
|
|
dbCfg.Password = value
|
|
case "database":
|
|
dbCfg.Database = value
|
|
case "sslmode":
|
|
dbCfg.SSLMode = value
|
|
case "timeout":
|
|
dbCfg.Timeout = parseDuration(value)
|
|
case "max_open_conns":
|
|
if conns, err := strconv.Atoi(value); err == nil {
|
|
dbCfg.MaxOpenConns = conns
|
|
}
|
|
case "max_idle_conns":
|
|
if conns, err := strconv.Atoi(value); err == nil {
|
|
dbCfg.MaxIdleConns = conns
|
|
}
|
|
case "conn_max_lifetime":
|
|
dbCfg.ConnMaxLifetime = parseDuration(value)
|
|
}
|
|
|
|
c.Databases[dbName] = dbCfg
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) loadCustomDatabaseConfigs() {
|
|
envVars := os.Environ()
|
|
for _, envVar := range envVars {
|
|
parts := strings.SplitN(envVar, "=", 2)
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
|
|
key := parts[0]
|
|
// Format yang diharapkan: DB_[NAMA_DB]_[PROPERTY]
|
|
if strings.HasPrefix(key, "DB_") && strings.Count(key, "_") >= 2 {
|
|
segments := strings.Split(key, "_")
|
|
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-1], "_"))
|
|
property := strings.ToLower(segments[len(segments)-1])
|
|
value := parts[1]
|
|
|
|
dbCfg, exists := c.Databases[dbName]
|
|
if !exists {
|
|
dbCfg = DatabaseConfig{
|
|
Name: dbName,
|
|
MaxOpenConns: 25,
|
|
MaxIdleConns: 25,
|
|
ConnMaxLifetime: 5 * time.Minute,
|
|
IsActive: true,
|
|
}
|
|
}
|
|
|
|
switch property {
|
|
case "type":
|
|
dbCfg.Type = value
|
|
case "host":
|
|
dbCfg.Host = value
|
|
case "port":
|
|
if port, err := strconv.Atoi(value); err == nil {
|
|
dbCfg.Port = port
|
|
}
|
|
case "username":
|
|
dbCfg.Username = value
|
|
case "password":
|
|
dbCfg.Password = value
|
|
case "database":
|
|
dbCfg.Database = value
|
|
case "schema":
|
|
dbCfg.Schema = value
|
|
case "path":
|
|
dbCfg.Path = value
|
|
case "sslmode":
|
|
dbCfg.SSLMode = value
|
|
}
|
|
c.Databases[dbName] = dbCfg
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) removeDuplicateDatabases() {
|
|
// Menghapus konfigurasi database yang tidak valid / kosong
|
|
for name, db := range c.Databases {
|
|
if db.Type == "" {
|
|
delete(c.Databases, name)
|
|
continue
|
|
}
|
|
// SQLite tidak butuh Host, sisanya butuh
|
|
if db.Type != "sqlite" && db.Host == "" {
|
|
delete(c.Databases, name)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
func (c *Config) loadReadReplicaConfigs() {
|
|
envVars := os.Environ()
|
|
for _, envVar := range envVars {
|
|
parts := strings.SplitN(envVar, "=", 2)
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
|
|
key := parts[0]
|
|
// Format: REPLICA_[DBNAME]_[INDEX]_[PROPERTY], cth: REPLICA_DEFAULT_0_HOST
|
|
if strings.HasPrefix(key, "REPLICA_") && strings.Count(key, "_") >= 3 {
|
|
segments := strings.Split(key, "_")
|
|
property := strings.ToLower(segments[len(segments)-1])
|
|
indexStr := segments[len(segments)-2]
|
|
dbName := strings.ToLower(strings.Join(segments[1:len(segments)-2], "_"))
|
|
value := parts[1]
|
|
|
|
index, err := strconv.Atoi(indexStr)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
replicas := c.ReadReplicas[dbName]
|
|
for len(replicas) <= index {
|
|
// Turunkan pengaturan dasar dari database master (seperti port, user)
|
|
baseCfg := c.Databases[dbName]
|
|
baseCfg.Name = fmt.Sprintf("%s-replica-%d", dbName, len(replicas))
|
|
replicas = append(replicas, baseCfg)
|
|
}
|
|
|
|
replicaCfg := replicas[index]
|
|
switch property {
|
|
case "host":
|
|
replicaCfg.Host = value
|
|
case "port":
|
|
if p, err := strconv.Atoi(value); err == nil {
|
|
replicaCfg.Port = p
|
|
}
|
|
case "username":
|
|
replicaCfg.Username = value
|
|
case "password":
|
|
replicaCfg.Password = value
|
|
case "database":
|
|
replicaCfg.Database = value
|
|
}
|
|
|
|
replicas[index] = replicaCfg
|
|
c.ReadReplicas[dbName] = replicas
|
|
}
|
|
}
|
|
}
|
|
|
|
func loadAuthConfig() AuthConfig {
|
|
return AuthConfig{
|
|
Type: getEnv("AUTH_TYPE", "jwt"),
|
|
FallbackTo: getEnv("AUTH_FALLBACK_TO", "jwt"),
|
|
StaticTokens: parseStaticTokens(getEnv("AUTH_STATIC_TOKENS", "")),
|
|
}
|
|
}
|
|
|
|
func loadKeycloakConfig() KeycloakConfig {
|
|
return KeycloakConfig{
|
|
Enabled: getEnvAsBool("KEYCLOAK_ENABLED", false),
|
|
URL: getEnv("KEYCLOAK_URL", ""),
|
|
Realm: getEnv("KEYCLOAK_REALM", ""),
|
|
ClientID: getEnv("KEYCLOAK_CLIENT_ID", ""),
|
|
ClientSecret: getEnv("KEYCLOAK_CLIENT_SECRET", ""),
|
|
Issuer: getEnv("KEYCLOAK_ISSUER", ""),
|
|
Audience: getEnv("KEYCLOAK_AUDIENCE", ""),
|
|
JwksURL: getEnv("KEYCLOAK_JWKS_URL", ""),
|
|
}
|
|
}
|