|
@@ -5,161 +5,342 @@ package irc
|
5
|
5
|
|
6
|
6
|
import (
|
7
|
7
|
"fmt"
|
|
8
|
+ "sort"
|
8
|
9
|
"strings"
|
|
10
|
+
|
|
11
|
+ "github.com/goshuirc/irc-go/ircfmt"
|
|
12
|
+
|
|
13
|
+ "github.com/oragono/oragono/irc/modes"
|
|
14
|
+ "github.com/oragono/oragono/irc/utils"
|
9
|
15
|
)
|
10
|
16
|
|
11
|
17
|
// TODO: "email" is an oversimplification here; it's actually any callback, e.g.,
|
12
|
18
|
// person@example.com, mailto:person@example.com, tel:16505551234.
|
13
|
|
-const nickservHelp = `NickServ lets you register and log into a user account.
|
14
|
|
-
|
15
|
|
-To register an account:
|
16
|
|
- /NS REGISTER username email [password]
|
17
|
|
-Leave out [password] if you're registering using your client certificate fingerprint.
|
18
|
|
-The server may or may not allow you to register anonymously (by sending * as your
|
19
|
|
-email address).
|
20
|
|
-
|
21
|
|
-To verify an account (if you were sent a verification code):
|
22
|
|
- /NS VERIFY username code
|
23
|
|
-
|
24
|
|
-To unregister an account:
|
25
|
|
- /NS UNREGISTER [username]
|
26
|
|
-Leave out [username] if you're unregistering the user you're currently logged in as.
|
27
|
|
-
|
28
|
|
-To login to an account:
|
29
|
|
- /NS IDENTIFY [username password]
|
30
|
|
-Leave out [username password] to use your client certificate fingerprint. Otherwise,
|
31
|
|
-the given username and password will be used.
|
32
|
|
-
|
33
|
|
-To see account information:
|
34
|
|
- /NS INFO [username]
|
35
|
|
-Leave out [username] to see your own account information.
|
36
|
|
-
|
37
|
|
-To associate your current nick with the account you're logged into:
|
38
|
|
- /NS GROUP
|
39
|
|
-
|
40
|
|
-To disassociate a nick with the account you're logged into:
|
41
|
|
- /NS DROP [nickname]
|
42
|
|
-Leave out [nickname] to drop your association with your current nickname.`
|
43
|
|
-
|
44
|
|
-// extractParam extracts a parameter from the given string, returning the param and the rest of the string.
|
45
|
|
-func extractParam(line string) (string, string) {
|
46
|
|
- rawParams := strings.SplitN(strings.TrimSpace(line), " ", 2)
|
47
|
|
- param0 := rawParams[0]
|
48
|
|
- var param1 string
|
49
|
|
- if 1 < len(rawParams) {
|
50
|
|
- param1 = strings.TrimSpace(rawParams[1])
|
51
|
|
- }
|
52
|
|
- return param0, param1
|
53
|
|
-}
|
|
19
|
+const nickservHelp = `NickServ lets you register and login to an account.
|
54
|
20
|
|
55
|
|
-// nickservNoticeHandler handles NOTICEs that NickServ receives.
|
56
|
|
-func (server *Server) nickservNoticeHandler(client *Client, message string, rb *ResponseBuffer) {
|
57
|
|
- // do nothing
|
|
21
|
+To see in-depth help for a specific NickServ command, try:
|
|
22
|
+ $b/NS HELP <command>$b
|
|
23
|
+
|
|
24
|
+Here are the commands you can use:
|
|
25
|
+%s`
|
|
26
|
+
|
|
27
|
+type nsCommand struct {
|
|
28
|
+ capabs []string // oper capabs the given user has to have to access this command
|
|
29
|
+ handler func(server *Server, client *Client, command, params string, rb *ResponseBuffer)
|
|
30
|
+ help string
|
|
31
|
+ helpShort string
|
|
32
|
+ nickReservation bool // nick reservation must be enabled to use this command
|
|
33
|
+ oper bool // true if the user has to be an oper to use this command
|
58
|
34
|
}
|
59
|
35
|
|
|
36
|
+var (
|
|
37
|
+ nickservCommands = map[string]*nsCommand{
|
|
38
|
+ "drop": {
|
|
39
|
+ handler: nsDropHandler,
|
|
40
|
+ help: `Syntax: $bDROP [nickname]$b
|
|
41
|
+
|
|
42
|
+DROP de-links the given (or your current) nickname from your user account.`,
|
|
43
|
+ helpShort: `$bDROP$b de-links your current (or the given) nickname from your user account.`,
|
|
44
|
+ nickReservation: true,
|
|
45
|
+ },
|
|
46
|
+ "ghost": {
|
|
47
|
+ handler: nsGhostHandler,
|
|
48
|
+ help: `Syntax: $bGHOST <nickname>$b
|
|
49
|
+
|
|
50
|
+GHOST disconnects the given user from the network if they're logged in with the
|
|
51
|
+same user account, letting you reclaim your nickname.`,
|
|
52
|
+ helpShort: `$bGHOST$b reclaims your nickname.`,
|
|
53
|
+ },
|
|
54
|
+ "group": {
|
|
55
|
+ handler: nsGroupHandler,
|
|
56
|
+ help: `Syntax: $bGROUP$b
|
|
57
|
+
|
|
58
|
+GROUP links your current nickname with your logged-in account, preventing other
|
|
59
|
+users from changing to it (or forcing them to rename).`,
|
|
60
|
+ helpShort: `$bGROUP$b links your current nickname to your user account.`,
|
|
61
|
+ nickReservation: true,
|
|
62
|
+ },
|
|
63
|
+ "help": {
|
|
64
|
+ help: `Syntax: $bHELP [command]$b
|
|
65
|
+
|
|
66
|
+HELP returns information on the given command.`,
|
|
67
|
+ helpShort: `$bHELP$b shows in-depth information about commands.`,
|
|
68
|
+ },
|
|
69
|
+ "identify": {
|
|
70
|
+ handler: nsIdentifyHandler,
|
|
71
|
+ help: `Syntax: $bIDENTIFY <username> [password]$b
|
|
72
|
+
|
|
73
|
+IDENTIFY lets you login to the given username using either password auth, or
|
|
74
|
+certfp (your client certificate) if a password is not given.`,
|
|
75
|
+ helpShort: `$bIDENTIFY$b lets you login to your account.`,
|
|
76
|
+ },
|
|
77
|
+ "info": {
|
|
78
|
+ handler: nsInfoHandler,
|
|
79
|
+ help: `Syntax: $bINFO [username]$b
|
|
80
|
+
|
|
81
|
+INFO gives you information about the given (or your own) user account.`,
|
|
82
|
+ helpShort: `$bINFO$b gives you information on a user account.`,
|
|
83
|
+ },
|
|
84
|
+ "register": {
|
|
85
|
+ handler: nsRegisterHandler,
|
|
86
|
+ help: `Syntax: $bREGISTER <username> <email> [password]$b
|
|
87
|
+
|
|
88
|
+REGISTER lets you register a user account. If the server allows anonymous
|
|
89
|
+registration, you can send an asterisk (*) as the email address.
|
|
90
|
+
|
|
91
|
+If the password is left out, your account will be registered to your TLS client
|
|
92
|
+certificate (and you will need to use that certificate to login in future).`,
|
|
93
|
+ helpShort: `$bREGISTER$b lets you register a user account.`,
|
|
94
|
+ },
|
|
95
|
+ "sadrop": {
|
|
96
|
+ handler: nsDropHandler,
|
|
97
|
+ help: `Syntax: $bSADROP <nickname>$b
|
|
98
|
+
|
|
99
|
+SADROP foribly de-links the given nickname from the attached user account.`,
|
|
100
|
+ helpShort: `$bSADROP$b forcibly de-links the given nickname from its user account.`,
|
|
101
|
+ nickReservation: true,
|
|
102
|
+ capabs: []string{"unregister"},
|
|
103
|
+ },
|
|
104
|
+ "unregister": {
|
|
105
|
+ handler: nsUnregisterHandler,
|
|
106
|
+ help: `Syntax: $bUNREGISTER [username]$b
|
|
107
|
+
|
|
108
|
+UNREGISTER lets you delete your user account (or the given one, if you're an
|
|
109
|
+IRC operator with the correct permissions).`,
|
|
110
|
+ helpShort: `$bUNREGISTER$b lets you delete your user account.`,
|
|
111
|
+ },
|
|
112
|
+ "verify": {
|
|
113
|
+ handler: nsVerifyHandler,
|
|
114
|
+ help: `Syntax: $bVERIFY <username> <code>$b
|
|
115
|
+
|
|
116
|
+VERIFY lets you complete an account registration, if the server requires email
|
|
117
|
+or other verification.`,
|
|
118
|
+ helpShort: `$bVERIFY$b lets you complete account registration.`,
|
|
119
|
+ },
|
|
120
|
+ }
|
|
121
|
+)
|
|
122
|
+
|
60
|
123
|
// send a notice from the NickServ "nick"
|
61
|
124
|
func nsNotice(rb *ResponseBuffer, text string) {
|
62
|
125
|
rb.Add(nil, "NickServ", "NOTICE", rb.target.Nick(), text)
|
63
|
126
|
}
|
64
|
127
|
|
|
128
|
+// nickservNoticeHandler handles NOTICEs that NickServ receives.
|
|
129
|
+func (server *Server) nickservNoticeHandler(client *Client, message string, rb *ResponseBuffer) {
|
|
130
|
+ // do nothing
|
|
131
|
+}
|
|
132
|
+
|
65
|
133
|
// nickservPrivmsgHandler handles PRIVMSGs that NickServ receives.
|
66
|
134
|
func (server *Server) nickservPrivmsgHandler(client *Client, message string, rb *ResponseBuffer) {
|
67
|
|
- command, params := extractParam(message)
|
68
|
|
- command = strings.ToLower(command)
|
|
135
|
+ commandName, params := utils.ExtractParam(message)
|
|
136
|
+ commandName = strings.ToLower(commandName)
|
69
|
137
|
|
70
|
|
- if command == "help" {
|
71
|
|
- for _, line := range strings.Split(nickservHelp, "\n") {
|
72
|
|
- nsNotice(rb, line)
|
73
|
|
- }
|
74
|
|
- } else if command == "register" {
|
75
|
|
- // get params
|
76
|
|
- username, afterUsername := extractParam(params)
|
77
|
|
- email, passphrase := extractParam(afterUsername)
|
78
|
|
- server.nickservRegisterHandler(client, username, email, passphrase, rb)
|
79
|
|
- } else if command == "verify" {
|
80
|
|
- username, code := extractParam(params)
|
81
|
|
- server.nickservVerifyHandler(client, username, code, rb)
|
82
|
|
- } else if command == "identify" {
|
83
|
|
- username, passphrase := extractParam(params)
|
84
|
|
- server.nickservIdentifyHandler(client, username, passphrase, rb)
|
85
|
|
- } else if command == "unregister" {
|
86
|
|
- username, _ := extractParam(params)
|
87
|
|
- server.nickservUnregisterHandler(client, username, rb)
|
88
|
|
- } else if command == "ghost" {
|
89
|
|
- nick, _ := extractParam(params)
|
90
|
|
- server.nickservGhostHandler(client, nick, rb)
|
91
|
|
- } else if command == "info" {
|
92
|
|
- nick, _ := extractParam(params)
|
93
|
|
- server.nickservInfoHandler(client, nick, rb)
|
94
|
|
- } else if command == "group" {
|
95
|
|
- server.nickservGroupHandler(client, rb)
|
96
|
|
- } else if command == "drop" {
|
97
|
|
- nick, _ := extractParam(params)
|
98
|
|
- server.nickservDropHandler(client, nick, false, rb)
|
99
|
|
- } else if command == "sadrop" {
|
100
|
|
- nick, _ := extractParam(params)
|
101
|
|
- server.nickservDropHandler(client, nick, true, rb)
|
102
|
|
- } else {
|
103
|
|
- nsNotice(rb, client.t("Command not recognised. To see the available commands, run /NS HELP"))
|
|
138
|
+ commandInfo := nickservCommands[commandName]
|
|
139
|
+ if commandInfo == nil {
|
|
140
|
+ nsNotice(rb, client.t("Unknown command. To see available commands, run /NS HELP"))
|
|
141
|
+ return
|
104
|
142
|
}
|
105
|
|
-}
|
106
|
143
|
|
107
|
|
-func (server *Server) nickservUnregisterHandler(client *Client, username string, rb *ResponseBuffer) {
|
108
|
|
- if !server.AccountConfig().Registration.Enabled {
|
|
144
|
+ if commandInfo.oper && !client.HasMode(modes.Operator) {
|
|
145
|
+ nsNotice(rb, client.t("Command restricted"))
|
|
146
|
+ return
|
|
147
|
+ }
|
|
148
|
+
|
|
149
|
+ if 0 < len(commandInfo.capabs) && !client.HasRoleCapabs(commandInfo.capabs...) {
|
|
150
|
+ nsNotice(rb, client.t("Command restricted"))
|
|
151
|
+ return
|
|
152
|
+ }
|
|
153
|
+
|
|
154
|
+ if commandInfo.nickReservation && !server.AccountConfig().Registration.Enabled {
|
109
|
155
|
nsNotice(rb, client.t("Account registration has been disabled"))
|
110
|
156
|
return
|
111
|
157
|
}
|
112
|
158
|
|
113
|
|
- if username == "" {
|
114
|
|
- username = client.Account()
|
|
159
|
+ // custom help handling here to prevent recursive init loop
|
|
160
|
+ if commandName == "help" {
|
|
161
|
+ nsHelpHandler(server, client, commandName, params, rb)
|
|
162
|
+ return
|
115
|
163
|
}
|
116
|
|
- if username == "" {
|
117
|
|
- nsNotice(rb, client.t("You're not logged into an account"))
|
|
164
|
+
|
|
165
|
+ if commandInfo.handler == nil {
|
|
166
|
+ nsNotice(rb, client.t("Command error. Please report this to the developers"))
|
118
|
167
|
return
|
119
|
168
|
}
|
120
|
|
- cfname, err := CasefoldName(username)
|
121
|
|
- if err != nil {
|
122
|
|
- nsNotice(rb, client.t("Invalid username"))
|
|
169
|
+
|
|
170
|
+ commandInfo.handler(server, client, commandName, params, rb)
|
|
171
|
+}
|
|
172
|
+
|
|
173
|
+func nsDropHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
|
174
|
+ sadrop := command == "sadrop"
|
|
175
|
+ nick, _ := utils.ExtractParam(params)
|
|
176
|
+
|
|
177
|
+ err := server.accounts.SetNickReserved(client, nick, sadrop, false)
|
|
178
|
+ if err == nil {
|
|
179
|
+ nsNotice(rb, fmt.Sprintf(client.t("Successfully ungrouped nick %s with your account"), nick))
|
|
180
|
+ } else if err == errAccountNotLoggedIn {
|
|
181
|
+ nsNotice(rb, client.t("You're not logged into an account"))
|
|
182
|
+ } else if err == errAccountCantDropPrimaryNick {
|
|
183
|
+ nsNotice(rb, client.t("You can't ungroup your primary nickname (try unregistering your account instead)"))
|
|
184
|
+ } else if err == errNicknameReserved {
|
|
185
|
+ nsNotice(rb, client.t("That nickname is already reserved by someone else"))
|
|
186
|
+ } else {
|
|
187
|
+ nsNotice(rb, client.t("Could not ungroup nick"))
|
|
188
|
+ }
|
|
189
|
+}
|
|
190
|
+
|
|
191
|
+func nsGhostHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
|
192
|
+ nick, _ := utils.ExtractParam(params)
|
|
193
|
+
|
|
194
|
+ account := client.Account()
|
|
195
|
+ if account == "" || server.accounts.NickToAccount(nick) != account {
|
|
196
|
+ nsNotice(rb, client.t("You don't own that nick"))
|
123
|
197
|
return
|
124
|
198
|
}
|
125
|
|
- if !(cfname == client.Account() || client.HasRoleCapabs("unregister")) {
|
126
|
|
- nsNotice(rb, client.t("Insufficient oper privs"))
|
|
199
|
+
|
|
200
|
+ ghost := server.clients.Get(nick)
|
|
201
|
+ if ghost == nil {
|
|
202
|
+ nsNotice(rb, client.t("No such nick"))
|
|
203
|
+ return
|
|
204
|
+ } else if ghost == client {
|
|
205
|
+ nsNotice(rb, client.t("You can't GHOST yourself (try /QUIT instead)"))
|
127
|
206
|
return
|
128
|
207
|
}
|
129
|
208
|
|
130
|
|
- if cfname == client.Account() {
|
131
|
|
- client.server.accounts.Logout(client)
|
|
209
|
+ ghost.Quit(fmt.Sprintf(ghost.t("GHOSTed by %s"), client.Nick()))
|
|
210
|
+ ghost.destroy(false)
|
|
211
|
+}
|
|
212
|
+
|
|
213
|
+func nsGroupHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
|
214
|
+ account := client.Account()
|
|
215
|
+ if account == "" {
|
|
216
|
+ nsNotice(rb, client.t("You're not logged into an account"))
|
|
217
|
+ return
|
132
|
218
|
}
|
133
|
219
|
|
134
|
|
- err = server.accounts.Unregister(cfname)
|
135
|
|
- if err == errAccountDoesNotExist {
|
136
|
|
- nsNotice(rb, client.t(err.Error()))
|
137
|
|
- } else if err != nil {
|
138
|
|
- nsNotice(rb, client.t("Error while unregistering account"))
|
|
220
|
+ nick := client.NickCasefolded()
|
|
221
|
+ err := server.accounts.SetNickReserved(client, nick, false, true)
|
|
222
|
+ if err == nil {
|
|
223
|
+ nsNotice(rb, fmt.Sprintf(client.t("Successfully grouped nick %s with your account"), nick))
|
|
224
|
+ } else if err == errAccountTooManyNicks {
|
|
225
|
+ nsNotice(rb, client.t("You have too many nicks reserved already (you can remove some with /NS DROP)"))
|
|
226
|
+ } else if err == errNicknameReserved {
|
|
227
|
+ nsNotice(rb, client.t("That nickname is already reserved by someone else"))
|
139
|
228
|
} else {
|
140
|
|
- nsNotice(rb, fmt.Sprintf(client.t("Successfully unregistered account %s"), cfname))
|
|
229
|
+ nsNotice(rb, client.t("Error reserving nickname"))
|
141
|
230
|
}
|
142
|
231
|
}
|
143
|
232
|
|
144
|
|
-func (server *Server) nickservVerifyHandler(client *Client, username string, code string, rb *ResponseBuffer) {
|
145
|
|
- err := server.accounts.Verify(client, username, code)
|
|
233
|
+func nsHelpHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
|
234
|
+ nsNotice(rb, ircfmt.Unescape(client.t("*** $bNickServ HELP$b ***")))
|
146
|
235
|
|
147
|
|
- var errorMessage string
|
148
|
|
- if err == errAccountVerificationInvalidCode || err == errAccountAlreadyVerified {
|
149
|
|
- errorMessage = err.Error()
|
150
|
|
- } else if err != nil {
|
151
|
|
- errorMessage = errAccountVerificationFailed.Error()
|
|
236
|
+ if params == "" {
|
|
237
|
+ // show general help
|
|
238
|
+ var shownHelpLines sort.StringSlice
|
|
239
|
+ for _, commandInfo := range nickservCommands {
|
|
240
|
+ // skip commands user can't access
|
|
241
|
+ if commandInfo.oper && !client.HasMode(modes.Operator) {
|
|
242
|
+ continue
|
|
243
|
+ }
|
|
244
|
+ if 0 < len(commandInfo.capabs) && !client.HasRoleCapabs(commandInfo.capabs...) {
|
|
245
|
+ continue
|
|
246
|
+ }
|
|
247
|
+ if commandInfo.nickReservation && !server.AccountConfig().Registration.Enabled {
|
|
248
|
+ continue
|
|
249
|
+ }
|
|
250
|
+
|
|
251
|
+ shownHelpLines = append(shownHelpLines, " "+client.t(commandInfo.helpShort))
|
|
252
|
+ }
|
|
253
|
+
|
|
254
|
+ // sort help lines
|
|
255
|
+ sort.Sort(shownHelpLines)
|
|
256
|
+
|
|
257
|
+ // assemble help text
|
|
258
|
+ assembledHelpLines := strings.Join(shownHelpLines, "\n")
|
|
259
|
+ fullHelp := ircfmt.Unescape(fmt.Sprintf(client.t(nickservHelp), assembledHelpLines))
|
|
260
|
+
|
|
261
|
+ // push out help text
|
|
262
|
+ for _, line := range strings.Split(fullHelp, "\n") {
|
|
263
|
+ nsNotice(rb, line)
|
|
264
|
+ }
|
|
265
|
+ } else {
|
|
266
|
+ commandInfo := nickservCommands[strings.ToLower(strings.TrimSpace(params))]
|
|
267
|
+ if commandInfo == nil {
|
|
268
|
+ nsNotice(rb, client.t("Unknown command. To see available commands, run /NS HELP"))
|
|
269
|
+ } else {
|
|
270
|
+ for _, line := range strings.Split(ircfmt.Unescape(client.t(commandInfo.help)), "\n") {
|
|
271
|
+ nsNotice(rb, line)
|
|
272
|
+ }
|
|
273
|
+ }
|
152
|
274
|
}
|
153
|
275
|
|
154
|
|
- if errorMessage != "" {
|
155
|
|
- nsNotice(rb, client.t(errorMessage))
|
|
276
|
+ nsNotice(rb, ircfmt.Unescape(client.t("*** $bEnd of NickServ HELP$b ***")))
|
|
277
|
+}
|
|
278
|
+
|
|
279
|
+func nsIdentifyHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
|
280
|
+ // fail out if we need to
|
|
281
|
+ if !server.AccountConfig().AuthenticationEnabled {
|
|
282
|
+ nsNotice(rb, client.t("Login has been disabled"))
|
156
|
283
|
return
|
157
|
284
|
}
|
158
|
285
|
|
159
|
|
- sendSuccessfulRegResponse(client, rb, true)
|
|
286
|
+ loginSuccessful := false
|
|
287
|
+
|
|
288
|
+ username, passphrase := utils.ExtractParam(params)
|
|
289
|
+
|
|
290
|
+ // try passphrase
|
|
291
|
+ if username != "" && passphrase != "" {
|
|
292
|
+ err := server.accounts.AuthenticateByPassphrase(client, username, passphrase)
|
|
293
|
+ loginSuccessful = (err == nil)
|
|
294
|
+ }
|
|
295
|
+
|
|
296
|
+ // try certfp
|
|
297
|
+ if !loginSuccessful && client.certfp != "" {
|
|
298
|
+ err := server.accounts.AuthenticateByCertFP(client)
|
|
299
|
+ loginSuccessful = (err == nil)
|
|
300
|
+ }
|
|
301
|
+
|
|
302
|
+ if loginSuccessful {
|
|
303
|
+ sendSuccessfulSaslAuth(client, rb, true)
|
|
304
|
+ } else {
|
|
305
|
+ nsNotice(rb, client.t("Could not login with your TLS certificate or supplied username/password"))
|
|
306
|
+ }
|
160
|
307
|
}
|
161
|
308
|
|
162
|
|
-func (server *Server) nickservRegisterHandler(client *Client, username, email, passphrase string, rb *ResponseBuffer) {
|
|
309
|
+func nsInfoHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
|
310
|
+ nick, _ := utils.ExtractParam(params)
|
|
311
|
+
|
|
312
|
+ if nick == "" {
|
|
313
|
+ nick = client.Nick()
|
|
314
|
+ }
|
|
315
|
+
|
|
316
|
+ accountName := nick
|
|
317
|
+ if server.AccountConfig().NickReservation.Enabled {
|
|
318
|
+ accountName = server.accounts.NickToAccount(nick)
|
|
319
|
+ if accountName == "" {
|
|
320
|
+ nsNotice(rb, client.t("That nickname is not registered"))
|
|
321
|
+ return
|
|
322
|
+ }
|
|
323
|
+ }
|
|
324
|
+
|
|
325
|
+ account, err := server.accounts.LoadAccount(accountName)
|
|
326
|
+ if err != nil || !account.Verified {
|
|
327
|
+ nsNotice(rb, client.t("Account does not exist"))
|
|
328
|
+ }
|
|
329
|
+
|
|
330
|
+ nsNotice(rb, fmt.Sprintf(client.t("Account: %s"), account.Name))
|
|
331
|
+ registeredAt := account.RegisteredAt.Format("Jan 02, 2006 15:04:05Z")
|
|
332
|
+ nsNotice(rb, fmt.Sprintf(client.t("Registered at: %s"), registeredAt))
|
|
333
|
+ // TODO nicer formatting for this
|
|
334
|
+ for _, nick := range account.AdditionalNicks {
|
|
335
|
+ nsNotice(rb, fmt.Sprintf(client.t("Additional grouped nick: %s"), nick))
|
|
336
|
+ }
|
|
337
|
+}
|
|
338
|
+
|
|
339
|
+func nsRegisterHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
|
340
|
+ // get params
|
|
341
|
+ username, afterUsername := utils.ExtractParam(params)
|
|
342
|
+ email, passphrase := utils.ExtractParam(afterUsername)
|
|
343
|
+
|
163
|
344
|
if !server.AccountConfig().Registration.Enabled {
|
164
|
345
|
nsNotice(rb, client.t("Account registration has been disabled"))
|
165
|
346
|
return
|
|
@@ -236,130 +417,61 @@ func (server *Server) nickservRegisterHandler(client *Client, username, email, p
|
236
|
417
|
}
|
237
|
418
|
}
|
238
|
419
|
|
239
|
|
-func (server *Server) nickservIdentifyHandler(client *Client, username, passphrase string, rb *ResponseBuffer) {
|
240
|
|
- // fail out if we need to
|
241
|
|
- if !server.AccountConfig().AuthenticationEnabled {
|
242
|
|
- nsNotice(rb, client.t("Login has been disabled"))
|
243
|
|
- return
|
244
|
|
- }
|
245
|
|
-
|
246
|
|
- loginSuccessful := false
|
|
420
|
+func nsUnregisterHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
|
421
|
+ username, _ := utils.ExtractParam(params)
|
247
|
422
|
|
248
|
|
- // try passphrase
|
249
|
|
- if username != "" && passphrase != "" {
|
250
|
|
- err := server.accounts.AuthenticateByPassphrase(client, username, passphrase)
|
251
|
|
- loginSuccessful = (err == nil)
|
252
|
|
- }
|
253
|
|
-
|
254
|
|
- // try certfp
|
255
|
|
- if !loginSuccessful && client.certfp != "" {
|
256
|
|
- err := server.accounts.AuthenticateByCertFP(client)
|
257
|
|
- loginSuccessful = (err == nil)
|
258
|
|
- }
|
259
|
|
-
|
260
|
|
- if loginSuccessful {
|
261
|
|
- sendSuccessfulSaslAuth(client, rb, true)
|
262
|
|
- } else {
|
263
|
|
- nsNotice(rb, client.t("Could not login with your TLS certificate or supplied username/password"))
|
264
|
|
- }
|
265
|
|
-}
|
266
|
|
-
|
267
|
|
-func (server *Server) nickservGhostHandler(client *Client, nick string, rb *ResponseBuffer) {
|
268
|
|
- if !server.AccountConfig().NickReservation.Enabled {
|
269
|
|
- nsNotice(rb, client.t("Nickname reservation is disabled"))
|
|
423
|
+ if !server.AccountConfig().Registration.Enabled {
|
|
424
|
+ nsNotice(rb, client.t("Account registration has been disabled"))
|
270
|
425
|
return
|
271
|
426
|
}
|
272
|
427
|
|
273
|
|
- account := client.Account()
|
274
|
|
- if account == "" || server.accounts.NickToAccount(nick) != account {
|
275
|
|
- nsNotice(rb, client.t("You don't own that nick"))
|
276
|
|
- return
|
|
428
|
+ if username == "" {
|
|
429
|
+ username = client.Account()
|
277
|
430
|
}
|
278
|
|
-
|
279
|
|
- ghost := server.clients.Get(nick)
|
280
|
|
- if ghost == nil {
|
281
|
|
- nsNotice(rb, client.t("No such nick"))
|
|
431
|
+ if username == "" {
|
|
432
|
+ nsNotice(rb, client.t("You're not logged into an account"))
|
282
|
433
|
return
|
283
|
|
- } else if ghost == client {
|
284
|
|
- nsNotice(rb, client.t("You can't GHOST yourself (try /QUIT instead)"))
|
|
434
|
+ }
|
|
435
|
+ cfname, err := CasefoldName(username)
|
|
436
|
+ if err != nil {
|
|
437
|
+ nsNotice(rb, client.t("Invalid username"))
|
285
|
438
|
return
|
286
|
439
|
}
|
287
|
|
-
|
288
|
|
- ghost.Quit(fmt.Sprintf(ghost.t("GHOSTed by %s"), client.Nick()))
|
289
|
|
- ghost.destroy(false)
|
290
|
|
-}
|
291
|
|
-
|
292
|
|
-func (server *Server) nickservGroupHandler(client *Client, rb *ResponseBuffer) {
|
293
|
|
- if !server.AccountConfig().NickReservation.Enabled {
|
294
|
|
- nsNotice(rb, client.t("Nickname reservation is disabled"))
|
|
440
|
+ if !(cfname == client.Account() || client.HasRoleCapabs("unregister")) {
|
|
441
|
+ nsNotice(rb, client.t("Insufficient oper privs"))
|
295
|
442
|
return
|
296
|
443
|
}
|
297
|
444
|
|
298
|
|
- account := client.Account()
|
299
|
|
- if account == "" {
|
300
|
|
- nsNotice(rb, client.t("You're not logged into an account"))
|
301
|
|
- return
|
|
445
|
+ if cfname == client.Account() {
|
|
446
|
+ client.server.accounts.Logout(client)
|
302
|
447
|
}
|
303
|
448
|
|
304
|
|
- nick := client.NickCasefolded()
|
305
|
|
- err := server.accounts.SetNickReserved(client, nick, false, true)
|
306
|
|
- if err == nil {
|
307
|
|
- nsNotice(rb, fmt.Sprintf(client.t("Successfully grouped nick %s with your account"), nick))
|
308
|
|
- } else if err == errAccountTooManyNicks {
|
309
|
|
- nsNotice(rb, client.t("You have too many nicks reserved already (you can remove some with /NS DROP)"))
|
310
|
|
- } else if err == errNicknameReserved {
|
311
|
|
- nsNotice(rb, client.t("That nickname is already reserved by someone else"))
|
|
449
|
+ err = server.accounts.Unregister(cfname)
|
|
450
|
+ if err == errAccountDoesNotExist {
|
|
451
|
+ nsNotice(rb, client.t(err.Error()))
|
|
452
|
+ } else if err != nil {
|
|
453
|
+ nsNotice(rb, client.t("Error while unregistering account"))
|
312
|
454
|
} else {
|
313
|
|
- nsNotice(rb, client.t("Error reserving nickname"))
|
|
455
|
+ nsNotice(rb, fmt.Sprintf(client.t("Successfully unregistered account %s"), cfname))
|
314
|
456
|
}
|
315
|
457
|
}
|
316
|
458
|
|
317
|
|
-func (server *Server) nickservInfoHandler(client *Client, nick string, rb *ResponseBuffer) {
|
318
|
|
- if nick == "" {
|
319
|
|
- nick = client.Nick()
|
320
|
|
- }
|
|
459
|
+func nsVerifyHandler(server *Server, client *Client, command, params string, rb *ResponseBuffer) {
|
|
460
|
+ username, code := utils.ExtractParam(params)
|
321
|
461
|
|
322
|
|
- accountName := nick
|
323
|
|
- if server.AccountConfig().NickReservation.Enabled {
|
324
|
|
- accountName = server.accounts.NickToAccount(nick)
|
325
|
|
- if accountName == "" {
|
326
|
|
- nsNotice(rb, client.t("That nickname is not registered"))
|
327
|
|
- return
|
328
|
|
- }
|
329
|
|
- }
|
330
|
|
-
|
331
|
|
- account, err := server.accounts.LoadAccount(accountName)
|
332
|
|
- if err != nil || !account.Verified {
|
333
|
|
- nsNotice(rb, client.t("Account does not exist"))
|
334
|
|
- }
|
|
462
|
+ err := server.accounts.Verify(client, username, code)
|
335
|
463
|
|
336
|
|
- nsNotice(rb, fmt.Sprintf(client.t("Account: %s"), account.Name))
|
337
|
|
- registeredAt := account.RegisteredAt.Format("Jan 02, 2006 15:04:05Z")
|
338
|
|
- nsNotice(rb, fmt.Sprintf(client.t("Registered at: %s"), registeredAt))
|
339
|
|
- // TODO nicer formatting for this
|
340
|
|
- for _, nick := range account.AdditionalNicks {
|
341
|
|
- nsNotice(rb, fmt.Sprintf(client.t("Additional grouped nick: %s"), nick))
|
|
464
|
+ var errorMessage string
|
|
465
|
+ if err == errAccountVerificationInvalidCode || err == errAccountAlreadyVerified {
|
|
466
|
+ errorMessage = err.Error()
|
|
467
|
+ } else if err != nil {
|
|
468
|
+ errorMessage = errAccountVerificationFailed.Error()
|
342
|
469
|
}
|
343
|
|
-}
|
344
|
470
|
|
345
|
|
-func (server *Server) nickservDropHandler(client *Client, nick string, sadrop bool, rb *ResponseBuffer) {
|
346
|
|
- if sadrop {
|
347
|
|
- if !client.HasRoleCapabs("unregister") {
|
348
|
|
- nsNotice(rb, client.t("Insufficient oper privs"))
|
349
|
|
- return
|
350
|
|
- }
|
|
471
|
+ if errorMessage != "" {
|
|
472
|
+ nsNotice(rb, client.t(errorMessage))
|
|
473
|
+ return
|
351
|
474
|
}
|
352
|
475
|
|
353
|
|
- err := server.accounts.SetNickReserved(client, nick, sadrop, false)
|
354
|
|
- if err == nil {
|
355
|
|
- nsNotice(rb, fmt.Sprintf(client.t("Successfully ungrouped nick %s with your account"), nick))
|
356
|
|
- } else if err == errAccountNotLoggedIn {
|
357
|
|
- nsNotice(rb, fmt.Sprintf(client.t("You're not logged into an account")))
|
358
|
|
- } else if err == errAccountCantDropPrimaryNick {
|
359
|
|
- nsNotice(rb, fmt.Sprintf(client.t("You can't ungroup your primary nickname (try unregistering your account instead)")))
|
360
|
|
- } else if err == errNicknameReserved {
|
361
|
|
- nsNotice(rb, fmt.Sprintf(client.t("That nickname is already reserved by someone else")))
|
362
|
|
- } else {
|
363
|
|
- nsNotice(rb, client.t("Error ungrouping nick"))
|
364
|
|
- }
|
|
476
|
+ sendSuccessfulRegResponse(client, rb, true)
|
365
|
477
|
}
|