-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.go
243 lines (212 loc) · 10.5 KB
/
main.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
package main
import (
"flag"
"os"
"strings"
jwt "github.com/dgrijalva/jwt-go"
utils "github.com/flaviostutz/go-utils"
"github.com/jinzhu/gorm"
"github.com/sirupsen/logrus"
)
type options struct {
logLevel string
dbDialect string
dbHost string
dbPort int
dbUsername string
dbPassword string
dbName string
dbSqliteFile string
corsAllowedOrigins string
accessTokenDefaultExpirationMinutes int
refreshTokenDefaultExpirationMinutes int
validationTokenExpirationMinutes int
passwordResetTokenExpirationMinutes int
accessTokenDefaultScope string
jwtIssuer string
jwtSigningMethod string
jwtSigningKeyFile string
jwtPublicKey interface{}
jwtPrivateKey interface{}
masterPublicKeyFile string
passwordRetriesMax int
passwordRetriesTimeSeconds int
passwordExpirationDays int
accountActivationMethod string
passwordValidationRegex string
mailSMTPHost string
mailSMTPPort int
mailSMTPUser string
mailSMTPPass string
mailFromAddress string
mailFromName string
mailActivationSubject string
mailActivationHTMLBody string
mailResetPasswordSubject string
mailResetPasswordHTMLBody string
mailTokensTests string
googleClientID string
googleClientSecret string
facebookClientID string
facebookClientSecret string
}
var (
opt options
db *gorm.DB
)
func main() {
logLevel := flag.String("loglevel", "debug", "debug, info, warning, error")
dbDialect0 := flag.String("db-dialect", "mysql", "Database dialect to use. One of mysql, postgres, sqlite or mssql")
dbHost0 := flag.String("db-host", "", "Database host address")
dbPort0 := flag.Int("db-port", 0, "Database port")
dbUsername0 := flag.String("db-username", "userme", "Database username")
dbPassword0 := flag.String("db-password", "", "Database password")
dbName0 := flag.String("db-name", "userme", "Database name")
dbSqliteFile0 := flag.String("db-sqlite-file", "/data/userme.db", "SQLite file path location")
corsAllowedOrigins0 := flag.String("cors-allowed-origins", "*", "Cors allowed origins for this server")
accessTokenDefaultExpirationMinutes0 := flag.Int("accesstoken-expiration-minutes", 480, "Default access token expiration age")
refreshTokenDefaultExpirationMinutes0 := flag.Int("refreshtoken-expiration-minutes", 40320, "Default refresh token expiration age")
validationTokenExpirationMinutes0 := flag.Int("validationtoken-expiration-minutes", 20, "Validation token expiration age (sent to email)")
passwordResetTokenExpirationMinutes0 := flag.Int("passwordresettoken-expiration-minutes", 20, "Password reset token expiration age (sent to email)")
accessTokenDefaultScope0 := flag.String("accesstoken-default-scope", "basic", "Default claim (scope) added to all access tokens")
passwordRetriesMax0 := flag.Int("password-retries-max", 5, "Max number of incorrect password retries")
passwordRetriesTimeSeconds0 := flag.Int("password-retries-time", 5, "Max number of incorrect password retries")
passwordExpirationDays0 := flag.Int("password-expiration-days", -1, "Password expiration time. This will force a password change. -1 means no expiration")
accountActivationMethod0 := flag.String("account-activation-method", "direct", "Activation method for new accounts. One of 'direct' (no additional steps needed) or 'mail' (send e-mail with activation link to user)")
passwordValidationRegex0 := flag.String("password-validation-regex", "^.{6,30}$", "Password validation regex. Defaults to '^.{6,30}$'")
mailFromName0 := flag.String("mail-from-name", "", "Mail from name on mail notifications. Used as JWT Issuer field too. required")
jwtSigningMethod0 := flag.String("jwt-signing-method", "", "JWT signing method. required")
jwtSigningKeyFile0 := flag.String("jwt-signing-key-file", "", "Key file used to sign tokens. Tokens may be later validated by thirdy parties by checking the signature with related public key when usign assymetric keys")
masterPublicKeyFile0 := flag.String("master-public-key-file", "", "Public key file used to sign special master tokens that can be used to perform special operations on userme.")
mailSMTPHost0 := flag.String("mail-smtp-host", "", "Mail smtp host")
mailSMTPPort0 := flag.Int("mail-smtp-port", 0, "Mail smtp port")
mailSMTPUser0 := flag.String("mail-smtp-username", "", "Mail smtp username")
mailSMTPPass0 := flag.String("mail-smtp-password", "", "Mail smtp password")
mailFromAddress0 := flag.String("mail-from-address", "", "Mail from address")
mailActivationSubject0 := flag.String("mail-activation-subject", "", "Mail activation subject")
mailActivationHTML0 := flag.String("mail-activation-html", "", "Mail activation html body. Use placeholders EMAIL, DISPLAY_NAME and ACTIVATION_TOKEN as templating")
mailResetPasswordSubject0 := flag.String("mail-password-reset-subject", "", "Mail password reset subject")
mailResetPasswordHTML0 := flag.String("mail-password-reset-html", "", "Mail password reset html body. Use placeholders EMAIL, DISPLAY_NAME and ACTIVATION_TOKEN as templating")
mailTokensTests0 := flag.String("mail-tokens-tests", "", "Send mail tokens to response headers. Useful for testing enviroments. NEVER use this in production as this makes second factor (e-mail) invalid for our application.")
facebookClientID0 := flag.String("facebook-client-id", "", "Facebook Application Client ID")
facebookClientSecret0 := flag.String("facebook-client-secret", "", "Facebook Application Client Secret")
googleClientID0 := flag.String("google-client-id", "", "Google Application Client ID")
googleClientSecret0 := flag.String("google-client-secret", "", "Google Application Client Secret")
flag.Parse()
switch *logLevel {
case "debug":
logrus.SetLevel(logrus.DebugLevel)
break
case "warning":
logrus.SetLevel(logrus.WarnLevel)
break
case "error":
logrus.SetLevel(logrus.ErrorLevel)
break
default:
logrus.SetLevel(logrus.InfoLevel)
}
opt = options{
logLevel: *logLevel,
dbDialect: *dbDialect0,
dbHost: *dbHost0,
dbPort: *dbPort0,
dbUsername: *dbUsername0,
dbPassword: *dbPassword0,
dbName: *dbName0,
dbSqliteFile: *dbSqliteFile0,
corsAllowedOrigins: *corsAllowedOrigins0,
accessTokenDefaultExpirationMinutes: *accessTokenDefaultExpirationMinutes0,
refreshTokenDefaultExpirationMinutes: *refreshTokenDefaultExpirationMinutes0,
validationTokenExpirationMinutes: *validationTokenExpirationMinutes0,
passwordResetTokenExpirationMinutes: *passwordResetTokenExpirationMinutes0,
accessTokenDefaultScope: *accessTokenDefaultScope0,
mailFromName: *mailFromName0,
jwtSigningMethod: *jwtSigningMethod0,
jwtSigningKeyFile: *jwtSigningKeyFile0,
masterPublicKeyFile: *masterPublicKeyFile0,
passwordRetriesMax: *passwordRetriesMax0,
passwordRetriesTimeSeconds: *passwordRetriesTimeSeconds0,
accountActivationMethod: *accountActivationMethod0,
passwordValidationRegex: *passwordValidationRegex0,
passwordExpirationDays: *passwordExpirationDays0,
mailSMTPHost: *mailSMTPHost0,
mailSMTPPort: *mailSMTPPort0,
mailSMTPUser: *mailSMTPUser0,
mailSMTPPass: *mailSMTPPass0,
mailFromAddress: *mailFromAddress0,
mailResetPasswordSubject: *mailResetPasswordSubject0,
mailResetPasswordHTMLBody: *mailResetPasswordHTML0,
mailActivationSubject: *mailActivationSubject0,
mailActivationHTMLBody: *mailActivationHTML0,
mailTokensTests: *mailTokensTests0,
googleClientID: *googleClientID0,
googleClientSecret: *googleClientSecret0,
facebookClientID: *facebookClientID0,
facebookClientSecret: *facebookClientSecret0,
}
if opt.dbDialect != "sqlite3" {
if opt.dbHost == "" || opt.dbPort == 0 || opt.dbName == "" || opt.dbUsername == "" || opt.dbPassword == "" {
logrus.Errorf("--db-host, --db-port, --db-name, --db-username and --db-password are all required non empty")
os.Exit(1)
}
}
if opt.mailSMTPHost == "" || opt.mailSMTPPort == 0 || opt.mailSMTPUser == "" || opt.mailSMTPPass == "" {
logrus.Errorf("--mail-smtp-host, --mail-smtp-port, --mail-smtp-username and --mail-smtp-password are required")
os.Exit(1)
}
if opt.mailFromName == "" || opt.mailFromAddress == "" || opt.mailResetPasswordSubject == "" || opt.mailResetPasswordHTMLBody == "" {
logrus.Errorf("--mail-from-name --mail-from-address, --mail-password-reset-subject and --mail-password-reset-html are required")
os.Exit(1)
}
if opt.accountActivationMethod == "mail" {
if opt.mailActivationSubject == "" || opt.mailActivationHTMLBody == "" {
logrus.Errorf("--mail-activation-subject and --mail-activation-html must be non empty when activation method is 'mail'")
os.Exit(1)
}
}
if opt.googleClientID == "" || opt.googleClientSecret == "" {
logrus.Warnf("Disabling Google login support. Google client id and secret were not defined.")
}
if opt.facebookClientID == "" || opt.facebookClientSecret == "" {
logrus.Warnf("Disabling Facebook login support. Facebook client id and secret were not defined.")
}
sm := jwt.GetSigningMethod(opt.jwtSigningMethod)
if sm == nil {
logrus.Errorf("Unsupported JWT signing method %s", opt.jwtSigningMethod)
os.Exit(1)
}
logrus.Infof("Loading JWT private signing key")
logrus.Debugf("JWT signing method: %s", opt.jwtSigningMethod)
if strings.HasPrefix(opt.jwtSigningMethod, "RS") || strings.HasPrefix(opt.jwtSigningMethod, "ES") || strings.HasPrefix(opt.jwtSigningMethod, "HS") {
privk, err := utils.ParseKeyFromPEM(opt.jwtSigningKeyFile, true)
if err != nil {
logrus.Errorf("Failed to parse PEM private key. err=%s", err)
os.Exit(1)
}
opt.jwtPrivateKey = privk
pubk, err := utils.ParseKeyFromPEM(opt.jwtSigningKeyFile, false)
if err != nil {
logrus.Errorf("Failed to parse PEM public key. err=%s", err)
os.Exit(1)
}
opt.jwtPublicKey = pubk
} else {
logrus.Errorf("Unsupported signing method %s", opt.jwtSigningMethod)
os.Exit(1)
}
logrus.Debugf("JWT key loaded")
opt.jwtIssuer = opt.mailFromName
db0, err0 := initDB()
if err0 != nil {
logrus.Warnf("Couldn't init database. err=%s", err0)
os.Exit(1)
}
db = db0
defer db.Close()
err := NewHTTPServer().Start()
if err != nil {
logrus.Warnf("Error starting server. err=%s", err)
os.Exit(1)
}
}