|
@@ -31,16 +31,42 @@ import (
|
31
|
31
|
"golang.org/x/crypto/bcrypt"
|
32
|
32
|
)
|
33
|
33
|
|
34
|
|
-// ACC [REGISTER|VERIFY] ...
|
|
34
|
+// ACC [LS|REGISTER|VERIFY] ...
|
35
|
35
|
func accHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
|
36
|
+ subcommand := strings.ToLower(msg.Params[0])
|
|
37
|
+
|
|
38
|
+ if subcommand == "ls" {
|
|
39
|
+ config := server.Config().Accounts
|
|
40
|
+
|
|
41
|
+ rb.Add(nil, server.name, "ACC", "LS", "SUBCOMMANDS", "LS REGISTER VERIFY")
|
|
42
|
+
|
|
43
|
+ var enabledCallbacks []string
|
|
44
|
+ for _, name := range config.Registration.EnabledCallbacks {
|
|
45
|
+ enabledCallbacks = append(enabledCallbacks, name)
|
|
46
|
+ }
|
|
47
|
+ sort.Strings(enabledCallbacks)
|
|
48
|
+ rb.Add(nil, server.name, "ACC", "LS", "CALLBACKS", strings.Join(enabledCallbacks, " "))
|
|
49
|
+
|
|
50
|
+ rb.Add(nil, server.name, "ACC", "LS", "CREDTYPES", "passphrase certfp")
|
|
51
|
+
|
|
52
|
+ if config.NickReservation.Enabled {
|
|
53
|
+ rb.Add(nil, server.name, "ACC", "LS", "FLAGS", "regnick")
|
|
54
|
+ }
|
|
55
|
+ return false
|
|
56
|
+ }
|
|
57
|
+
|
|
58
|
+ // disallow account stuff before connection registration has completed, for now
|
|
59
|
+ if !client.Registered() {
|
|
60
|
+ client.Send(nil, server.name, ERR_NOTREGISTERED, "*", client.t("You need to register before you can use that command"))
|
|
61
|
+ return false
|
|
62
|
+ }
|
|
63
|
+
|
36
|
64
|
// make sure reg is enabled
|
37
|
65
|
if !server.AccountConfig().Registration.Enabled {
|
38
|
|
- rb.Add(nil, server.name, ERR_REG_UNSPECIFIED_ERROR, client.nick, "*", client.t("Account registration is disabled"))
|
|
66
|
+ rb.Add(nil, server.name, "FAIL", "ACC", "REG_UNAVAILABLE", client.t("Account registration is disabled"))
|
39
|
67
|
return false
|
40
|
68
|
}
|
41
|
69
|
|
42
|
|
- subcommand := strings.ToLower(msg.Params[0])
|
43
|
|
-
|
44
|
70
|
if subcommand == "register" {
|
45
|
71
|
return accRegisterHandler(server, client, msg, rb)
|
46
|
72
|
} else if subcommand == "verify" {
|
|
@@ -61,7 +87,7 @@ func parseCallback(spec string, config *AccountConfig) (callbackNamespace string
|
61
|
87
|
callbackValues := strings.SplitN(callback, ":", 2)
|
62
|
88
|
callbackNamespace, callbackValue = callbackValues[0], callbackValues[1]
|
63
|
89
|
} else {
|
64
|
|
- // "the IRC server MAY choose to use mailto as a default"
|
|
90
|
+ // "If a callback namespace is not ... provided, the IRC server MUST use mailto""
|
65
|
91
|
callbackNamespace = "mailto"
|
66
|
92
|
callbackValue = callback
|
67
|
93
|
}
|
|
@@ -81,23 +107,35 @@ func parseCallback(spec string, config *AccountConfig) (callbackNamespace string
|
81
|
107
|
// ACC REGISTER <accountname> [callback_namespace:]<callback> [cred_type] :<credential>
|
82
|
108
|
func accRegisterHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
83
|
109
|
nick := client.Nick()
|
|
110
|
+
|
|
111
|
+ if len(msg.Params) < 4 {
|
|
112
|
+ rb.Add(nil, server.name, ERR_NEEDMOREPARAMS, nick, msg.Command, client.t("Not enough parameters"))
|
|
113
|
+ return false
|
|
114
|
+ }
|
|
115
|
+
|
|
116
|
+ account := strings.TrimSpace(msg.Params[1])
|
|
117
|
+
|
|
118
|
+ // check for account name of *
|
|
119
|
+ if account == "*" {
|
|
120
|
+ account = nick
|
|
121
|
+ } else {
|
|
122
|
+ if server.Config().Accounts.NickReservation.Enabled {
|
|
123
|
+ rb.Add(nil, server.name, "FAIL", "ACC", "REG_MUST_USE_REGNICK", account, client.t("Must register with current nickname instead of separate account name"))
|
|
124
|
+ return false
|
|
125
|
+ }
|
|
126
|
+ }
|
|
127
|
+
|
84
|
128
|
// clients can't reg new accounts if they're already logged in
|
85
|
129
|
if client.LoggedIntoAccount() {
|
86
|
|
- rb.Add(nil, server.name, ERR_REG_UNSPECIFIED_ERROR, nick, "*", client.t("You're already logged into an account"))
|
|
130
|
+ rb.Add(nil, server.name, "FAIL", "ACC", "REG_UNSPECIFIED_ERROR", account, client.t("You're already logged into an account"))
|
87
|
131
|
return false
|
88
|
132
|
}
|
89
|
133
|
|
90
|
|
- // get and sanitise account name
|
91
|
|
- account := strings.TrimSpace(msg.Params[1])
|
|
134
|
+ // sanitise account name
|
92
|
135
|
casefoldedAccount, err := CasefoldName(account)
|
93
|
136
|
// probably don't need explicit check for "*" here... but let's do it anyway just to make sure
|
94
|
137
|
if err != nil || msg.Params[1] == "*" {
|
95
|
|
- rb.Add(nil, server.name, ERR_REG_UNSPECIFIED_ERROR, nick, account, client.t("Account name is not valid"))
|
96
|
|
- return false
|
97
|
|
- }
|
98
|
|
-
|
99
|
|
- if len(msg.Params) < 4 {
|
100
|
|
- rb.Add(nil, server.name, ERR_NEEDMOREPARAMS, nick, msg.Command, client.t("Not enough parameters"))
|
|
138
|
+ rb.Add(nil, server.name, "FAIL", "ACC", "REG_INVALID_ACCOUNT_NAME", account, client.t("Account name is not valid"))
|
101
|
139
|
return false
|
102
|
140
|
}
|
103
|
141
|
|
|
@@ -105,7 +143,7 @@ func accRegisterHandler(server *Server, client *Client, msg ircmsg.IrcMessage, r
|
105
|
143
|
callbackNamespace, callbackValue := parseCallback(callbackSpec, server.AccountConfig())
|
106
|
144
|
|
107
|
145
|
if callbackNamespace == "" {
|
108
|
|
- rb.Add(nil, server.name, ERR_REG_INVALID_CALLBACK, nick, account, callbackSpec, client.t("Callback namespace is not supported"))
|
|
146
|
+ rb.Add(nil, server.name, "FAIL", "ACC", "REG_INVALID_CALLBACK", account, callbackSpec, client.t("Cannot send verification code there"))
|
109
|
147
|
return false
|
110
|
148
|
}
|
111
|
149
|
|
|
@@ -129,12 +167,12 @@ func accRegisterHandler(server *Server, client *Client, msg ircmsg.IrcMessage, r
|
129
|
167
|
}
|
130
|
168
|
}
|
131
|
169
|
if credentialType == "certfp" && client.certfp == "" {
|
132
|
|
- rb.Add(nil, server.name, ERR_REG_INVALID_CRED_TYPE, nick, credentialType, callbackNamespace, client.t("You are not using a TLS certificate"))
|
|
170
|
+ rb.Add(nil, server.name, "FAIL", "ACC", "REG_INVALID_CRED_TYPE", account, credentialType, client.t("You are not using a TLS certificate"))
|
133
|
171
|
return false
|
134
|
172
|
}
|
135
|
173
|
|
136
|
174
|
if !credentialValid {
|
137
|
|
- rb.Add(nil, server.name, ERR_REG_INVALID_CRED_TYPE, nick, credentialType, callbackNamespace, client.t("Credential type is not supported"))
|
|
175
|
+ rb.Add(nil, server.name, "FAIL", "ACC", "REG_INVALID_CRED_TYPE", account, credentialType, client.t("Credential type is not supported"))
|
138
|
176
|
return false
|
139
|
177
|
}
|
140
|
178
|
|
|
@@ -147,14 +185,14 @@ func accRegisterHandler(server *Server, client *Client, msg ircmsg.IrcMessage, r
|
147
|
185
|
|
148
|
186
|
throttled, remainingTime := client.loginThrottle.Touch()
|
149
|
187
|
if throttled {
|
150
|
|
- rb.Add(nil, server.name, ERR_REG_UNSPECIFIED_ERROR, nick, fmt.Sprintf(client.t("Please wait at least %v and try again"), remainingTime))
|
|
188
|
+ rb.Add(nil, server.name, "FAIL", "ACC", "REG_UNSPECIFIED_ERROR", account, fmt.Sprintf(client.t("Please wait at least %v and try again"), remainingTime))
|
151
|
189
|
return false
|
152
|
190
|
}
|
153
|
191
|
|
154
|
192
|
err = server.accounts.Register(client, account, callbackNamespace, callbackValue, passphrase, certfp)
|
155
|
193
|
if err != nil {
|
156
|
|
- msg, code := registrationErrorToMessageAndCode(err)
|
157
|
|
- rb.Add(nil, server.name, code, nick, "ACC", "REGISTER", client.t(msg))
|
|
194
|
+ msg := registrationErrorToMessageAndCode(err)
|
|
195
|
+ rb.Add(nil, server.name, "FAIL", "ACC", "REG_UNSPECIFIED_ERROR", account, client.t(msg))
|
158
|
196
|
return false
|
159
|
197
|
}
|
160
|
198
|
|
|
@@ -174,15 +212,13 @@ func accRegisterHandler(server *Server, client *Client, msg ircmsg.IrcMessage, r
|
174
|
212
|
return false
|
175
|
213
|
}
|
176
|
214
|
|
177
|
|
-func registrationErrorToMessageAndCode(err error) (message, numeric string) {
|
|
215
|
+func registrationErrorToMessageAndCode(err error) (message string) {
|
178
|
216
|
// default responses: let's be risk-averse about displaying internal errors
|
179
|
217
|
// to the clients, especially for something as sensitive as accounts
|
180
|
218
|
message = `Could not register`
|
181
|
|
- numeric = ERR_UNKNOWNERROR
|
182
|
219
|
switch err {
|
183
|
220
|
case errAccountAlreadyRegistered, errAccountAlreadyVerified:
|
184
|
221
|
message = err.Error()
|
185
|
|
- numeric = ERR_ACCOUNT_ALREADY_EXISTS
|
186
|
222
|
case errAccountCreation, errAccountMustHoldNick, errAccountBadPassphrase, errCertfpAlreadyExists, errFeatureDisabled:
|
187
|
223
|
message = err.Error()
|
188
|
224
|
}
|
|
@@ -194,20 +230,23 @@ func sendSuccessfulRegResponse(client *Client, rb *ResponseBuffer, forNS bool) {
|
194
|
230
|
if forNS {
|
195
|
231
|
rb.Notice(client.t("Account created"))
|
196
|
232
|
} else {
|
197
|
|
- rb.Add(nil, client.server.name, RPL_REGISTRATION_SUCCESS, client.nick, client.AccountName(), client.t("Account created"))
|
|
233
|
+ rb.Add(nil, client.server.name, RPL_REG_SUCCESS, client.nick, client.AccountName(), client.t("Account created"))
|
198
|
234
|
}
|
199
|
|
- sendSuccessfulSaslAuth(client, rb, forNS)
|
|
235
|
+ sendSuccessfulAccountAuth(client, rb, forNS, false)
|
200
|
236
|
}
|
201
|
237
|
|
202
|
|
-// sendSuccessfulSaslAuth means that a SASL auth attempt completed successfully, and is used to dispatch messages.
|
203
|
|
-func sendSuccessfulSaslAuth(client *Client, rb *ResponseBuffer, forNS bool) {
|
|
238
|
+// sendSuccessfulAccountAuth means that an account auth attempt completed successfully, and is used to dispatch messages.
|
|
239
|
+func sendSuccessfulAccountAuth(client *Client, rb *ResponseBuffer, forNS, forSASL bool) {
|
204
|
240
|
details := client.Details()
|
205
|
241
|
|
206
|
242
|
if forNS {
|
207
|
243
|
rb.Notice(fmt.Sprintf(client.t("You're now logged in as %s"), details.accountName))
|
208
|
244
|
} else {
|
|
245
|
+ //TODO(dan): some servers send this numeric even for NickServ logins iirc? to confirm and maybe do too
|
209
|
246
|
rb.Add(nil, client.server.name, RPL_LOGGEDIN, details.nick, details.nickMask, details.accountName, fmt.Sprintf(client.t("You are now logged in as %s"), details.accountName))
|
210
|
|
- rb.Add(nil, client.server.name, RPL_SASLSUCCESS, details.nick, client.t("Authentication successful"))
|
|
247
|
+ if forSASL {
|
|
248
|
+ rb.Add(nil, client.server.name, RPL_SASLSUCCESS, details.nick, client.t("Authentication successful"))
|
|
249
|
+ }
|
211
|
250
|
}
|
212
|
251
|
|
213
|
252
|
// dispatch account-notify
|
|
@@ -223,26 +262,33 @@ func sendSuccessfulSaslAuth(client *Client, rb *ResponseBuffer, forNS bool) {
|
223
|
262
|
// ACC VERIFY <accountname> <auth_code>
|
224
|
263
|
func accVerifyHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
225
|
264
|
account := strings.TrimSpace(msg.Params[1])
|
|
265
|
+
|
|
266
|
+ if len(msg.Params) < 3 {
|
|
267
|
+ rb.Add(nil, server.name, ERR_NEEDMOREPARAMS, client.Nick(), msg.Command, client.t("Not enough parameters"))
|
|
268
|
+ return false
|
|
269
|
+ }
|
|
270
|
+
|
226
|
271
|
err := server.accounts.Verify(client, account, msg.Params[2])
|
227
|
272
|
|
228
|
273
|
var code string
|
229
|
274
|
var message string
|
230
|
275
|
|
231
|
276
|
if err == errAccountVerificationInvalidCode {
|
232
|
|
- code = ERR_ACCOUNT_INVALID_VERIFY_CODE
|
|
277
|
+ code = "ACCOUNT_INVALID_VERIFY_CODE"
|
233
|
278
|
message = err.Error()
|
234
|
279
|
} else if err == errAccountAlreadyVerified {
|
235
|
|
- code = ERR_ACCOUNT_ALREADY_VERIFIED
|
|
280
|
+ code = "ACCOUNT_ALREADY_VERIFIED"
|
236
|
281
|
message = err.Error()
|
237
|
282
|
} else if err != nil {
|
238
|
|
- code = ERR_UNKNOWNERROR
|
|
283
|
+ code = "VERIFY_UNSPECIFIED_ERROR"
|
239
|
284
|
message = errAccountVerificationFailed.Error()
|
240
|
285
|
}
|
241
|
286
|
|
242
|
287
|
if err == nil {
|
243
|
|
- sendSuccessfulRegResponse(client, rb, false)
|
|
288
|
+ rb.Add(nil, server.name, RPL_VERIFY_SUCCESS, client.Nick(), account, client.t("Account verification successful"))
|
|
289
|
+ sendSuccessfulAccountAuth(client, rb, false, false)
|
244
|
290
|
} else {
|
245
|
|
- rb.Add(nil, server.name, code, client.Nick(), account, client.t(message))
|
|
291
|
+ rb.Add(nil, server.name, "FAIL", "ACC", code, account, client.t(message))
|
246
|
292
|
}
|
247
|
293
|
|
248
|
294
|
return false
|
|
@@ -373,7 +419,7 @@ func authPlainHandler(server *Server, client *Client, mechanism string, value []
|
373
|
419
|
return false
|
374
|
420
|
}
|
375
|
421
|
|
376
|
|
- sendSuccessfulSaslAuth(client, rb, false)
|
|
422
|
+ sendSuccessfulAccountAuth(client, rb, false, true)
|
377
|
423
|
return false
|
378
|
424
|
}
|
379
|
425
|
|
|
@@ -401,7 +447,7 @@ func authExternalHandler(server *Server, client *Client, mechanism string, value
|
401
|
447
|
return false
|
402
|
448
|
}
|
403
|
449
|
|
404
|
|
- sendSuccessfulSaslAuth(client, rb, false)
|
|
450
|
+ sendSuccessfulAccountAuth(client, rb, false, true)
|
405
|
451
|
return false
|
406
|
452
|
}
|
407
|
453
|
|