選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

nickserv.go 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. // Copyright (c) 2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "fmt"
  6. "strings"
  7. )
  8. // TODO: "email" is an oversimplification here; it's actually any callback, e.g.,
  9. // person@example.com, mailto:person@example.com, tel:16505551234.
  10. const nickservHelp = `NickServ lets you register and log into a user account.
  11. To register an account:
  12. /NS REGISTER username email [password]
  13. Leave out [password] if you're registering using your client certificate fingerprint.
  14. The server may or may not allow you to register anonymously (by sending * as your
  15. email address).
  16. To verify an account (if you were sent a verification code):
  17. /NS VERIFY username code
  18. To unregister an account:
  19. /NS UNREGISTER [username]
  20. Leave out [username] if you're unregistering the user you're currently logged in as.
  21. To login to an account:
  22. /NS IDENTIFY [username password]
  23. Leave out [username password] to use your client certificate fingerprint. Otherwise,
  24. the given username and password will be used.
  25. To see account information:
  26. /NS INFO [username]
  27. Leave out [username] to see your own account information.
  28. To associate your current nick with the account you're logged into:
  29. /NS GROUP
  30. To disassociate a nick with the account you're logged into:
  31. /NS DROP [nickname]
  32. Leave out [nickname] to drop your association with your current nickname.`
  33. // extractParam extracts a parameter from the given string, returning the param and the rest of the string.
  34. func extractParam(line string) (string, string) {
  35. rawParams := strings.SplitN(strings.TrimSpace(line), " ", 2)
  36. param0 := rawParams[0]
  37. var param1 string
  38. if 1 < len(rawParams) {
  39. param1 = strings.TrimSpace(rawParams[1])
  40. }
  41. return param0, param1
  42. }
  43. // nickservNoticeHandler handles NOTICEs that NickServ receives.
  44. func (server *Server) nickservNoticeHandler(client *Client, message string, rb *ResponseBuffer) {
  45. // do nothing
  46. }
  47. // send a notice from the NickServ "nick"
  48. func nsNotice(rb *ResponseBuffer, text string) {
  49. rb.Add(nil, "NickServ", "NOTICE", rb.target.Nick(), text)
  50. }
  51. // nickservPrivmsgHandler handles PRIVMSGs that NickServ receives.
  52. func (server *Server) nickservPrivmsgHandler(client *Client, message string, rb *ResponseBuffer) {
  53. command, params := extractParam(message)
  54. command = strings.ToLower(command)
  55. if command == "help" {
  56. for _, line := range strings.Split(nickservHelp, "\n") {
  57. nsNotice(rb, line)
  58. }
  59. } else if command == "register" {
  60. // get params
  61. username, afterUsername := extractParam(params)
  62. email, passphrase := extractParam(afterUsername)
  63. server.nickservRegisterHandler(client, username, email, passphrase, rb)
  64. } else if command == "verify" {
  65. username, code := extractParam(params)
  66. server.nickservVerifyHandler(client, username, code, rb)
  67. } else if command == "identify" {
  68. username, passphrase := extractParam(params)
  69. server.nickservIdentifyHandler(client, username, passphrase, rb)
  70. } else if command == "unregister" {
  71. username, _ := extractParam(params)
  72. server.nickservUnregisterHandler(client, username, rb)
  73. } else if command == "ghost" {
  74. nick, _ := extractParam(params)
  75. server.nickservGhostHandler(client, nick, rb)
  76. } else if command == "info" {
  77. nick, _ := extractParam(params)
  78. server.nickservInfoHandler(client, nick, rb)
  79. } else if command == "group" {
  80. server.nickservGroupHandler(client, rb)
  81. } else if command == "drop" {
  82. nick, _ := extractParam(params)
  83. server.nickservDropHandler(client, nick, false, rb)
  84. } else if command == "sadrop" {
  85. nick, _ := extractParam(params)
  86. server.nickservDropHandler(client, nick, true, rb)
  87. } else {
  88. nsNotice(rb, client.t("Command not recognised. To see the available commands, run /NS HELP"))
  89. }
  90. }
  91. func (server *Server) nickservUnregisterHandler(client *Client, username string, rb *ResponseBuffer) {
  92. if !server.AccountConfig().Registration.Enabled {
  93. nsNotice(rb, client.t("Account registration has been disabled"))
  94. return
  95. }
  96. if username == "" {
  97. username = client.Account()
  98. }
  99. if username == "" {
  100. nsNotice(rb, client.t("You're not logged into an account"))
  101. return
  102. }
  103. cfname, err := CasefoldName(username)
  104. if err != nil {
  105. nsNotice(rb, client.t("Invalid username"))
  106. return
  107. }
  108. if !(cfname == client.Account() || client.HasRoleCapabs("unregister")) {
  109. nsNotice(rb, client.t("Insufficient oper privs"))
  110. return
  111. }
  112. if cfname == client.Account() {
  113. client.server.accounts.Logout(client)
  114. }
  115. err = server.accounts.Unregister(cfname)
  116. if err == errAccountDoesNotExist {
  117. nsNotice(rb, client.t(err.Error()))
  118. } else if err != nil {
  119. nsNotice(rb, client.t("Error while unregistering account"))
  120. } else {
  121. nsNotice(rb, fmt.Sprintf(client.t("Successfully unregistered account %s"), cfname))
  122. }
  123. }
  124. func (server *Server) nickservVerifyHandler(client *Client, username string, code string, rb *ResponseBuffer) {
  125. err := server.accounts.Verify(client, username, code)
  126. var errorMessage string
  127. if err == errAccountVerificationInvalidCode || err == errAccountAlreadyVerified {
  128. errorMessage = err.Error()
  129. } else if err != nil {
  130. errorMessage = errAccountVerificationFailed.Error()
  131. }
  132. if errorMessage != "" {
  133. nsNotice(rb, client.t(errorMessage))
  134. return
  135. }
  136. sendSuccessfulRegResponse(client, rb, true)
  137. }
  138. func (server *Server) nickservRegisterHandler(client *Client, username, email, passphrase string, rb *ResponseBuffer) {
  139. if !server.AccountConfig().Registration.Enabled {
  140. nsNotice(rb, client.t("Account registration has been disabled"))
  141. return
  142. }
  143. if username == "" {
  144. nsNotice(rb, client.t("No username supplied"))
  145. return
  146. }
  147. certfp := client.certfp
  148. if passphrase == "" && certfp == "" {
  149. nsNotice(rb, client.t("You need to either supply a passphrase or be connected via TLS with a client cert"))
  150. return
  151. }
  152. if client.LoggedIntoAccount() {
  153. if server.AccountConfig().Registration.AllowMultiplePerConnection {
  154. server.accounts.Logout(client)
  155. } else {
  156. nsNotice(rb, client.t("You're already logged into an account"))
  157. return
  158. }
  159. }
  160. config := server.AccountConfig()
  161. var callbackNamespace, callbackValue string
  162. noneCallbackAllowed := false
  163. for _, callback := range config.Registration.EnabledCallbacks {
  164. if callback == "*" {
  165. noneCallbackAllowed = true
  166. }
  167. }
  168. // XXX if ACC REGISTER allows registration with the `none` callback, then ignore
  169. // any callback that was passed here (to avoid confusion in the case where the ircd
  170. // has no mail server configured). otherwise, register using the provided callback:
  171. if noneCallbackAllowed {
  172. callbackNamespace = "*"
  173. } else {
  174. callbackNamespace, callbackValue = parseCallback(email, config)
  175. if callbackNamespace == "" {
  176. nsNotice(rb, client.t("Registration requires a valid e-mail address"))
  177. return
  178. }
  179. }
  180. // get and sanitise account name
  181. account := strings.TrimSpace(username)
  182. err := server.accounts.Register(client, account, callbackNamespace, callbackValue, passphrase, client.certfp)
  183. if err == nil {
  184. if callbackNamespace == "*" {
  185. err = server.accounts.Verify(client, account, "")
  186. if err == nil {
  187. sendSuccessfulRegResponse(client, rb, true)
  188. }
  189. } else {
  190. messageTemplate := client.t("Account created, pending verification; verification code has been sent to %s:%s")
  191. message := fmt.Sprintf(messageTemplate, callbackNamespace, callbackValue)
  192. nsNotice(rb, message)
  193. }
  194. }
  195. // details could not be stored and relevant numerics have been dispatched, abort
  196. if err != nil {
  197. errMsg := "Could not register"
  198. if err == errCertfpAlreadyExists {
  199. errMsg = "An account already exists for your certificate fingerprint"
  200. } else if err == errAccountAlreadyRegistered {
  201. errMsg = "Account already exists"
  202. }
  203. nsNotice(rb, client.t(errMsg))
  204. return
  205. }
  206. }
  207. func (server *Server) nickservIdentifyHandler(client *Client, username, passphrase string, rb *ResponseBuffer) {
  208. // fail out if we need to
  209. if !server.AccountConfig().AuthenticationEnabled {
  210. nsNotice(rb, client.t("Login has been disabled"))
  211. return
  212. }
  213. loginSuccessful := false
  214. // try passphrase
  215. if username != "" && passphrase != "" {
  216. err := server.accounts.AuthenticateByPassphrase(client, username, passphrase)
  217. loginSuccessful = (err == nil)
  218. }
  219. // try certfp
  220. if !loginSuccessful && client.certfp != "" {
  221. err := server.accounts.AuthenticateByCertFP(client)
  222. loginSuccessful = (err == nil)
  223. }
  224. if loginSuccessful {
  225. sendSuccessfulSaslAuth(client, rb, true)
  226. } else {
  227. nsNotice(rb, client.t("Could not login with your TLS certificate or supplied username/password"))
  228. }
  229. }
  230. func (server *Server) nickservGhostHandler(client *Client, nick string, rb *ResponseBuffer) {
  231. if !server.AccountConfig().NickReservation.Enabled {
  232. nsNotice(rb, client.t("Nickname reservation is disabled"))
  233. return
  234. }
  235. account := client.Account()
  236. if account == "" || server.accounts.NickToAccount(nick) != account {
  237. nsNotice(rb, client.t("You don't own that nick"))
  238. return
  239. }
  240. ghost := server.clients.Get(nick)
  241. if ghost == nil {
  242. nsNotice(rb, client.t("No such nick"))
  243. return
  244. } else if ghost == client {
  245. nsNotice(rb, client.t("You can't GHOST yourself (try /QUIT instead)"))
  246. return
  247. }
  248. ghost.Quit(fmt.Sprintf(ghost.t("GHOSTed by %s"), client.Nick()))
  249. ghost.destroy(false)
  250. }
  251. func (server *Server) nickservGroupHandler(client *Client, rb *ResponseBuffer) {
  252. if !server.AccountConfig().NickReservation.Enabled {
  253. nsNotice(rb, client.t("Nickname reservation is disabled"))
  254. return
  255. }
  256. account := client.Account()
  257. if account == "" {
  258. nsNotice(rb, client.t("You're not logged into an account"))
  259. return
  260. }
  261. nick := client.NickCasefolded()
  262. err := server.accounts.SetNickReserved(client, nick, false, true)
  263. if err == nil {
  264. nsNotice(rb, fmt.Sprintf(client.t("Successfully grouped nick %s with your account"), nick))
  265. } else if err == errAccountTooManyNicks {
  266. nsNotice(rb, client.t("You have too many nicks reserved already (you can remove some with /NS DROP)"))
  267. } else if err == errNicknameReserved {
  268. nsNotice(rb, client.t("That nickname is already reserved by someone else"))
  269. } else {
  270. nsNotice(rb, client.t("Error reserving nickname"))
  271. }
  272. }
  273. func (server *Server) nickservInfoHandler(client *Client, nick string, rb *ResponseBuffer) {
  274. if nick == "" {
  275. nick = client.Nick()
  276. }
  277. accountName := nick
  278. if server.AccountConfig().NickReservation.Enabled {
  279. accountName = server.accounts.NickToAccount(nick)
  280. if accountName == "" {
  281. nsNotice(rb, client.t("That nickname is not registered"))
  282. return
  283. }
  284. }
  285. account, err := server.accounts.LoadAccount(accountName)
  286. if err != nil || !account.Verified {
  287. nsNotice(rb, client.t("Account does not exist"))
  288. }
  289. nsNotice(rb, fmt.Sprintf(client.t("Account: %s"), account.Name))
  290. registeredAt := account.RegisteredAt.Format("Jan 02, 2006 15:04:05Z")
  291. nsNotice(rb, fmt.Sprintf(client.t("Registered at: %s"), registeredAt))
  292. // TODO nicer formatting for this
  293. for _, nick := range account.AdditionalNicks {
  294. nsNotice(rb, fmt.Sprintf(client.t("Additional grouped nick: %s"), nick))
  295. }
  296. }
  297. func (server *Server) nickservDropHandler(client *Client, nick string, sadrop bool, rb *ResponseBuffer) {
  298. if sadrop {
  299. if !client.HasRoleCapabs("unregister") {
  300. nsNotice(rb, client.t("Insufficient oper privs"))
  301. return
  302. }
  303. }
  304. err := server.accounts.SetNickReserved(client, nick, sadrop, false)
  305. if err == nil {
  306. nsNotice(rb, fmt.Sprintf(client.t("Successfully ungrouped nick %s with your account"), nick))
  307. } else if err == errAccountNotLoggedIn {
  308. nsNotice(rb, fmt.Sprintf(client.t("You're not logged into an account")))
  309. } else if err == errAccountCantDropPrimaryNick {
  310. nsNotice(rb, fmt.Sprintf(client.t("You can't ungroup your primary nickname (try unregistering your account instead)")))
  311. } else if err == errNicknameReserved {
  312. nsNotice(rb, fmt.Sprintf(client.t("That nickname is already reserved by someone else")))
  313. } else {
  314. nsNotice(rb, client.t("Error ungrouping nick"))
  315. }
  316. }