-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
158 lines (128 loc) · 4 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package server
import (
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"reflect"
"strings"
"time"
"github.com/dgrijalva/jwt-go/v4"
"github.com/mitchellh/mapstructure"
log "github.com/sirupsen/logrus"
"github.com/netsoc/iam/pkg/email"
)
// base64ToBytesHookFunc returns a mapstructure.DecodeHookFunc which parses a []byte from a Base64 string
func base64ToBytesHookFunc() mapstructure.DecodeHookFunc {
return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
if f.Kind() != reflect.String || t.Kind() != reflect.Slice || t.Elem().Kind() != reflect.Uint8 {
return data, nil
}
return base64.StdEncoding.DecodeString(data.(string))
}
}
// stringToLogLevelHookFunc returns a mapstructure.DecodeHookFunc which parses a logrus Level from a string
func stringToLogLevelHookFunc() mapstructure.DecodeHookFunc {
return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
if f.Kind() != reflect.String || t != reflect.TypeOf(log.InfoLevel) {
return data, nil
}
var level log.Level
err := level.UnmarshalText([]byte(data.(string)))
return level, err
}
}
// ConfigDecoderOptions enables necessary mapstructure decode hook functions
func ConfigDecoderOptions(config *mapstructure.DecoderConfig) {
config.ErrorUnused = true
config.DecodeHook = mapstructure.ComposeDecodeHookFunc(
base64ToBytesHookFunc(),
config.DecodeHook,
stringToLogLevelHookFunc(),
)
}
type JWTConfig struct {
Key []byte `mapstructure:"key"`
KeyFile string `mapstructure:"key_file"`
Issuer string
LoginValidity time.Duration `mapstructure:"login_validity"`
EmailValidity time.Duration `mapstructure:"email_validity"`
}
type CleanupConfig struct {
Interval time.Duration
MaxAge time.Duration `mapstructure:"max_age"`
}
type MA1SDConfig struct {
HTTPAddress string `mapstructure:"http_address"`
BaseURL string `mapstructure:"base_url"`
Domain string
}
// Config defines iamd's configuration
type Config struct {
LogLevel log.Level `mapstructure:"log_level"`
PostgreSQL struct {
Host string
User string
Password string
PasswordFile string `mapstructure:"password_file"`
Database string
TimeZone string
DSNExtra string `mapstructure:"dsn_extra"`
SoftDelete bool `mapstructure:"soft_delete"`
}
Mail email.Config
SMTP email.SMTPConfig
HTTP struct {
ListenAddress string `mapstructure:"listen_address"`
CORS struct {
AllowedOrigins []string `mapstructure:"allowed_origins"`
}
}
JWT JWTConfig
RootPassword string `mapstructure:"root_password"`
RootPasswordFile string `mapstructure:"root_password_file"`
ReservedUsernames []string `mapstructure:"reserved_usernames"`
Cleanup CleanupConfig
MA1SD MA1SDConfig
}
// ReadSecrets loads values for secret config options from files
func (c *Config) ReadSecrets() error {
if c.PostgreSQL.PasswordFile != "" {
pw, err := ioutil.ReadFile(c.PostgreSQL.PasswordFile)
if err != nil {
return fmt.Errorf("failed to read PostgreSQL password file: %w", err)
}
c.PostgreSQL.Password = strings.TrimSpace(string(pw))
}
if c.SMTP.PasswordFile != "" {
pw, err := ioutil.ReadFile(c.SMTP.PasswordFile)
if err != nil {
return fmt.Errorf("failed to read SMTP password file: %w", err)
}
c.SMTP.Password = strings.TrimSpace(string(pw))
}
if c.JWT.KeyFile != "" {
var err error
c.JWT.Key, err = ioutil.ReadFile(c.JWT.KeyFile)
if err != nil {
return fmt.Errorf("failed to read JWT key file: %w", err)
}
}
if len(c.JWT.Key) < 32 {
return errors.New("JWT secret must be at least 32 bytes")
}
if c.RootPasswordFile != "" {
pw, err := ioutil.ReadFile(c.RootPasswordFile)
if err != nil {
return fmt.Errorf("failed to read root password file: %w", err)
}
c.RootPassword = strings.TrimSpace(string(pw))
}
return nil
}
// JWTKeyFunc returns a function that will return the JWT key (for use with `jwt` package)
func (c *Config) JWTKeyFunc() jwt.Keyfunc {
return func(t *jwt.Token) (interface{}, error) {
return c.JWT.Key, nil
}
}