feat: bump configuration schema to 0.0.1-rc.2
All checks were successful
continuous-integration/drone/push Build is passing

this entails a couple of breaking changes due to schema evolution. once
the schema is stabilised, backward compatibility promise will be given.

* update config struct and accompanying scructs
* update tests
* update exampleConfig.dhall
* update local dev environment (devenv)
* make settings reflect the config schema changes
* make use of some settings/config updates
This commit is contained in:
leo 2023-05-21 12:44:18 +02:00
parent 7b5366daa4
commit 9eb811169d
Signed by: wanderer
SSH Key Fingerprint: SHA256:Dp8+iwKHSlrMEHzE3bJnPng70I7LEsa3IJXRH/U+idQ
10 changed files with 446 additions and 72 deletions

@ -4,13 +4,16 @@
package app package app
import ( import (
"encoding/hex"
"net/http" "net/http"
"github.com/gorilla/sessions" "github.com/gorilla/sessions"
"github.com/labstack/echo-contrib/session" "github.com/labstack/echo-contrib/session"
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4/middleware"
"golang.org/x/time/rate"
) )
// SetEchoSettings sets up the main Echo instance and panics on err.
func (a *App) SetEchoSettings() { func (a *App) SetEchoSettings() {
e := a.E() e := a.E()
@ -40,8 +43,13 @@ func (a *App) SetEchoSettings() {
// }, // },
// })) // }))
// TODO: have this in the config. if a.setting.HTTPRateLimitEnabled() {
e.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(20))) limit := rate.Limit(a.setting.HTTPRateLimit())
e.Use(middleware.RateLimiter(
middleware.NewRateLimiterMemoryStore(limit),
))
}
// TODO: add check for prometheus config setting. // TODO: add check for prometheus config setting.
// if true { // if true {
@ -52,11 +60,59 @@ func (a *App) SetEchoSettings() {
e.Use(middleware.Recover()) e.Use(middleware.Recover())
e.Use(session.Middleware( var (
sessions.NewCookieStore( store *sessions.CookieStore
[]byte(a.setting.SessionCookieSecret()), authSecret []byte
), encrSecret []byte
)) )
if a.setting.SessionAuthIsHex {
b, err := hex.DecodeString(a.setting.SessionCookieAuthSecret())
if err != nil {
panic(err)
}
authSecret = b
}
if a.setting.SessionEncrIsHex {
b, err := hex.DecodeString(a.setting.SessionCookieEncrSecret())
if err != nil {
panic(err)
}
encrSecret = b
}
switch {
case authSecret != nil && encrSecret != nil:
store = sessions.NewCookieStore(
authSecret,
encrSecret,
)
case authSecret != nil && encrSecret == nil:
store = sessions.NewCookieStore(
authSecret,
[]byte(a.setting.SessionCookieEncrSecret()),
)
case authSecret == nil && encrSecret != nil:
store = sessions.NewCookieStore(
[]byte(a.setting.SessionCookieAuthSecret()),
encrSecret,
)
case authSecret == nil && encrSecret == nil:
store = sessions.NewCookieStore(
[]byte(a.setting.SessionCookieAuthSecret()),
[]byte(a.setting.SessionCookieEncrSecret()),
)
}
store.Options.Domain = a.setting.HTTPDomain()
store.Options.HttpOnly = true
store.Options.SameSite = http.SameSiteStrictMode
store.Options.Secure = a.setting.HTTPSecure()
e.Use(session.Middleware(store))
// e.Use(middleware.CSRF()) // e.Use(middleware.CSRF())
e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{ e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{
@ -70,4 +126,10 @@ func (a *App) SetEchoSettings() {
) )
e.Use(middleware.Secure()) e.Use(middleware.Secure())
if a.setting.HTTPGzipEnabled() {
e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
Level: a.setting.HTTPGzipLevel(),
}))
}
} }

