Skip to content

Commit

Permalink
feat: generate more accurate backend config jsonschema
Browse files Browse the repository at this point in the history
  • Loading branch information
lfleischmann committed Jul 31, 2023
1 parent 82c571f commit 223cf9d
Show file tree
Hide file tree
Showing 3 changed files with 651 additions and 77 deletions.
148 changes: 75 additions & 73 deletions backend/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ import (

// Config is the central configuration type
type Config struct {
Server Server `yaml:"server" json:"server" koanf:"server"`
Webauthn WebauthnSettings `yaml:"webauthn" json:"webauthn" koanf:"webauthn"`
Server Server `yaml:"server" json:"server,omitempty" koanf:"server"`
Webauthn WebauthnSettings `yaml:"webauthn" json:"webauthn,omitempty" koanf:"webauthn"`
Passcode Passcode `yaml:"passcode" json:"passcode" koanf:"passcode"`
Password Password `yaml:"password" json:"password" koanf:"password"`
Password Password `yaml:"password" json:"password,omitempty" koanf:"password"`
Database Database `yaml:"database" json:"database" koanf:"database"`
Secrets Secrets `yaml:"secrets" json:"secrets" koanf:"secrets"`
Service Service `yaml:"service" json:"service" koanf:"service"`
Session Session `yaml:"session" json:"session" koanf:"session"`
AuditLog AuditLog `yaml:"audit_log" json:"audit_log" koanf:"audit_log" split_words:"true"`
Emails Emails `yaml:"emails" json:"emails" koanf:"emails"`
RateLimiter RateLimiter `yaml:"rate_limiter" json:"rate_limiter" koanf:"rate_limiter" split_words:"true"`
ThirdParty ThirdParty `yaml:"third_party" json:"third_party" koanf:"third_party" split_words:"true"`
Log LoggerConfig `yaml:"log" json:"log" koanf:"log"`
Account Account `yaml:"account" json:"account" koanf:"account"`
Session Session `yaml:"session" json:"session,omitempty" koanf:"session"`
AuditLog AuditLog `yaml:"audit_log" json:"audit_log,omitempty" koanf:"audit_log" split_words:"true"`
Emails Emails `yaml:"emails" json:"emails,omitempty" koanf:"emails"`
RateLimiter RateLimiter `yaml:"rate_limiter" json:"rate_limiter,omitempty" koanf:"rate_limiter" split_words:"true"`
ThirdParty ThirdParty `yaml:"third_party" json:"third_party,omitempty" koanf:"third_party" split_words:"true"`
Log LoggerConfig `yaml:"log" json:"log,omitempty" koanf:"log"`
Account Account `yaml:"account" json:"account,omitempty" koanf:"account"`
}

var (
Expand Down Expand Up @@ -185,8 +185,8 @@ func (c *Config) Validate() error {

// Server contains the setting for the public and admin server
type Server struct {
Public ServerSettings `yaml:"public" json:"public" koanf:"public"`
Admin ServerSettings `yaml:"admin" json:"admin" koanf:"admin"`
Public ServerSettings `yaml:"public" json:"public,omitempty" koanf:"public"`
Admin ServerSettings `yaml:"admin" json:"admin,omitempty" koanf:"admin"`
}

func (s *Server) Validate() error {
Expand All @@ -213,16 +213,16 @@ func (s *Service) Validate() error {
}

type Password struct {
Enabled bool `yaml:"enabled" json:"enabled" koanf:"enabled"`
MinPasswordLength int `yaml:"min_password_length" json:"min_password_length" koanf:"min_password_length" split_words:"true"`
Enabled bool `yaml:"enabled" json:"enabled,omitempty" koanf:"enabled" jsonschema:"default=false"`
MinPasswordLength int `yaml:"min_password_length" json:"min_password_length,omitempty" koanf:"min_password_length" split_words:"true" jsonschema:"default=8"`
}

type Cookie struct {
Name string `yaml:"name" json:"name" koanf:"name"`
Domain string `yaml:"domain" json:"domain" koanf:"domain"`
HttpOnly bool `yaml:"http_only" json:"http_only" koanf:"http_only" split_words:"true"`
SameSite string `yaml:"same_site" json:"same_site" koanf:"same_site" split_words:"true"`
Secure bool `yaml:"secure" json:"secure" koanf:"secure"`
Name string `yaml:"name" json:"name,omitempty" koanf:"name" jsonschema:"default=hanko"`
Domain string `yaml:"domain" json:"domain,omitempty" koanf:"domain"`
HttpOnly bool `yaml:"http_only" json:"http_only,omitempty" koanf:"http_only" split_words:"true"`
SameSite string `yaml:"same_site" json:"same_site,omitempty" koanf:"same_site" split_words:"true"`
Secure bool `yaml:"secure" json:"secure,omitempty" koanf:"secure"`
}

func (c *Cookie) GetName() string {
Expand All @@ -236,8 +236,8 @@ func (c *Cookie) GetName() string {
type ServerSettings struct {
// The Address to listen on in the form of host:port
// See net.Dial for details of the address format.
Address string `yaml:"address" json:"address" koanf:"address"`
Cors Cors `yaml:"cors" json:"cors" koanf:"cors"`
Address string `yaml:"address" json:"address,omitempty" koanf:"address"`
Cors Cors `yaml:"cors" json:"cors,omitempty" koanf:"cors"`
}

type Cors struct {
Expand All @@ -254,7 +254,7 @@ type Cors struct {
// attacks. See: https://github.com/labstack/echo/issues/2400 for discussion on the subject.
//
// Optional. Default value is false.
UnsafeWildcardOriginAllowed bool `yaml:"unsafe_wildcard_origin_allowed" json:"unsafe_wildcard_origin_allowed" koanf:"unsafe_wildcard_origin_allowed" split_words:"true"`
UnsafeWildcardOriginAllowed bool `yaml:"unsafe_wildcard_origin_allowed" json:"unsafe_wildcard_origin_allowed,omitempty" koanf:"unsafe_wildcard_origin_allowed" split_words:"true" jsonschema:"default=false"`
}

func (cors *Cors) Validate() error {
Expand All @@ -279,9 +279,9 @@ func (s *ServerSettings) Validate() error {

// WebauthnSettings defines the settings for the webauthn authentication mechanism
type WebauthnSettings struct {
RelyingParty RelyingParty `yaml:"relying_party" json:"relying_party" koanf:"relying_party" split_words:"true"`
Timeout int `yaml:"timeout" json:"timeout" koanf:"timeout"`
UserVerification string `yaml:"user_verification" json:"user_verification" koanf:"user_verification" split_words:"true""`
RelyingParty RelyingParty `yaml:"relying_party" json:"relying_party,omitempty" koanf:"relying_party" split_words:"true"`
Timeout int `yaml:"timeout" json:"timeout,omitempty" koanf:"timeout" jsonschema:"default=60000"`
UserVerification string `yaml:"user_verification" json:"user_verification,omitempty" koanf:"user_verification" split_words:"true" jsonschema:"default=preferred,enum=required,enum=preferred,enum=discouraged"`
}

// Validate does not need to validate the config, because the library does this already
Expand All @@ -295,18 +295,18 @@ func (r *WebauthnSettings) Validate() error {

// RelyingParty webauthn settings for your application using hanko.
type RelyingParty struct {
Id string `yaml:"id" json:"id" koanf:"id"`
DisplayName string `yaml:"display_name" json:"display_name" koanf:"display_name" split_words:"true"`
Icon string `yaml:"icon" json:"icon" koanf:"icon"`
Origins []string `yaml:"origins" json:"origins" koanf:"origins"`
Id string `yaml:"id" json:"id,omitempty" koanf:"id" jsonschema:"default=localhost"`
DisplayName string `yaml:"display_name" json:"display_name,omitempty" koanf:"display_name" split_words:"true" jsonschema:"default=Hanko Authentication Service"`
Icon string `yaml:"icon" json:"icon,omitempty" koanf:"icon"`
Origins []string `yaml:"origins" json:"origins,omitempty" koanf:"origins" jsonschema:"minItems=1,default=http://localhost:8888"`
}

// SMTP Server Settings for sending passcodes
type SMTP struct {
Host string `yaml:"host" json:"host" koanf:"host"`
Port string `yaml:"port" json:"port" koanf:"port"`
User string `yaml:"user" json:"user" koanf:"user"`
Password string `yaml:"password" json:"password" koanf:"password"`
Port string `yaml:"port" json:"port,omitempty" koanf:"port" jsonschema:"default=465,oneof_type=string;integer"`
User string `yaml:"user" json:"user,omitempty" koanf:"user"`
Password string `yaml:"password" json:"password,omitempty" koanf:"password"`
}

func (s *SMTP) Validate() error {
Expand All @@ -320,8 +320,8 @@ func (s *SMTP) Validate() error {
}

type Email struct {
FromAddress string `yaml:"from_address" json:"from_address" koanf:"from_address" split_words:"true"`
FromName string `yaml:"from_name" json:"from_name" koanf:"from_name" split_words:"true"`
FromAddress string `yaml:"from_address" json:"from_address,omitempty" koanf:"from_address" split_words:"true" jsonschema:"[email protected]"`
FromName string `yaml:"from_name" json:"from_name,omitempty" koanf:"from_name" split_words:"true" jsonschema:"default=Hanko"`
}

func (e *Email) Validate() error {
Expand All @@ -334,7 +334,7 @@ func (e *Email) Validate() error {
type Passcode struct {
Email Email `yaml:"email" json:"email" koanf:"email"`
Smtp SMTP `yaml:"smtp" json:"smtp" koanf:"smtp"`
TTL int `yaml:"ttl" json:"ttl" koanf:"ttl"`
TTL int `yaml:"ttl" json:"ttl,omitempty" koanf:"ttl" jsonschema:"default=300"`
}

func (p *Passcode) Validate() error {
Expand All @@ -351,13 +351,13 @@ func (p *Passcode) Validate() error {

// Database connection settings
type Database struct {
Database string `yaml:"database" json:"database" koanf:"database"`
User string `yaml:"user" json:"user" koanf:"user"`
Password string `yaml:"password" json:"password" koanf:"password"`
Host string `yaml:"host" json:"host" koanf:"host"`
Port string `yaml:"port" json:"port" koanf:"port"`
Dialect string `yaml:"dialect" json:"dialect" koanf:"dialect"`
Url string `yaml:"url" json:"url" koanf:"url"`
Database string `yaml:"database" json:"database,omitempty" koanf:"database" jsonschema:"default=hanko" jsonschema:"oneof_required=config"`
User string `yaml:"user" json:"user,omitempty" koanf:"user" jsonschema:"oneof_required=config"`
Password string `yaml:"password" json:"password,omitempty" koanf:"password" jsonschema:"oneof_required=config"`
Host string `yaml:"host" json:"host,omitempty" koanf:"host" jsonschema:"oneof_required=config"`
Port string `yaml:"port" json:"port,omitempty" koanf:"port" jsonschema:"oneof_required=config,oneof_type=string;integer"`
Dialect string `yaml:"dialect" json:"dialect,omitempty" koanf:"dialect" jsonschema:"oneof_required=config,enum=postgres,enum=mysql,enum=cockroach"`
Url string `yaml:"url" json:"url,omitempty" koanf:"url" jsonschema:"oneof_required=url"`
}

func (d *Database) Validate() error {
Expand Down Expand Up @@ -393,7 +393,7 @@ type Secrets struct {
// application startup will fail.
//
// Each key must be at least 16 characters long.
Keys []string `yaml:"keys" json:"keys" koanf:"keys"`
Keys []string `yaml:"keys" json:"keys" koanf:"keys" jsonschema:"minItems=1"`
}

func (s *Secrets) Validate() error {
Expand All @@ -404,15 +404,17 @@ func (s *Secrets) Validate() error {
}

type Session struct {
EnableAuthTokenHeader bool `yaml:"enable_auth_token_header" json:"enable_auth_token_header" koanf:"enable_auth_token_header" split_words:"true"`
Lifespan string `yaml:"lifespan" json:"lifespan" koanf:"lifespan"`
Cookie Cookie `yaml:"cookie" json:"cookie" koanf:"cookie"`
EnableAuthTokenHeader bool `yaml:"enable_auth_token_header" json:"enable_auth_token_header,omitempty" koanf:"enable_auth_token_header" split_words:"true" jsonschema:"default=false"`
// Lifespan, possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix,
// such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
Lifespan string `yaml:"lifespan" json:"lifespan,omitempty" koanf:"lifespan" jsonschema:"default=1h"`
Cookie Cookie `yaml:"cookie" json:"cookie,omitempty" koanf:"cookie"`

// Issuer optional string to be used in the jwt iss claim.
Issuer string `yaml:"issuer" json:"issuer" koanf:"issuer"`
Issuer string `yaml:"issuer" json:"issuer,omitempty" koanf:"issuer"`

// Audience optional []string containing strings which get put into the aud claim. If not set default to Webauthn.RelyingParty.Id config parameter.
Audience []string `yaml:"audience" json:"audience" koanf:"audience"`
Audience []string `yaml:"audience" json:"audience,omitempty" koanf:"audience"`
}

func (s *Session) Validate() error {
Expand All @@ -424,22 +426,22 @@ func (s *Session) Validate() error {
}

type AuditLog struct {
ConsoleOutput AuditLogConsole `yaml:"console_output" json:"console_output" koanf:"console_output" split_words:"true"`
Storage AuditLogStorage `yaml:"storage" json:"storage" koanf:"storage"`
ConsoleOutput AuditLogConsole `yaml:"console_output" json:"console_output,omitempty" koanf:"console_output" split_words:"true"`
Storage AuditLogStorage `yaml:"storage" json:"storage,omitempty" koanf:"storage"`
}

type AuditLogStorage struct {
Enabled bool `yaml:"enabled" json:"enabled" koanf:"enabled"`
Enabled bool `yaml:"enabled" json:"enabled,omitempty" koanf:"enabled" jsonschema:"default=false"`
}

type AuditLogConsole struct {
Enabled bool `yaml:"enabled" json:"enabled" koanf:"enabled"`
OutputStream OutputStream `yaml:"output" json:"output" koanf:"output" split_words:"true"`
Enabled bool `yaml:"enabled" json:"enabled,omitempty" koanf:"enabled" jsonschema:"default=true"`
OutputStream OutputStream `yaml:"output" json:"output,omitempty" koanf:"output" split_words:"true" jsonschema:"default=stdout,enum=stdout,enum=stderr"`
}

type Emails struct {
RequireVerification bool `yaml:"require_verification" json:"require_verification" koanf:"require_verification" split_words:"true"`
MaxNumOfAddresses int `yaml:"max_num_of_addresses" json:"max_num_of_addresses" koanf:"max_num_of_addresses" split_words:"true"`
RequireVerification bool `yaml:"require_verification" json:"require_verification,omitempty" koanf:"require_verification" split_words:"true" jsonschema:"default=true"`
MaxNumOfAddresses int `yaml:"max_num_of_addresses" json:"max_num_of_addresses,omitempty" koanf:"max_num_of_addresses" split_words:"true" jsonschema:"default=5"`
}

type OutputStream string
Expand All @@ -450,12 +452,12 @@ var (
)

type RateLimiter struct {
Enabled bool `yaml:"enabled" json:"enabled" koanf:"enabled"`
Store RateLimiterStoreType `yaml:"store" json:"store" koanf:"store"`
Redis *RedisConfig `yaml:"redis_config" json:"redis_config" koanf:"redis_config"`
PasscodeLimits RateLimits `yaml:"passcode_limits" json:"passcode_limits" koanf:"passcode_limits" split_words:"true"`
PasswordLimits RateLimits `yaml:"password_limits" json:"password_limits" koanf:"password_limits" split_words:"true"`
TokenLimits RateLimits `yaml:"token_limits" json:"token_limits" koanf:"token_limits" split_words:"true"`
Enabled bool `yaml:"enabled" json:"enabled,omitempty" koanf:"enabled" jsonschema:"default=true"`
Store RateLimiterStoreType `yaml:"store" json:"store,omitempty" koanf:"store" jsonschema:"default=in_memory,enum=in_memory,enum=redis"`
Redis *RedisConfig `yaml:"redis_config" json:"redis_config,omitempty" koanf:"redis_config"`
PasscodeLimits RateLimits `yaml:"passcode_limits" json:"passcode_limits,omitempty" koanf:"passcode_limits" split_words:"true"`
PasswordLimits RateLimits `yaml:"password_limits" json:"password_limits,omitempty" koanf:"password_limits" split_words:"true"`
TokenLimits RateLimits `yaml:"token_limits" json:"token_limits,omitempty" koanf:"token_limits" split_words:"true"`
}

type RateLimits struct {
Expand Down Expand Up @@ -490,17 +492,17 @@ func (r *RateLimiter) Validate() error {
}

type RedisConfig struct {
//Address of redis in the form of host[:port][/database]
// Address of redis in the form of host[:port][/database]
Address string `yaml:"address" json:"address" koanf:"address"`
Password string `yaml:"password" json:"password" koanf:"password"`
Password string `yaml:"password" json:"password,omitempty" koanf:"password"`
}

type ThirdParty struct {
Providers ThirdPartyProviders `yaml:"providers" json:"providers" koanf:"providers"`
RedirectURL string `yaml:"redirect_url" json:"redirect_url" koanf:"redirect_url" split_words:"true"`
ErrorRedirectURL string `yaml:"error_redirect_url" json:"error_redirect_url" koanf:"error_redirect_url" split_words:"true"`
AllowedRedirectURLS []string `yaml:"allowed_redirect_urls" json:"allowed_redirect_urls" koanf:"allowed_redirect_urls" split_words:"true"`
AllowedRedirectURLMap map[string]glob.Glob
Providers ThirdPartyProviders `yaml:"providers" json:"providers,omitempty" koanf:"providers"`
RedirectURL string `yaml:"redirect_url" json:"redirect_url,omitempty" koanf:"redirect_url" split_words:"true"`
ErrorRedirectURL string `yaml:"error_redirect_url" json:"error_redirect_url,omitempty" koanf:"error_redirect_url" split_words:"true"`
AllowedRedirectURLS []string `yaml:"allowed_redirect_urls" json:"allowed_redirect_urls,omitempty" koanf:"allowed_redirect_urls" split_words:"true"`
AllowedRedirectURLMap map[string]glob.Glob `jsonschema:"-"`
}

func (t *ThirdParty) Validate() error {
Expand Down Expand Up @@ -566,9 +568,9 @@ func (p *ThirdPartyProvider) Validate() error {
}

type ThirdPartyProviders struct {
Google ThirdPartyProvider `yaml:"google" json:"google" koanf:"google"`
GitHub ThirdPartyProvider `yaml:"github" json:"github" koanf:"github"`
Apple ThirdPartyProvider `yaml:"apple" json:"apple" koanf:"apple"`
Google ThirdPartyProvider `yaml:"google" json:"google,omitempty" koanf:"google"`
GitHub ThirdPartyProvider `yaml:"github" json:"github,omitempty" koanf:"github"`
Apple ThirdPartyProvider `yaml:"apple" json:"apple,omitempty" koanf:"apple"`
}

func (p *ThirdPartyProviders) Validate() error {
Expand Down Expand Up @@ -618,10 +620,10 @@ func (c *Config) PostProcess() error {
}

type LoggerConfig struct {
LogHealthAndMetrics bool `yaml:"log_health_and_metrics" json:"log_health_and_metrics" koanf:"log_health_and_metrics"`
LogHealthAndMetrics bool `yaml:"log_health_and_metrics,omitempty" json:"log_health_and_metrics" koanf:"log_health_and_metrics" jsonschema:"default=true"`
}

type Account struct {
// Allow Deletion indicates if a user can perform self-service deletion
AllowDeletion bool `yaml:"allow_deletion" json:"allow_deletion" koanf:"allow_deletion"`
AllowDeletion bool `yaml:"allow_deletion" json:"allow_deletion,omitempty" koanf:"allow_deletion" jsonschema:"default=false"`
}
Loading

0 comments on commit 223cf9d

Please sign in to comment.