package config import ( "encoding" "encoding/base64" "fmt" "github.com/fatih/structs" "github.com/iancoleman/strcase" "github.com/spf13/viper" "go.uber.org/fx" "go.uber.org/zap" "reflect" ) import ( "crypto/ed25519" ) type PrivateKey ed25519.PrivateKey var ( _ encoding.TextUnmarshaler = (*PrivateKey)(nil) _ encoding.TextMarshaler = (*PrivateKey)(nil) ) func (p *PrivateKey) UnmarshalText(text []byte) error { dec, err := base64.StdEncoding.DecodeString(string(text)) if err != nil { return err } *p = dec return nil } func (p *PrivateKey) MarshalText() ([]byte, error) { return []byte(base64.StdEncoding.EncodeToString(*p)), nil } type Config struct { Host string `mapstructure:"host" structs:"host"` Port int `mapstructure:"port" structs:"port"` GiteaUrl string `mapstructure:"gitea_url" structs:"gitea_url"` DbPath string `mapstructure:"db_path" structs:"db_path"` Oauth OauthConfig JwtPrivateKey PrivateKey Domain string `mapstructure:"domain" structs:"domain"` GiteaWebHookSecret string `mapstructure:"gitea_webhook_secret" structs:"gitea_webhook_secret"` } type OauthConfig struct { Authorization string `mapstructure:"authorization" structs:"authorization"` Token string `mapstructure:"token" structs:"token"` ClientId string `mapstructure:"client_id" structs:"client_id"` ClientSecret string `mapstructure:"client_secret" structs:"client_secret"` RefreshToken string `mapstructure:"refresh_token" structs:"refresh_token"` } var Module = fx.Module("config", fx.Options( fx.Provide(NewConfig), ), ) func NewConfig(logger *zap.Logger) *Config { c := &Config{} _, sk, err := ed25519.GenerateKey(nil) if err != nil { logger.Fatal("Error generating private key", zap.Error(err)) } // Set the default values viper.SetDefault("host", "localhost") viper.SetDefault("port", 8080) viper.SetDefault("gitea_url", "") viper.SetDefault("db_path", "data.db") viper.SetDefault("jwt_private_key", base64.StdEncoding.EncodeToString(sk)) viper.SetDefault("oauth.client_id", "") viper.SetDefault("oauth.client_secret", "") viper.AddConfigPath(".") viper.AddConfigPath("/etc/gitea-github-proxy") viper.SetConfigName("config") viper.SetConfigType("yaml") err = viper.ReadInConfig() if err != nil { err = viper.SafeWriteConfig() if err != nil { logger.Fatal("Error writing config file", zap.Error(err)) } } err = viper.Unmarshal(c) if err != nil { logger.Fatal("Error unmarshalling config", zap.Error(err)) } /* err = viper.UnmarshalKey("jwt_private_key", &c.JwtPrivateKey, viper.DecodeHook(mapstructure.TextUnmarshallerHookFunc())) if err != nil { logger.Fatal("Error unmarshalling jwtPrivateKey", zap.Error(err)) }*/ if len(c.GiteaUrl) == 0 { logger.Fatal("Gitea URL is required") } return c } func SaveConfig(cfg *Config) error { data := structs.New(cfg) for _, field := range data.Fields() { processFields(field, nil) } /* if field, ok := interface{}(cfg.JwtPrivateKey).(encoding.TextMarshaler); ok { text, err := field.MarshalText() if err != nil { return err } viper.Set("jwt_private_key", string(text)) } */ return viper.WriteConfig() } func processFields(f *structs.Field, parent *structs.Field) { if f.IsZero() { return } if f.Kind() == reflect.Struct { fields := f.Fields() if len(fields) > 0 { for _, field := range fields { processFields(field, f) } return } } name := "" if parent != nil { name = fmt.Sprintf("%s.%s", parent.Name(), f.Name()) } else { name = f.Name() } name = strcase.ToSnakeWithIgnore(name, ".") viper.Set(name, f.Value()) }