@ -21,15 +21,18 @@ const connstr = "file:ent_tests?mode=memory&_fk=1"
var conf = &config.Config{ var conf = &config.Config{
Port: 3005, Port: 3005,
AppName: "pcmt-test",
LiveMode: true, LiveMode: true,
DevelMode: false, DevelMode: false,
Session: struct { Session: struct {
CookieName string CookieName string
CookieSecret string CookieAuthSecret string
CookieEncrSecret string
MaxAge int
}{ }{
CookieName: "sessionz", CookieName: "sessionz",
CookieSecret: "secret", CookieAuthSecret: "c50429df4c74c7d23652171460c1209d529815caf101c164e90a0ed20e6857411c43f721f0d7ab85842e7dc827475f451e85f104092ed69f3463d9498bb6f8a3",
CookieEncrSecret: "5fa29053a2a6cd2b8aae686f768e6bd52c78de82fba64e94d3e0427ec3258320",
MaxAge: 0,
}, },
} }

@ -14,11 +14,21 @@ import (
type Settings struct { type Settings struct {
host string host string
port int port int
appName string appPath string
httpDomain string
httpSecure bool
httpGzipEnabled bool
httpGzipLevel int
httpRateLimitEnabled bool
httpRateLimit int
isLive bool isLive bool
isDevel bool isDevel bool
loggerJSON bool
sessionCookieName string sessionCookieName string
sessionCookieSecret string sessionCookieAuthSecret string
sessionCookieEncrSecret string
SessionAuthIsHex bool
SessionEncrIsHex bool
assetsPath string assetsPath string
templatesPath string templatesPath string
version string version string
@ -27,12 +37,16 @@ type Settings struct {
dbIsSetUp bool dbIsSetUp bool
} }
const appName = "pcmt"
// cleantgt is a list of ENV vars pertaining to pcmt. // cleantgt is a list of ENV vars pertaining to pcmt.
var cleantgt = []string{ var cleantgt = []string{
"PCMT_LIVE", "PCMT_LIVE",
"PCMT_DEVEL", "PCMT_DEVEL",
"PCMT_CONNSTRING", "PCMT_CONNSTRING",
"PCMT_DBTYPE", "PCMT_DBTYPE",
"PCMT_SESSION_AUTH_SECRET",
"PCMT_SESSION_ENCR_SECRET",
} }
// New returns a new instance of the settings struct. // New returns a new instance of the settings struct.
@ -55,11 +69,36 @@ func (s *Settings) Consolidate(conf *config.Config, host *string, port *int, dev
s.SetHost(conf.Host) s.SetHost(conf.Host)
s.SetPort(conf.Port) s.SetPort(conf.Port)
s.SetAppName(conf.AppName) s.SetAppPath(conf.AppPath)
s.SetIsLive(conf.LiveMode) s.SetIsLive(conf.LiveMode)
s.SetIsDevel(conf.DevelMode) s.SetIsDevel(conf.DevelMode)
s.SetLoggerIsJSON(conf.Logger.JSON)
s.SetSessionCookieName(conf.Session.CookieName) s.SetSessionCookieName(conf.Session.CookieName)
s.SetSessionCookieSecret(conf.Session.CookieSecret) s.SetSessionCookieAuthSecret(conf.Session.CookieAuthSecret)
s.SetSessionCookieEncrSecret(conf.Session.CookieEncrSecret)
authHex, encrHex := conf.SessionSecretsAreHex()
if authHex {
s.SessionAuthIsHex = true
}
if encrHex {
s.SessionEncrIsHex = true
}
s.SetHTTPDomain(conf.HTTP.Domain)
s.SetHTTPSecure(conf.HTTP.Secure)
if conf.HTTP.Gzip > 0 {
s.SetHTTPGzipEnabled(true)
s.SetHTTPGzipLevel(conf.HTTP.Gzip)
}
if conf.HTTP.RateLimit > 0 {
s.SetHTTPRateLimitEnabled(true)
s.SetHTTPRateLimit(conf.HTTP.RateLimit)
}
log.Debug("checking flag overrides") log.Debug("checking flag overrides")
@ -101,7 +140,12 @@ func (s *Settings) Port() int {
// AppName returns the appName. // AppName returns the appName.
func (s *Settings) AppName() string { func (s *Settings) AppName() string {
return s.appName return appName
}
// AppPath returns the appPath.
func (s *Settings) AppPath() string {
return s.appPath
} }
// IsLive returns the value of isLive of the receiver. // IsLive returns the value of isLive of the receiver.
@ -114,14 +158,54 @@ func (s *Settings) IsDevel() bool {
return s.isDevel return s.isDevel
} }
// LoggerIsJSON returns whether the logger should use the JSON handler.
func (s *Settings) LoggerIsJSON() bool {
return s.loggerJSON
}
// SessionCookieName returns the sessionCookieName. // SessionCookieName returns the sessionCookieName.
func (s *Settings) SessionCookieName() string { func (s *Settings) SessionCookieName() string {
return s.sessionCookieName return s.sessionCookieName
} }
// SessionCookieSecret returns the sessionCookieSecret. // SessionCookieAuthSecret returns the sessionCookieAuthSecret.
func (s *Settings) SessionCookieSecret() string { func (s *Settings) SessionCookieAuthSecret() string {
return s.sessionCookieSecret return s.sessionCookieAuthSecret
}
// SessionCookieEncrSecret returns the sessionCookieEncrSecret.
func (s *Settings) SessionCookieEncrSecret() string {
return s.sessionCookieEncrSecret
}
// HTTPDomain returns the httpDomain.
func (s *Settings) HTTPDomain() string {
return s.httpDomain
}
// HTTPSecure returns the httpSecure.
func (s *Settings) HTTPSecure() bool {
return s.httpSecure
}
// HTTPGzipEnabled returns the httpGzipEnabled variable.
func (s *Settings) HTTPGzipEnabled() bool {
return s.httpGzipEnabled
}
// HTTPGzipLevel returns the httpGzipLevel.
func (s *Settings) HTTPGzipLevel() int {
return s.httpGzipLevel
}
// HTTPRateLimitEnabled returns the httpRateLimitEnabled variable.
func (s *Settings) HTTPRateLimitEnabled() bool {
return s.httpRateLimitEnabled
}
// HTTPRateLimit returns the httpRateLimit.
func (s *Settings) HTTPRateLimit() int {
return s.httpRateLimit
} }
// AssetsPath returns the assetsPath. // AssetsPath returns the assetsPath.
@ -164,9 +248,9 @@ func (s *Settings) SetPort(port int) {
s.port = port s.port = port
} }
// SetAppName sets the appName. // SetAppPath sets the appPath.
func (s *Settings) SetAppName(appName string) { func (s *Settings) SetAppPath(appPath string) {
s.appName = appName s.appPath = appPath
} }
// SetIsLive sets the value of isLive of the receiver. // SetIsLive sets the value of isLive of the receiver.
@ -179,14 +263,54 @@ func (s *Settings) SetIsDevel(devel bool) {
s.isDevel = devel s.isDevel = devel
} }
// SetLoggerIsJSON sets the setting value of loggerIsJSON.
func (s *Settings) SetLoggerIsJSON(isJSON bool) {
s.loggerJSON = isJSON
}
// SetSessionCookieName sets the sessionCookieName. // SetSessionCookieName sets the sessionCookieName.
func (s *Settings) SetSessionCookieName(sessionCookieName string) { func (s *Settings) SetSessionCookieName(sessionCookieName string) {
s.sessionCookieName = sessionCookieName s.sessionCookieName = sessionCookieName
} }
// SetSessionCookieSecret sets the sessionCookieSecret. // SetSessionCookieAuthSecret sets the sessionCookieAuthSecret.
func (s *Settings) SetSessionCookieSecret(sessionCookieSecret string) { func (s *Settings) SetSessionCookieAuthSecret(sessionCookieAuthSecret string) {
s.sessionCookieSecret = sessionCookieSecret s.sessionCookieAuthSecret = sessionCookieAuthSecret
}
// SetSessionCookieEncrSecret sets the sessionCookieEncrSecret.
func (s *Settings) SetSessionCookieEncrSecret(sessionCookieEncrSecret string) {
s.sessionCookieEncrSecret = sessionCookieEncrSecret
}
// SetHTTPDomain sets the httpDomain.
func (s *Settings) SetHTTPDomain(domain string) {
s.httpDomain = domain
}
// SetHTTPSecure sets the httpSecure.
func (s *Settings) SetHTTPSecure(secure bool) {
s.httpSecure = secure
}
// SetHTTPGzipEnabled sets the httpGzipEnabled variable.
func (s *Settings) SetHTTPGzipEnabled(enabled bool) {
s.httpGzipEnabled = enabled
}
// SetHTTPGzipLevel sets the httpGzipLevel.
func (s *Settings) SetHTTPGzipLevel(level int) {
s.httpGzipLevel = level
}
// SetHTTPRateLimitEnabled sets the httpRateLimitEnabled variable.
func (s *Settings) SetHTTPRateLimitEnabled(enabled bool) {
s.httpRateLimitEnabled = enabled
}
// SetHTTPRateLimit sets the httpRateLimit.
func (s *Settings) SetHTTPRateLimit(rateLimit int) {
s.httpRateLimit = rateLimit
} }
// SetAssetsPath sets the assetsPath. // SetAssetsPath sets the assetsPath.

@ -17,26 +17,89 @@ import (
type session struct { type session struct {
CookieName string CookieName string
CookieSecret string // CookieAuthSecret is the key used for signing and authentication.
CookieAuthSecret string
// CookieEncrSecret is the key used for encrypting.
CookieEncrSecret string
MaxAge int
} }
type httpRec struct {
// Secure denotes whether the HTTP should use TLS (i.e. HTTPS).
Secure bool
Domain string
AutoTLS bool
TLSCertKeyPath string
TLSKeyPath string
ContentSecurityPolicy string
// HSTSMaxAge sets the strict transport security duration, zero mean it's not set.
HSTSMaxAge int
// Gzip is the level of gzip compression, 0 means do not enable gzip.
Gzip int
// RateLimit controls the number of requests per second, 0 means no limit.
RateLimit int
// Timount controls connection timeout in seconds, 0 means no limit.
Timeout int
}
type mailer struct {
Enabled bool
EnableHELO bool
ForceTrustServerCert bool
Protocol string
SMTPPort int
SendPlainText bool
SubjectPrefix string
}
type initialiser struct {
AdminPassword string
CreateAdmin bool
}
// Config represents the Dhall configuration schema,
// https://git.dotya.ml/mirre-mt/pcmt-config-schema/ for reference.
type Config struct { type Config struct {
AppPath string
Host string Host string
Port int Port int
AppName string HTTP httpRec
LiveMode bool LiveMode bool
DevelMode bool DevelMode bool
Session session Session session
Registration struct{ Allowed bool } Registration struct{ Allowed bool }
Logger struct { Logger struct {
Json bool //nolint:revive JSON bool
Fmt string Fmt string
} }
Init initialiser
// Mailer is currently a noop.
Mailer mailer
} }
const schemaCompatibility = "0.0.0" //nolint:unused const (
schemaCompatibility = "0.0.1-rc.2"
var log slogging.Slogger // authKeySize is the session cookie auth key length in bytes.
authKeySize = 64
// encrKeySize is the session cookie encryption key length in bytes.
encrKeySize = 32
)
var (
log slogging.Slogger
errSessionAuthSecretWrongSize = fmt.Errorf("session cookie authentication secret should be *exactly* 64 bytes long, both raw and hex-encoded strings are accepted; make sure to generate the key with sufficient entropy e.g. using openssl")
errSessionEncrSecretWrongSize = fmt.Errorf("session cookie encryption secret should be *exactly* 32 bytes (for 256 bit AES), both raw and hex-encoded strings are accepted; make sure to generate the key with sufficient entropy e.g. using openssl")
errSessionSecretZeros = fmt.Errorf("session cookie secrets cannot be all zeros")
// authSecretIsHex is used to recall whether the authentication secret was
// determined to be pure hex.
authSecretIsHex bool
// authSecretIsHex is used to recall whether the encryption secret was
// determined to be pure hex.
encrSecretIsHex bool
)
func Load(conf string, isPath bool) (*Config, error) { func Load(conf string, isPath bool) (*Config, error) {
var config Config var config Config
@ -56,6 +119,8 @@ func Load(conf string, isPath bool) (*Config, error) {
slog.Group("pcmt extra", slog.String("module", "config")), slog.Group("pcmt extra", slog.String("module", "config")),
) )
log.Debugf("schema compatibility: '%s'", schemaCompatibility)
switch { switch {
case isPath: case isPath:
log.Debug("config from file") log.Debug("config from file")
@ -67,7 +132,7 @@ func Load(conf string, isPath bool) (*Config, error) {
err = dhall.Unmarshal([]byte(conf), &config) err = dhall.Unmarshal([]byte(conf), &config)
} }
if !config.Logger.Json { if !config.Logger.JSON {
slogger = slogging.Init(false) slogger = slogging.Init(false)
log.Logger = slogger.Logger.With( log.Logger = slogger.Logger.With(
slog.Group("pcmt extra", slog.String("module", "config")), slog.Group("pcmt extra", slog.String("module", "config")),
@ -104,9 +169,72 @@ func Load(conf string, isPath bool) (*Config, error) {
return nil, err return nil, err
} }
// make sure the secrets meet *basic* requirements for consumption.
// NOTE: this func does not prevent the user from using dumb but correctly
// sized keys (such as 32 bytes of 0x01...). secrets are checked if they
// are not all zero bytes, though.
if err = checkSessionSecretsLen(&config); err != nil {
return nil, err
}
return &config, nil return &config, nil
} }
func (c *Config) SessionSecretsAreHex() (bool, bool) {
return authSecretIsHex, encrSecretIsHex
}
func checkSessionSecretsLen(conf *Config) error {
auth := conf.Session.CookieAuthSecret
encr := conf.Session.CookieEncrSecret
log.Debugf("auth len bytes: %d", len([]byte(auth)))
log.Debugf("encr len bytes: %d", len([]byte(encr)))
switch {
case (len([]byte(auth)) != authKeySize) && (isHex(auth) && len([]byte(auth)) != 2*authKeySize):
return errSessionAuthSecretWrongSize
case (len([]byte(encr)) != encrKeySize) && (isHex(encr) && len([]byte(encr)) != 2*encrKeySize):
return errSessionEncrSecretWrongSize
case isAllZeros([]byte(auth)) || isAllZeros([]byte(encr)):
return errSessionSecretZeros
case isHex(auth):
authSecretIsHex = true
fallthrough
case isHex(encr):
encrSecretIsHex = true
}
return nil
}
func isAllZeros(b []byte) bool {
for _, v := range b {
if v != 0 {
return false
}
}
return true
}
// isHex checks if the string is a hex string with even number of bytes.
func isHex(s string) bool {
bs := []byte(s)
for _, b := range bs {
if !(b >= '0' && b <= '9' || b >= 'a' && b <= 'f' || b >= 'A' && b <= 'F') {
return false
}
}
return true
}
func prettyPrintConfig(conf string, isPath bool) error { func prettyPrintConfig(conf string, isPath bool) error {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel() defer cancel()

@ -12,6 +12,8 @@ import (
func TestConfig(t *testing.T) { func TestConfig(t *testing.T) {
if os.Getenv("CI") == "true" { if os.Getenv("CI") == "true" {
// the reason for skipping is initial normalisation can take a minute
// and waiting that long for every test is not really feasible.
t.Skip("we're running in CI apparently, skipping these tests") t.Skip("we're running in CI apparently, skipping these tests")
} }
@ -41,13 +43,23 @@ func TestConfig(t *testing.T) {
isPath: false, isPath: false,
conf: ` conf: `
let ConfigSchema = let ConfigSchema =
https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
sha256:c82b0904c261d442e5765c2f47d76ad53c3c3ed16ace1b33416cedf98f2f5df0 sha256:9082079ea4d41cc290c879a6a7e2034a2914949c30c337975cc5c6fecfc0da50
? https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall ? https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
let Config = ConfigSchema.Schema let Config = ConfigSchema.Schema
let c = Config::{ DevelMode = True } let c =
Config::{
, DevelMode = True
, Session =
ConfigSchema.Schema.default.Session
// { CookieAuthSecret =
"c50429df4c74c7d23652171460c1209d529815caf101c164e90a0ed20e6857411c43f721f0d7ab85842e7dc827475f451e85f104092ed69f3463d9498bb6f8a3"
, CookieEncrSecret =
"5fa29053a2a6cd2b8aae686f768e6bd52c78de82fba64e94d3e0427ec3258320"
}
}
in c in c
`, `,
@ -59,9 +71,9 @@ func TestConfig(t *testing.T) {
isPath: false, isPath: false,
conf: ` conf: `
let ConfigSchema = let ConfigSchema =
https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
sha256:c82b0904c261d442e5765c2f47d76ad53c3c3ed16ace1b33416cedf98f2f5df0 sha256:9082079ea4d41cc290c879a6a7e2034a2914949c30c337975cc5c6fecfc0da50
? https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall ? https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
let Config = ConfigSchema.Schema let Config = ConfigSchema.Schema
@ -74,9 +86,19 @@ func TestConfig(t *testing.T) {
isPath: false, isPath: false,
conf: ` conf: `
let ConfigSchema = let ConfigSchema =
https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
sha256:c82b0904c261d442e5765c2f47d76ad53c3c3ed16ace1b33416cedf98f2f5df0 sha256:9082079ea4d41cc290c879a6a7e2034a2914949c30c337975cc5c6fecfc0da50
in ConfigSchema.Schema::{ DevelMode = True, Port = 5555 } in ConfigSchema.Schema::{
, DevelMode = True
, Port = 5555
, Session =
ConfigSchema.Schema.default.Session
// { CookieAuthSecret =
"c50429df4c74c7d23652171460c1209d529815caf101c164e90a0ed20e6857411c43f721f0d7ab85842e7dc827475f451e85f104092ed69f3463d9498bb6f8a3"
, CookieEncrSecret =
"5fa29053a2a6cd2b8aae686f768e6bd52c78de82fba64e94d3e0427ec3258320"
}
}
`, `,
}, },
{ {
@ -85,9 +107,19 @@ func TestConfig(t *testing.T) {
isPath: false, isPath: false,
conf: ` conf: `
let ConfigSchema = let ConfigSchema =
https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
sha256:c82b0904c261d442e5765c2f47d76ad53c3c3ed16ace1b33416cedf98f2f5df0 sha256:9082079ea4d41cc290c879a6a7e2034a2914949c30c337975cc5c6fecfc0da50
in ConfigSchema.Schema.default // { DevelMode = True }
in ConfigSchema.Schema.default
// { DevelMode = True
, Session =
ConfigSchema.Schema.default.Session
// { CookieAuthSecret =
"c50429df4c74c7d23652171460c1209d529815caf101c164e90a0ed20e6857411c43f721f0d7ab85842e7dc827475f451e85f104092ed69f3463d9498bb6f8a3"
, CookieEncrSecret =
"5fa29053a2a6cd2b8aae686f768e6bd52c78de82fba64e94d3e0427ec3258320"
}
}
`, `,
}, },
} }

@ -1,7 +1,7 @@
let ConfigSchema = let ConfigSchema =
https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
sha256:c82b0904c261d442e5765c2f47d76ad53c3c3ed16ace1b33416cedf98f2f5df0 sha256:9082079ea4d41cc290c879a6a7e2034a2914949c30c337975cc5c6fecfc0da50
? https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall ? https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
let Config = ConfigSchema.Schema let Config = ConfigSchema.Schema

@ -1,10 +1,20 @@
let ConfigSchema = let ConfigSchema =
https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
sha256:c82b0904c261d442e5765c2f47d76ad53c3c3ed16ace1b33416cedf98f2f5df0 sha256:9082079ea4d41cc290c879a6a7e2034a2914949c30c337975cc5c6fecfc0da50
? https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall ? https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
let Config = ConfigSchema.Schema let Config = ConfigSchema.Schema
let c = Config::{ Host = "localhost" } let c =
Config::{
, Host = "localhost"
, Session =
ConfigSchema.Schema.default.Session
// { CookieAuthSecret =
"c50429df4c74c7d23652171460c1209d529815caf101c164e90a0ed20e6857411c43f721f0d7ab85842e7dc827475f451e85f104092ed69f3463d9498bb6f8a3"
, CookieEncrSecret =
"5fa29053a2a6cd2b8aae686f768e6bd52c78de82fba64e94d3e0427ec3258320"
}
}
in c in c

@ -4,6 +4,8 @@
env.CGO_ENABLED = 0; env.CGO_ENABLED = 0;
env.PCMT_DBTYPE = "postgres"; env.PCMT_DBTYPE = "postgres";
env.PCMT_CONNSTRING = "host=127.0.0.1 sslmode=disable port=5432 user=postgres dbname=postgres password=postgres"; env.PCMT_CONNSTRING = "host=127.0.0.1 sslmode=disable port=5432 user=postgres dbname=postgres password=postgres";
env.PCMT_SESSION_AUTH_SECRET = "c43fb09c24a35f71a37e755f031b31aa733a44e6d07a4d7086c0aefe080ad6817d92ffe8cc12df0fce67938c6f42ffa0a6cefdbfb1d23b04d32ee4e2615ae118";
env.PCMT_SESSION_ENCR_SECRET = "a222d20971aafde2aa5cb4d52c31f5761a0649e0d308a0713ad88022805b92db";
packages = with pkgs; [ packages = with pkgs; [
git git

@ -1,8 +1,8 @@
{- import config schema that is integrity-check protected (with a fallback) -} {- import config schema that is integrity-check protected (with a fallback) -}
let ConfigSchema = let ConfigSchema =
https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
sha256:c82b0904c261d442e5765c2f47d76ad53c3c3ed16ace1b33416cedf98f2f5df0 sha256:9082079ea4d41cc290c879a6a7e2034a2914949c30c337975cc5c6fecfc0da50
? https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.0/package.dhall ? https://git.dotya.ml/mirre-mt/pcmt-config-schema/raw/tag/0.0.1-rc.2/package.dhall
let Config = ConfigSchema.Schema let Config = ConfigSchema.Schema
@ -12,6 +12,19 @@ let c =
, Host = env:PCMT_HOST as Text ? Config.default.Host , Host = env:PCMT_HOST as Text ? Config.default.Host
, LiveMode = env:PCMT_LIVE ? True , LiveMode = env:PCMT_LIVE ? True
, DevelMode = env:PCMT_DEVEL ? True , DevelMode = env:PCMT_DEVEL ? True
, Session =
Config.default.Session
// { CookieName = env:PCMT_SESSION_NAME as Text ? "pcmt_session"
, CookieAuthSecret =
env:PCMT_SESSION_AUTH_SECRET as Text
? Config.default.Session.CookieAuthSecret
, CookieEncrSecret =
env:PCMT_SESSION_ENCR_SECRET as Text
? Config.default.Session.CookieEncrSecret
}
, HTTP = Config.default.HTTP
, Mailer = Config.default.Mailer
, Init = Config.default.Init // { CreateAdmin = True }
} }
let _ = let _ =

2
go.mod

@ -15,6 +15,7 @@ require (
github.com/xiaoqidun/entps v0.0.0-20230328150929-94b1b92d8c03 github.com/xiaoqidun/entps v0.0.0-20230328150929-94b1b92d8c03
golang.org/x/crypto v0.6.0 golang.org/x/crypto v0.6.0
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
golang.org/x/time v0.3.0
) )
require ( require (
@ -45,7 +46,6 @@ require (
golang.org/x/net v0.9.0 // indirect golang.org/x/net v0.9.0 // indirect
golang.org/x/sys v0.7.0 // indirect golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.6.1-0.20230222164832-25d2519c8696 // indirect golang.org/x/tools v0.6.1-0.20230222164832-25d2519c8696 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
lukechampine.com/uint128 v1.2.0 // indirect lukechampine.com/uint128 v1.2.0 // indirect