You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

nickserv.go 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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. // extractParam extracts a parameter from the given string, returning the param and the rest of the string.
  26. func extractParam(line string) (string, string) {
  27. rawParams := strings.SplitN(strings.TrimSpace(line), " ", 2)
  28. param0 := rawParams[0]
  29. var param1 string
  30. if 1 < len(rawParams) {
  31. param1 = strings.TrimSpace(rawParams[1])
  32. }
  33. return param0, param1
  34. }
  35. // nickservNoticeHandler handles NOTICEs that NickServ receives.
  36. func (server *Server) nickservNoticeHandler(client *Client, message string, rb *ResponseBuffer) {
  37. // do nothing
  38. }
  39. // nickservPrivmsgHandler handles PRIVMSGs that NickServ receives.
  40. func (server *Server) nickservPrivmsgHandler(client *Client, message string, rb *ResponseBuffer) {
  41. command, params := extractParam(message)
  42. command = strings.ToLower(command)
  43. if command == "help" {
  44. for _, line := range strings.Split(nickservHelp, "\n") {
  45. rb.Notice(line)
  46. }
  47. } else if command == "register" {
  48. // get params
  49. username, afterUsername := extractParam(params)
  50. email, passphrase := extractParam(afterUsername)
  51. server.nickservRegisterHandler(client, username, email, passphrase, rb)
  52. } else if command == "verify" {
  53. username, code := extractParam(params)
  54. server.nickservVerifyHandler(client, username, code, rb)
  55. } else if command == "identify" {
  56. username, passphrase := extractParam(params)
  57. server.nickservIdentifyHandler(client, username, passphrase, rb)
  58. } else if command == "unregister" {
  59. username, _ := extractParam(params)
  60. server.nickservUnregisterHandler(client, username, rb)
  61. } else {
  62. rb.Notice(client.t("Command not recognised. To see the available commands, run /NS HELP"))
  63. }
  64. }
  65. func (server *Server) nickservUnregisterHandler(client *Client, username string, rb *ResponseBuffer) {
  66. if !server.AccountConfig().Registration.Enabled {
  67. rb.Notice(client.t("Account registration has been disabled"))
  68. return
  69. }
  70. if username == "" {
  71. username = client.Account()
  72. }
  73. if username == "" {
  74. rb.Notice(client.t("You're not logged into an account"))
  75. return
  76. }
  77. cfname, err := CasefoldName(username)
  78. if err != nil {
  79. rb.Notice(client.t("Invalid username"))
  80. return
  81. }
  82. if !(cfname == client.Account() || client.HasRoleCapabs("unregister")) {
  83. rb.Notice(client.t("Insufficient oper privs"))
  84. return
  85. }
  86. if cfname == client.Account() {
  87. client.server.accounts.Logout(client)
  88. }
  89. err = server.accounts.Unregister(cfname)
  90. if err == errAccountDoesNotExist {
  91. rb.Notice(client.t(err.Error()))
  92. } else if err != nil {
  93. rb.Notice(client.t("Error while unregistering account"))
  94. } else {
  95. rb.Notice(fmt.Sprintf(client.t("Successfully unregistered account %s"), cfname))
  96. }
  97. }
  98. func (server *Server) nickservVerifyHandler(client *Client, username string, code string, rb *ResponseBuffer) {
  99. err := server.accounts.Verify(client, username, code)
  100. var errorMessage string
  101. if err == errAccountVerificationInvalidCode || err == errAccountAlreadyVerified {
  102. errorMessage = err.Error()
  103. } else if err != nil {
  104. errorMessage = errAccountVerificationFailed.Error()
  105. }
  106. if errorMessage != "" {
  107. rb.Notice(client.t(errorMessage))
  108. return
  109. }
  110. sendSuccessfulRegResponse(client, rb, true)
  111. }
  112. func (server *Server) nickservRegisterHandler(client *Client, username, email, passphrase string, rb *ResponseBuffer) {
  113. if !server.AccountConfig().Registration.Enabled {
  114. rb.Notice(client.t("Account registration has been disabled"))
  115. return
  116. }
  117. if username == "" {
  118. rb.Notice(client.t("No username supplied"))
  119. return
  120. }
  121. certfp := client.certfp
  122. if passphrase == "" && certfp == "" {
  123. rb.Notice(client.t("You need to either supply a passphrase or be connected via TLS with a client cert"))
  124. return
  125. }
  126. if client.LoggedIntoAccount() {
  127. if server.AccountConfig().Registration.AllowMultiplePerConnection {
  128. server.accounts.Logout(client)
  129. } else {
  130. rb.Notice(client.t("You're already logged into an account"))
  131. return
  132. }
  133. }
  134. config := server.AccountConfig()
  135. var callbackNamespace, callbackValue string
  136. noneCallbackAllowed := false
  137. for _, callback := range(config.Registration.EnabledCallbacks) {
  138. if callback == "*" {
  139. noneCallbackAllowed = true
  140. }
  141. }
  142. // XXX if ACC REGISTER allows registration with the `none` callback, then ignore
  143. // any callback that was passed here (to avoid confusion in the case where the ircd
  144. // has no mail server configured). otherwise, register using the provided callback:
  145. if noneCallbackAllowed {
  146. callbackNamespace = "*"
  147. } else {
  148. callbackNamespace, callbackValue = parseCallback(email, config)
  149. if callbackNamespace == "" {
  150. rb.Notice(client.t("Registration requires a valid e-mail address"))
  151. return
  152. }
  153. }
  154. // get and sanitise account name
  155. account := strings.TrimSpace(username)
  156. err := server.accounts.Register(client, account, callbackNamespace, callbackValue, passphrase, client.certfp)
  157. if err == nil {
  158. if callbackNamespace == "*" {
  159. err = server.accounts.Verify(client, account, "")
  160. if err == nil {
  161. sendSuccessfulRegResponse(client, rb, true)
  162. }
  163. } else {
  164. messageTemplate := client.t("Account created, pending verification; verification code has been sent to %s:%s")
  165. message := fmt.Sprintf(messageTemplate, callbackNamespace, callbackValue)
  166. rb.Notice(message)
  167. }
  168. }
  169. // details could not be stored and relevant numerics have been dispatched, abort
  170. if err != nil {
  171. errMsg := "Could not register"
  172. if err == errCertfpAlreadyExists {
  173. errMsg = "An account already exists for your certificate fingerprint"
  174. } else if err == errAccountAlreadyRegistered {
  175. errMsg = "Account already exists"
  176. }
  177. rb.Notice(client.t(errMsg))
  178. return
  179. }
  180. }
  181. func (server *Server) nickservIdentifyHandler(client *Client, username, passphrase string, rb *ResponseBuffer) {
  182. // fail out if we need to
  183. if !server.AccountConfig().AuthenticationEnabled {
  184. rb.Notice(client.t("Login has been disabled"))
  185. return
  186. }
  187. loginSuccessful := false
  188. // try passphrase
  189. if username != "" && passphrase != "" {
  190. err := server.accounts.AuthenticateByPassphrase(client, username, passphrase)
  191. loginSuccessful = (err == nil)
  192. }
  193. // try certfp
  194. if !loginSuccessful && client.certfp != "" {
  195. err := server.accounts.AuthenticateByCertFP(client)
  196. loginSuccessful = (err == nil)
  197. }
  198. if loginSuccessful {
  199. sendSuccessfulSaslAuth(client, rb, true)
  200. } else {
  201. rb.Notice(client.t("Could not login with your TLS certificate or supplied username/password"))
  202. }
  203. }