feat: initial commit
This commit is contained in:
48
internal/config/api.go
Normal file
48
internal/config/api.go
Normal file
@ -0,0 +1,48 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type APIConfig struct {
|
||||
Authentication AuthenticationConfig `yaml:"auth" envPrefix:"AUTH_"`
|
||||
}
|
||||
|
||||
type Accounts []AccountConfig
|
||||
|
||||
type AuthenticationConfig struct {
|
||||
Accounts Accounts `yaml:"accounts" env:"ACCOUNTS"`
|
||||
}
|
||||
|
||||
func parseAccounts(value string) (any, error) {
|
||||
var accounts Accounts
|
||||
|
||||
spew.Dump(value)
|
||||
|
||||
if err := json.Unmarshal([]byte(value), &accounts); err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
return accounts, nil
|
||||
}
|
||||
|
||||
type AccountConfig struct {
|
||||
Username string `yaml:"username" json:"username"`
|
||||
Password string `yaml:"password" json:"password"`
|
||||
}
|
||||
|
||||
func NewDefaultAPIConfig() APIConfig {
|
||||
return APIConfig{
|
||||
Authentication: AuthenticationConfig{
|
||||
Accounts: []AccountConfig{
|
||||
{
|
||||
Username: "admin",
|
||||
Password: "webauthn",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
128
internal/config/config.go
Normal file
128
internal/config/config.go
Normal file
@ -0,0 +1,128 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/caarlos0/env/v10"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Debug bool `yaml:"debug" env:"DEBUG"`
|
||||
HTTP HTTPConfig `yaml:"http" envPrefix:"HTTP_"`
|
||||
Hydra HydraConfig `yaml:"hydra" envPrefix:"HYDRA_"`
|
||||
Session SessionConfig `yaml:"session" envPrefix:"SESSION_"`
|
||||
Sentry SentryConfig `yaml:"sentry" envPrefix:"SENTRY_"`
|
||||
WebAuthn WebAuthnConfig `yaml:"webauthn" envPrefix:"WEBAUTHN_"`
|
||||
API APIConfig `yaml:"api" envPrefix:"API_"`
|
||||
Storage StorageConfig `yaml:"storage" envPrefix:"STORAGE_"`
|
||||
}
|
||||
|
||||
// NewFromFile retrieves the configuration from the given file
|
||||
func NewFromFile(filepath string) (*Config, error) {
|
||||
config := NewDefault()
|
||||
|
||||
data, err := os.ReadFile(filepath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not read file '%s'", filepath)
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(data, config); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not unmarshal configuration")
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
type HydraConfig struct {
|
||||
BaseURL string `yaml:"baseURL" env:"BASE_URL"`
|
||||
// Fake upstream SSL termination adding the "X-Forwarded-Proto: https" to the OIDC client
|
||||
// HTTP request headers.
|
||||
// Required by ory/hydra in some networks topologies
|
||||
FakeSSLTermination bool `yaml:"fakeSSLTermination" env:"FAKE_SSL_TERMINATION"`
|
||||
HTTPClientTimeout time.Duration `yaml:"httpClientTimeout" env:"HTTP_CLIENT_TIMEOUT"`
|
||||
}
|
||||
|
||||
type SessionConfig struct {
|
||||
DefaultDuration int `yaml:"defaultDuration" env:"DEFAULT_DURATION"`
|
||||
RememberMeDuration int `yaml:"rememberMeDuration" env:"REMEMBER_ME_DURATION"`
|
||||
}
|
||||
|
||||
type SentryConfig struct {
|
||||
DSN string `yaml:"dsn" env:"DSN"`
|
||||
// Server events sampling rate, see https://docs.sentry.io/platforms/go/configuration/options/
|
||||
ServerSampleRate float64 `yaml:"serverSampleRate" env:"SERVER_SAMPLE_RATE"`
|
||||
ServerFlushTimeout time.Duration `yaml:"serverFlushTimeout" env:"SERVER_FLUSH_TIMEOUT"`
|
||||
Environment string `yaml:"environment" env:"ENVIRONMENT"`
|
||||
}
|
||||
|
||||
func NewDumpDefault() *Config {
|
||||
config := NewDefault()
|
||||
return config
|
||||
}
|
||||
|
||||
func NewDefault() *Config {
|
||||
return &Config{
|
||||
Debug: false,
|
||||
HTTP: HTTPConfig{
|
||||
Address: ":3000",
|
||||
CookieAuthenticationKey: "",
|
||||
CookieEncryptionKey: "",
|
||||
TokenEncryptionKey: "",
|
||||
TokenSigningKey: "",
|
||||
CookieMaxAge: int((time.Hour * 1).Seconds()), // 1 hour
|
||||
TemplateDir: "template",
|
||||
PublicDir: "public",
|
||||
BaseURL: "/",
|
||||
},
|
||||
Hydra: HydraConfig{
|
||||
BaseURL: "http://localhost:4445/",
|
||||
FakeSSLTermination: false,
|
||||
HTTPClientTimeout: time.Second * 30, //nolint: gomnb
|
||||
},
|
||||
Session: SessionConfig{
|
||||
DefaultDuration: int((time.Hour * 1).Seconds()), // 1 hour
|
||||
RememberMeDuration: int((time.Hour * 24 * 30).Seconds()), // 30 days
|
||||
},
|
||||
Sentry: SentryConfig{
|
||||
DSN: "",
|
||||
ServerSampleRate: 1,
|
||||
ServerFlushTimeout: 2 * time.Second,
|
||||
Environment: "",
|
||||
},
|
||||
WebAuthn: NewDefaultWebAuthnConfig(),
|
||||
API: NewDefaultAPIConfig(),
|
||||
Storage: NewDefaultStorageConfig(),
|
||||
}
|
||||
}
|
||||
|
||||
func Dump(config *Config, w io.Writer) error {
|
||||
data, err := yaml.Marshal(config)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not dump config")
|
||||
}
|
||||
|
||||
if _, err := w.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithEnvironment(conf *Config) error {
|
||||
if err := env.ParseWithOptions(conf, env.Options{
|
||||
Prefix: "HYDRA_WEBAUTHN_",
|
||||
FuncMap: map[reflect.Type]env.ParserFunc{
|
||||
reflect.TypeOf(Accounts{}): parseAccounts,
|
||||
},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
13
internal/config/http.go
Normal file
13
internal/config/http.go
Normal file
@ -0,0 +1,13 @@
|
||||
package config
|
||||
|
||||
type HTTPConfig struct {
|
||||
Address string `yaml:"address" env:"ADDRESS"`
|
||||
CookieAuthenticationKey string `yaml:"cookieAuthenticationKey" env:"COOKIE_AUTHENTICATION_KEY"`
|
||||
CookieEncryptionKey string `yaml:"cookieEncryptionKey" env:"COOKIE_ENCRYPTION_KEY"`
|
||||
TokenSigningKey string `yaml:"tokenSigningKey" env:"TOKEN_SIGNING_KEY"`
|
||||
TokenEncryptionKey string `yaml:"tokenEncryptionKey" env:"TOKEN_ENCRYPTION_KEY"`
|
||||
BaseURL string `yaml:"basePublicUrl" env:"BASE_URL"`
|
||||
CookieMaxAge int `yaml:"cookieMaxAge" env:"COOKIE_MAX_AGE"`
|
||||
TemplateDir string `yaml:"templateDir" env:"TEMPLATE_DIR"`
|
||||
PublicDir string `yaml:"publicDir" env:"PUBLIC_DIR"`
|
||||
}
|
9
internal/config/provider.go
Normal file
9
internal/config/provider.go
Normal file
@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
import "gitlab.com/wpetit/goweb/service"
|
||||
|
||||
func ServiceProvider(config *Config) service.Provider {
|
||||
return func(ctn *service.Container) (interface{}, error) {
|
||||
return config, nil
|
||||
}
|
||||
}
|
33
internal/config/service.go
Normal file
33
internal/config/service.go
Normal file
@ -0,0 +1,33 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/service"
|
||||
)
|
||||
|
||||
const ServiceName service.Name = "config"
|
||||
|
||||
// From retrieves the config service in the given container
|
||||
func From(container *service.Container) (*Config, error) {
|
||||
service, err := container.Service(ServiceName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error while retrieving '%s' service", ServiceName)
|
||||
}
|
||||
|
||||
srv, ok := service.(*Config)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("retrieved service is not a valid '%s' service", ServiceName)
|
||||
}
|
||||
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
// Must retrieves the config service in the given container or panic otherwise
|
||||
func Must(container *service.Container) *Config {
|
||||
srv, err := From(container)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return srv
|
||||
}
|
13
internal/config/storage.go
Normal file
13
internal/config/storage.go
Normal file
@ -0,0 +1,13 @@
|
||||
package config
|
||||
|
||||
type StorageConfig struct {
|
||||
Driver string `yaml:"driver" env:"DRIVER"`
|
||||
DSN string `yaml:"dsn" env:"DSN"`
|
||||
}
|
||||
|
||||
func NewDefaultStorageConfig() StorageConfig {
|
||||
return StorageConfig{
|
||||
Driver: "sqlite",
|
||||
DSN: "./data/storage.sqlite?mode=rw&_pragma=foreign_keys(1)&_pragma=busy_timeout=150000&_pragma=journal_mode=WAL",
|
||||
}
|
||||
}
|
21
internal/config/webauthn.go
Normal file
21
internal/config/webauthn.go
Normal file
@ -0,0 +1,21 @@
|
||||
package config
|
||||
|
||||
type WebAuthnConfig struct {
|
||||
RelyingParty WebAuthnRelyingPartyConfig `yaml:"relyingParty" envPrefix:"RELYINGPARTY_"`
|
||||
}
|
||||
|
||||
type WebAuthnRelyingPartyConfig struct {
|
||||
ID string `yaml:"id" env:"ID"`
|
||||
DisplayName string `yaml:"displayName" env:"DISPLAYNAME"`
|
||||
Origins []string `yaml:"origins" env:"ORIGINS" envSeparator:","`
|
||||
}
|
||||
|
||||
func NewDefaultWebAuthnConfig() WebAuthnConfig {
|
||||
return WebAuthnConfig{
|
||||
RelyingParty: WebAuthnRelyingPartyConfig{
|
||||
ID: "localhost",
|
||||
DisplayName: "WebAuthn",
|
||||
Origins: []string{"http://localhost:3000"},
|
||||
},
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user