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.

accounts.go 39KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318
  1. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "net/smtp"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. "sync/atomic"
  13. "time"
  14. "unicode"
  15. "github.com/oragono/oragono/irc/caps"
  16. "github.com/oragono/oragono/irc/passwd"
  17. "github.com/oragono/oragono/irc/utils"
  18. "github.com/tidwall/buntdb"
  19. )
  20. const (
  21. keyAccountExists = "account.exists %s"
  22. keyAccountVerified = "account.verified %s"
  23. keyAccountCallback = "account.callback %s"
  24. keyAccountVerificationCode = "account.verificationcode %s"
  25. keyAccountName = "account.name %s" // stores the 'preferred name' of the account, not casemapped
  26. keyAccountRegTime = "account.registered.time %s"
  27. keyAccountCredentials = "account.credentials %s"
  28. keyAccountAdditionalNicks = "account.additionalnicks %s"
  29. keyAccountEnforcement = "account.customenforcement %s"
  30. keyAccountVHost = "account.vhost %s"
  31. keyCertToAccount = "account.creds.certfp %s"
  32. keyAccountChannels = "account.channels %s"
  33. keyVHostQueueAcctToId = "vhostQueue %s"
  34. vhostRequestIdx = "vhostQueue"
  35. )
  36. // everything about accounts is persistent; therefore, the database is the authoritative
  37. // source of truth for all account information. anything on the heap is just a cache
  38. type AccountManager struct {
  39. // XXX these are up here so they can be aligned to a 64-bit boundary, please forgive me
  40. // autoincrementing ID for vhost requests:
  41. vhostRequestID uint64
  42. vhostRequestPendingCount uint64
  43. sync.RWMutex // tier 2
  44. serialCacheUpdateMutex sync.Mutex // tier 3
  45. vHostUpdateMutex sync.Mutex // tier 3
  46. server *Server
  47. // track clients logged in to accounts
  48. accountToClients map[string][]*Client
  49. nickToAccount map[string]string
  50. skeletonToAccount map[string]string
  51. accountToMethod map[string]NickReservationMethod
  52. }
  53. func (am *AccountManager) Initialize(server *Server) {
  54. am.accountToClients = make(map[string][]*Client)
  55. am.nickToAccount = make(map[string]string)
  56. am.skeletonToAccount = make(map[string]string)
  57. am.accountToMethod = make(map[string]NickReservationMethod)
  58. am.server = server
  59. am.buildNickToAccountIndex()
  60. am.initVHostRequestQueue()
  61. }
  62. func (am *AccountManager) buildNickToAccountIndex() {
  63. if !am.server.AccountConfig().NickReservation.Enabled {
  64. return
  65. }
  66. nickToAccount := make(map[string]string)
  67. skeletonToAccount := make(map[string]string)
  68. accountToMethod := make(map[string]NickReservationMethod)
  69. existsPrefix := fmt.Sprintf(keyAccountExists, "")
  70. am.serialCacheUpdateMutex.Lock()
  71. defer am.serialCacheUpdateMutex.Unlock()
  72. err := am.server.store.View(func(tx *buntdb.Tx) error {
  73. err := tx.AscendGreaterOrEqual("", existsPrefix, func(key, value string) bool {
  74. if !strings.HasPrefix(key, existsPrefix) {
  75. return false
  76. }
  77. account := strings.TrimPrefix(key, existsPrefix)
  78. if _, err := tx.Get(fmt.Sprintf(keyAccountVerified, account)); err == nil {
  79. nickToAccount[account] = account
  80. accountName, err := tx.Get(fmt.Sprintf(keyAccountName, account))
  81. if err != nil {
  82. am.server.logger.Error("internal", "missing account name for", account)
  83. } else {
  84. skeleton, _ := Skeleton(accountName)
  85. skeletonToAccount[skeleton] = account
  86. }
  87. }
  88. if rawNicks, err := tx.Get(fmt.Sprintf(keyAccountAdditionalNicks, account)); err == nil {
  89. additionalNicks := unmarshalReservedNicks(rawNicks)
  90. for _, nick := range additionalNicks {
  91. cfnick, _ := CasefoldName(nick)
  92. nickToAccount[cfnick] = account
  93. skeleton, _ := Skeleton(nick)
  94. skeletonToAccount[skeleton] = account
  95. }
  96. }
  97. if methodStr, err := tx.Get(fmt.Sprintf(keyAccountEnforcement, account)); err == nil {
  98. method, err := nickReservationFromString(methodStr)
  99. if err == nil {
  100. accountToMethod[account] = method
  101. }
  102. }
  103. return true
  104. })
  105. return err
  106. })
  107. if err != nil {
  108. am.server.logger.Error("internal", "couldn't read reserved nicks", err.Error())
  109. } else {
  110. am.Lock()
  111. am.nickToAccount = nickToAccount
  112. am.skeletonToAccount = skeletonToAccount
  113. am.accountToMethod = accountToMethod
  114. am.Unlock()
  115. }
  116. }
  117. func (am *AccountManager) initVHostRequestQueue() {
  118. if !am.server.AccountConfig().VHosts.Enabled {
  119. return
  120. }
  121. am.vHostUpdateMutex.Lock()
  122. defer am.vHostUpdateMutex.Unlock()
  123. // the db maps the account name to the autoincrementing integer ID of its request
  124. // create an numerically ordered index on ID, so we can list the oldest requests
  125. // finally, collect the integer id of the newest request and the total request count
  126. var total uint64
  127. var lastIDStr string
  128. err := am.server.store.Update(func(tx *buntdb.Tx) error {
  129. err := tx.CreateIndex(vhostRequestIdx, fmt.Sprintf(keyVHostQueueAcctToId, "*"), buntdb.IndexInt)
  130. if err != nil {
  131. return err
  132. }
  133. return tx.Descend(vhostRequestIdx, func(key, value string) bool {
  134. if lastIDStr == "" {
  135. lastIDStr = value
  136. }
  137. total++
  138. return true
  139. })
  140. })
  141. if err != nil {
  142. am.server.logger.Error("internal", "could not create vhost queue index", err.Error())
  143. }
  144. lastID, _ := strconv.ParseUint(lastIDStr, 10, 64)
  145. am.server.logger.Debug("services", fmt.Sprintf("vhost queue length is %d, autoincrementing id is %d", total, lastID))
  146. atomic.StoreUint64(&am.vhostRequestID, lastID)
  147. atomic.StoreUint64(&am.vhostRequestPendingCount, total)
  148. }
  149. func (am *AccountManager) NickToAccount(nick string) string {
  150. cfnick, err := CasefoldName(nick)
  151. if err != nil {
  152. return ""
  153. }
  154. am.RLock()
  155. defer am.RUnlock()
  156. return am.nickToAccount[cfnick]
  157. }
  158. // Given a nick, looks up the account that owns it and the method (none/timeout/strict)
  159. // used to enforce ownership.
  160. func (am *AccountManager) EnforcementStatus(cfnick, skeleton string) (account string, method NickReservationMethod) {
  161. config := am.server.Config()
  162. if !config.Accounts.NickReservation.Enabled {
  163. return "", NickReservationNone
  164. }
  165. am.RLock()
  166. defer am.RUnlock()
  167. // given an account, combine stored enforcement method with the config settings
  168. // to compute the actual enforcement method
  169. finalEnforcementMethod := func(account_ string) (result NickReservationMethod) {
  170. result = am.accountToMethod[account_]
  171. // if they don't have a custom setting, or customization is disabled, use the default
  172. if result == NickReservationOptional || !config.Accounts.NickReservation.AllowCustomEnforcement {
  173. result = config.Accounts.NickReservation.Method
  174. }
  175. if result == NickReservationOptional {
  176. // enforcement was explicitly enabled neither in the config or by the user
  177. result = NickReservationNone
  178. }
  179. return
  180. }
  181. nickAccount := am.nickToAccount[cfnick]
  182. skelAccount := am.skeletonToAccount[skeleton]
  183. if nickAccount == "" && skelAccount == "" {
  184. return "", NickReservationNone
  185. } else if nickAccount != "" && (skelAccount == nickAccount || skelAccount == "") {
  186. return nickAccount, finalEnforcementMethod(nickAccount)
  187. } else if skelAccount != "" && nickAccount == "" {
  188. return skelAccount, finalEnforcementMethod(skelAccount)
  189. } else {
  190. // nickAccount != skelAccount and both are nonempty:
  191. // two people have competing claims on (this casefolding of) this nick!
  192. nickMethod := finalEnforcementMethod(nickAccount)
  193. skelMethod := finalEnforcementMethod(skelAccount)
  194. switch {
  195. case nickMethod == NickReservationNone && skelMethod == NickReservationNone:
  196. return nickAccount, NickReservationNone
  197. case skelMethod == NickReservationNone:
  198. return nickAccount, nickMethod
  199. case nickMethod == NickReservationNone:
  200. return skelAccount, skelMethod
  201. default:
  202. // nobody can use this nick
  203. return "!", NickReservationStrict
  204. }
  205. }
  206. }
  207. // Looks up the enforcement method stored in the database for an account
  208. // (typically you want EnforcementStatus instead, which respects the config)
  209. func (am *AccountManager) getStoredEnforcementStatus(account string) string {
  210. am.RLock()
  211. defer am.RUnlock()
  212. return nickReservationToString(am.accountToMethod[account])
  213. }
  214. // Sets a custom enforcement method for an account and stores it in the database.
  215. func (am *AccountManager) SetEnforcementStatus(account string, method NickReservationMethod) (err error) {
  216. config := am.server.Config()
  217. if !(config.Accounts.NickReservation.Enabled && config.Accounts.NickReservation.AllowCustomEnforcement) {
  218. return errFeatureDisabled
  219. }
  220. var serialized string
  221. if method == NickReservationOptional {
  222. serialized = "" // normally this is "default", but we're going to delete the key
  223. } else {
  224. serialized = nickReservationToString(method)
  225. }
  226. key := fmt.Sprintf(keyAccountEnforcement, account)
  227. am.Lock()
  228. defer am.Unlock()
  229. currentMethod := am.accountToMethod[account]
  230. if method != currentMethod {
  231. if method == NickReservationOptional {
  232. delete(am.accountToMethod, account)
  233. } else {
  234. am.accountToMethod[account] = method
  235. }
  236. return am.server.store.Update(func(tx *buntdb.Tx) (err error) {
  237. if serialized != "" {
  238. _, _, err = tx.Set(key, nickReservationToString(method), nil)
  239. } else {
  240. _, err = tx.Delete(key)
  241. }
  242. return
  243. })
  244. }
  245. return nil
  246. }
  247. func (am *AccountManager) AccountToClients(account string) (result []*Client) {
  248. cfaccount, err := CasefoldName(account)
  249. if err != nil {
  250. return
  251. }
  252. am.RLock()
  253. defer am.RUnlock()
  254. return am.accountToClients[cfaccount]
  255. }
  256. func (am *AccountManager) Register(client *Client, account string, callbackNamespace string, callbackValue string, passphrase string, certfp string) error {
  257. casefoldedAccount, err := CasefoldName(account)
  258. skeleton, skerr := Skeleton(account)
  259. if err != nil || skerr != nil || account == "" || account == "*" {
  260. return errAccountCreation
  261. }
  262. if restrictedNicknames[casefoldedAccount] || restrictedNicknames[skeleton] {
  263. return errAccountAlreadyRegistered
  264. }
  265. config := am.server.AccountConfig()
  266. // final "is registration allowed" check, probably redundant:
  267. if !(config.Registration.Enabled || callbackNamespace == "admin") {
  268. return errFeatureDisabled
  269. }
  270. // if nick reservation is enabled, you can only register your current nickname
  271. // as an account; this prevents "land-grab" situations where someone else
  272. // registers your nick out from under you and then NS GHOSTs you
  273. // n.b. client is nil during a SAREGISTER:
  274. if config.NickReservation.Enabled && client != nil && client.NickCasefolded() != casefoldedAccount {
  275. return errAccountMustHoldNick
  276. }
  277. // can't register a guest nickname
  278. renamePrefix := strings.ToLower(config.NickReservation.RenamePrefix)
  279. if renamePrefix != "" && strings.HasPrefix(casefoldedAccount, renamePrefix) {
  280. return errAccountAlreadyRegistered
  281. }
  282. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  283. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  284. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  285. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  286. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  287. verificationCodeKey := fmt.Sprintf(keyAccountVerificationCode, casefoldedAccount)
  288. certFPKey := fmt.Sprintf(keyCertToAccount, certfp)
  289. credStr, err := am.serializeCredentials(passphrase, certfp)
  290. if err != nil {
  291. return err
  292. }
  293. registeredTimeStr := strconv.FormatInt(time.Now().Unix(), 10)
  294. callbackSpec := fmt.Sprintf("%s:%s", callbackNamespace, callbackValue)
  295. var setOptions *buntdb.SetOptions
  296. ttl := config.Registration.VerifyTimeout
  297. if ttl != 0 {
  298. setOptions = &buntdb.SetOptions{Expires: true, TTL: ttl}
  299. }
  300. err = func() error {
  301. am.serialCacheUpdateMutex.Lock()
  302. defer am.serialCacheUpdateMutex.Unlock()
  303. // can't register an account with the same name as a registered nick
  304. if am.NickToAccount(casefoldedAccount) != "" {
  305. return errAccountAlreadyRegistered
  306. }
  307. return am.server.store.Update(func(tx *buntdb.Tx) error {
  308. _, err := am.loadRawAccount(tx, casefoldedAccount)
  309. if err != errAccountDoesNotExist {
  310. return errAccountAlreadyRegistered
  311. }
  312. if certfp != "" {
  313. // make sure certfp doesn't already exist because that'd be silly
  314. _, err := tx.Get(certFPKey)
  315. if err != buntdb.ErrNotFound {
  316. return errCertfpAlreadyExists
  317. }
  318. }
  319. tx.Set(accountKey, "1", setOptions)
  320. tx.Set(accountNameKey, account, setOptions)
  321. tx.Set(registeredTimeKey, registeredTimeStr, setOptions)
  322. tx.Set(credentialsKey, credStr, setOptions)
  323. tx.Set(callbackKey, callbackSpec, setOptions)
  324. if certfp != "" {
  325. tx.Set(certFPKey, casefoldedAccount, setOptions)
  326. }
  327. return nil
  328. })
  329. }()
  330. if err != nil {
  331. return err
  332. }
  333. code, err := am.dispatchCallback(client, casefoldedAccount, callbackNamespace, callbackValue)
  334. if err != nil {
  335. am.Unregister(casefoldedAccount)
  336. return errCallbackFailed
  337. } else {
  338. return am.server.store.Update(func(tx *buntdb.Tx) error {
  339. _, _, err = tx.Set(verificationCodeKey, code, setOptions)
  340. return err
  341. })
  342. }
  343. }
  344. // validatePassphrase checks whether a passphrase is allowed by our rules
  345. func validatePassphrase(passphrase string) error {
  346. // sanity check the length
  347. if len(passphrase) == 0 || len(passphrase) > 600 {
  348. return errAccountBadPassphrase
  349. }
  350. // for now, just enforce that spaces are not allowed
  351. for _, r := range passphrase {
  352. if unicode.IsSpace(r) {
  353. return errAccountBadPassphrase
  354. }
  355. }
  356. return nil
  357. }
  358. // helper to assemble the serialized JSON for an account's credentials
  359. func (am *AccountManager) serializeCredentials(passphrase string, certfp string) (result string, err error) {
  360. var creds AccountCredentials
  361. creds.Version = 1
  362. // we need at least one of passphrase and certfp:
  363. if passphrase == "" && certfp == "" {
  364. return "", errAccountBadPassphrase
  365. }
  366. // but if we have one, it's fine if the other is missing, it just means no
  367. // credential of that type will be accepted.
  368. creds.Certificate = certfp
  369. if passphrase != "" {
  370. if validatePassphrase(passphrase) != nil {
  371. return "", errAccountBadPassphrase
  372. }
  373. bcryptCost := int(am.server.Config().Accounts.Registration.BcryptCost)
  374. creds.PassphraseHash, err = passwd.GenerateFromPassword([]byte(passphrase), bcryptCost)
  375. if err != nil {
  376. am.server.logger.Error("internal", "could not hash password", err.Error())
  377. return "", errAccountCreation
  378. }
  379. }
  380. credText, err := json.Marshal(creds)
  381. if err != nil {
  382. am.server.logger.Error("internal", "could not marshal credentials", err.Error())
  383. return "", errAccountCreation
  384. }
  385. return string(credText), nil
  386. }
  387. // changes the password for an account
  388. func (am *AccountManager) setPassword(account string, password string) (err error) {
  389. casefoldedAccount, err := CasefoldName(account)
  390. if err != nil {
  391. return err
  392. }
  393. act, err := am.LoadAccount(casefoldedAccount)
  394. if err != nil {
  395. return err
  396. }
  397. credStr, err := am.serializeCredentials(password, act.Credentials.Certificate)
  398. if err != nil {
  399. return err
  400. }
  401. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  402. return am.server.store.Update(func(tx *buntdb.Tx) error {
  403. _, _, err := tx.Set(credentialsKey, credStr, nil)
  404. return err
  405. })
  406. }
  407. func (am *AccountManager) dispatchCallback(client *Client, casefoldedAccount string, callbackNamespace string, callbackValue string) (string, error) {
  408. if callbackNamespace == "*" || callbackNamespace == "none" || callbackNamespace == "admin" {
  409. return "", nil
  410. } else if callbackNamespace == "mailto" {
  411. return am.dispatchMailtoCallback(client, casefoldedAccount, callbackValue)
  412. } else {
  413. return "", errors.New(fmt.Sprintf("Callback not implemented: %s", callbackNamespace))
  414. }
  415. }
  416. func (am *AccountManager) dispatchMailtoCallback(client *Client, casefoldedAccount string, callbackValue string) (code string, err error) {
  417. config := am.server.AccountConfig().Registration.Callbacks.Mailto
  418. code = utils.GenerateSecretToken()
  419. subject := config.VerifyMessageSubject
  420. if subject == "" {
  421. subject = fmt.Sprintf(client.t("Verify your account on %s"), am.server.name)
  422. }
  423. messageStrings := []string{
  424. fmt.Sprintf("From: %s\r\n", config.Sender),
  425. fmt.Sprintf("To: %s\r\n", callbackValue),
  426. fmt.Sprintf("Subject: %s\r\n", subject),
  427. "\r\n", // end headers, begin message body
  428. fmt.Sprintf(client.t("Account: %s"), casefoldedAccount) + "\r\n",
  429. fmt.Sprintf(client.t("Verification code: %s"), code) + "\r\n",
  430. "\r\n",
  431. client.t("To verify your account, issue one of these commands:") + "\r\n",
  432. fmt.Sprintf("/MSG NickServ VERIFY %s %s", casefoldedAccount, code) + "\r\n",
  433. }
  434. var message []byte
  435. for i := 0; i < len(messageStrings); i++ {
  436. message = append(message, []byte(messageStrings[i])...)
  437. }
  438. addr := fmt.Sprintf("%s:%d", config.Server, config.Port)
  439. var auth smtp.Auth
  440. if config.Username != "" && config.Password != "" {
  441. auth = smtp.PlainAuth("", config.Username, config.Password, config.Server)
  442. }
  443. // TODO: this will never send the password in plaintext over a nonlocal link,
  444. // but it might send the email in plaintext, regardless of the value of
  445. // config.TLS.InsecureSkipVerify
  446. err = smtp.SendMail(addr, auth, config.Sender, []string{callbackValue}, message)
  447. if err != nil {
  448. am.server.logger.Error("internal", "Failed to dispatch e-mail", err.Error())
  449. }
  450. return
  451. }
  452. func (am *AccountManager) Verify(client *Client, account string, code string) error {
  453. casefoldedAccount, err := CasefoldName(account)
  454. if err != nil || account == "" || account == "*" {
  455. return errAccountVerificationFailed
  456. }
  457. verifiedKey := fmt.Sprintf(keyAccountVerified, casefoldedAccount)
  458. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  459. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  460. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  461. verificationCodeKey := fmt.Sprintf(keyAccountVerificationCode, casefoldedAccount)
  462. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  463. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  464. var raw rawClientAccount
  465. func() {
  466. am.serialCacheUpdateMutex.Lock()
  467. defer am.serialCacheUpdateMutex.Unlock()
  468. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  469. raw, err = am.loadRawAccount(tx, casefoldedAccount)
  470. if err == errAccountDoesNotExist {
  471. return errAccountDoesNotExist
  472. } else if err != nil {
  473. return errAccountVerificationFailed
  474. } else if raw.Verified {
  475. return errAccountAlreadyVerified
  476. }
  477. // actually verify the code
  478. // a stored code of "" means a none callback / no code required
  479. success := false
  480. storedCode, err := tx.Get(verificationCodeKey)
  481. if err == nil {
  482. // this is probably unnecessary
  483. if storedCode == "" || utils.SecretTokensMatch(storedCode, code) {
  484. success = true
  485. }
  486. }
  487. if !success {
  488. return errAccountVerificationInvalidCode
  489. }
  490. // verify the account
  491. tx.Set(verifiedKey, "1", nil)
  492. // don't need the code anymore
  493. tx.Delete(verificationCodeKey)
  494. // re-set all other keys, removing the TTL
  495. tx.Set(accountKey, "1", nil)
  496. tx.Set(accountNameKey, raw.Name, nil)
  497. tx.Set(registeredTimeKey, raw.RegisteredAt, nil)
  498. tx.Set(callbackKey, raw.Callback, nil)
  499. tx.Set(credentialsKey, raw.Credentials, nil)
  500. var creds AccountCredentials
  501. // XXX we shouldn't do (de)serialization inside the txn,
  502. // but this is like 2 usec on my system
  503. json.Unmarshal([]byte(raw.Credentials), &creds)
  504. if creds.Certificate != "" {
  505. certFPKey := fmt.Sprintf(keyCertToAccount, creds.Certificate)
  506. tx.Set(certFPKey, casefoldedAccount, nil)
  507. }
  508. return nil
  509. })
  510. if err == nil {
  511. skeleton, _ := Skeleton(raw.Name)
  512. am.Lock()
  513. am.nickToAccount[casefoldedAccount] = casefoldedAccount
  514. am.skeletonToAccount[skeleton] = casefoldedAccount
  515. am.Unlock()
  516. }
  517. }()
  518. if err != nil {
  519. return err
  520. }
  521. nick := "[server admin]"
  522. if client != nil {
  523. nick = client.Nick()
  524. }
  525. am.server.logger.Info("accounts", "client", nick, "registered account", casefoldedAccount)
  526. raw.Verified = true
  527. clientAccount, err := am.deserializeRawAccount(raw)
  528. if err != nil {
  529. return err
  530. }
  531. if client != nil {
  532. am.Login(client, clientAccount)
  533. }
  534. return nil
  535. }
  536. func marshalReservedNicks(nicks []string) string {
  537. return strings.Join(nicks, ",")
  538. }
  539. func unmarshalReservedNicks(nicks string) (result []string) {
  540. if nicks == "" {
  541. return
  542. }
  543. return strings.Split(nicks, ",")
  544. }
  545. func (am *AccountManager) SetNickReserved(client *Client, nick string, saUnreserve bool, reserve bool) error {
  546. cfnick, err := CasefoldName(nick)
  547. skeleton, skerr := Skeleton(nick)
  548. // garbage nick, or garbage options, or disabled
  549. nrconfig := am.server.AccountConfig().NickReservation
  550. if err != nil || skerr != nil || cfnick == "" || (reserve && saUnreserve) || !nrconfig.Enabled {
  551. return errAccountNickReservationFailed
  552. }
  553. // the cache is in sync with the DB while we hold serialCacheUpdateMutex
  554. am.serialCacheUpdateMutex.Lock()
  555. defer am.serialCacheUpdateMutex.Unlock()
  556. // find the affected account, which is usually the client's:
  557. account := client.Account()
  558. if saUnreserve {
  559. // unless this is a sadrop:
  560. account = am.NickToAccount(cfnick)
  561. if account == "" {
  562. // nothing to do
  563. return nil
  564. }
  565. }
  566. if account == "" {
  567. return errAccountNotLoggedIn
  568. }
  569. am.Lock()
  570. accountForNick := am.nickToAccount[cfnick]
  571. var accountForSkeleton string
  572. if reserve {
  573. accountForSkeleton = am.skeletonToAccount[skeleton]
  574. }
  575. am.Unlock()
  576. if reserve && (accountForNick != "" || accountForSkeleton != "") {
  577. return errNicknameReserved
  578. } else if !reserve && !saUnreserve && accountForNick != account {
  579. return errNicknameReserved
  580. } else if !reserve && cfnick == account {
  581. return errAccountCantDropPrimaryNick
  582. }
  583. nicksKey := fmt.Sprintf(keyAccountAdditionalNicks, account)
  584. unverifiedAccountKey := fmt.Sprintf(keyAccountExists, cfnick)
  585. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  586. if reserve {
  587. // unverified accounts don't show up in NickToAccount yet (which is intentional),
  588. // however you shouldn't be able to reserve a nick out from under them
  589. _, err := tx.Get(unverifiedAccountKey)
  590. if err == nil {
  591. return errNicknameReserved
  592. }
  593. }
  594. rawNicks, err := tx.Get(nicksKey)
  595. if err != nil && err != buntdb.ErrNotFound {
  596. return err
  597. }
  598. nicks := unmarshalReservedNicks(rawNicks)
  599. if reserve {
  600. if len(nicks) >= nrconfig.AdditionalNickLimit {
  601. return errAccountTooManyNicks
  602. }
  603. nicks = append(nicks, nick)
  604. } else {
  605. // compute (original reserved nicks) minus cfnick
  606. var newNicks []string
  607. for _, reservedNick := range nicks {
  608. cfreservednick, _ := CasefoldName(reservedNick)
  609. if cfreservednick != cfnick {
  610. newNicks = append(newNicks, reservedNick)
  611. } else {
  612. // found the original, unfolded version of the nick we're dropping;
  613. // recompute the true skeleton from it
  614. skeleton, _ = Skeleton(reservedNick)
  615. }
  616. }
  617. nicks = newNicks
  618. }
  619. marshaledNicks := marshalReservedNicks(nicks)
  620. _, _, err = tx.Set(nicksKey, string(marshaledNicks), nil)
  621. return err
  622. })
  623. if err == errAccountTooManyNicks || err == errNicknameReserved {
  624. return err
  625. } else if err != nil {
  626. return errAccountNickReservationFailed
  627. }
  628. // success
  629. am.Lock()
  630. defer am.Unlock()
  631. if reserve {
  632. am.nickToAccount[cfnick] = account
  633. am.skeletonToAccount[skeleton] = account
  634. } else {
  635. delete(am.nickToAccount, cfnick)
  636. delete(am.skeletonToAccount, skeleton)
  637. }
  638. return nil
  639. }
  640. func (am *AccountManager) checkPassphrase(accountName, passphrase string) (account ClientAccount, err error) {
  641. account, err = am.LoadAccount(accountName)
  642. if err != nil {
  643. return
  644. }
  645. if !account.Verified {
  646. err = errAccountUnverified
  647. return
  648. }
  649. switch account.Credentials.Version {
  650. case 0:
  651. err = handleLegacyPasswordV0(am.server, accountName, account.Credentials, passphrase)
  652. case 1:
  653. if passwd.CompareHashAndPassword(account.Credentials.PassphraseHash, []byte(passphrase)) != nil {
  654. err = errAccountInvalidCredentials
  655. }
  656. default:
  657. err = errAccountInvalidCredentials
  658. }
  659. return
  660. }
  661. func (am *AccountManager) AuthenticateByPassphrase(client *Client, accountName string, passphrase string) error {
  662. account, err := am.checkPassphrase(accountName, passphrase)
  663. if err != nil {
  664. return err
  665. }
  666. am.Login(client, account)
  667. return nil
  668. }
  669. func (am *AccountManager) LoadAccount(accountName string) (result ClientAccount, err error) {
  670. casefoldedAccount, err := CasefoldName(accountName)
  671. if err != nil {
  672. err = errAccountDoesNotExist
  673. return
  674. }
  675. var raw rawClientAccount
  676. am.server.store.View(func(tx *buntdb.Tx) error {
  677. raw, err = am.loadRawAccount(tx, casefoldedAccount)
  678. return nil
  679. })
  680. if err != nil {
  681. return
  682. }
  683. result, err = am.deserializeRawAccount(raw)
  684. return
  685. }
  686. func (am *AccountManager) deserializeRawAccount(raw rawClientAccount) (result ClientAccount, err error) {
  687. result.Name = raw.Name
  688. regTimeInt, _ := strconv.ParseInt(raw.RegisteredAt, 10, 64)
  689. result.RegisteredAt = time.Unix(regTimeInt, 0)
  690. e := json.Unmarshal([]byte(raw.Credentials), &result.Credentials)
  691. if e != nil {
  692. am.server.logger.Error("internal", "could not unmarshal credentials", e.Error())
  693. err = errAccountDoesNotExist
  694. return
  695. }
  696. result.AdditionalNicks = unmarshalReservedNicks(raw.AdditionalNicks)
  697. result.Verified = raw.Verified
  698. if raw.VHost != "" {
  699. e := json.Unmarshal([]byte(raw.VHost), &result.VHost)
  700. if e != nil {
  701. am.server.logger.Warning("internal", "could not unmarshal vhost for account", result.Name, e.Error())
  702. // pretend they have no vhost and move on
  703. }
  704. }
  705. return
  706. }
  707. func (am *AccountManager) loadRawAccount(tx *buntdb.Tx, casefoldedAccount string) (result rawClientAccount, err error) {
  708. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  709. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  710. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  711. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  712. verifiedKey := fmt.Sprintf(keyAccountVerified, casefoldedAccount)
  713. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  714. nicksKey := fmt.Sprintf(keyAccountAdditionalNicks, casefoldedAccount)
  715. vhostKey := fmt.Sprintf(keyAccountVHost, casefoldedAccount)
  716. _, e := tx.Get(accountKey)
  717. if e == buntdb.ErrNotFound {
  718. err = errAccountDoesNotExist
  719. return
  720. }
  721. result.Name, _ = tx.Get(accountNameKey)
  722. result.RegisteredAt, _ = tx.Get(registeredTimeKey)
  723. result.Credentials, _ = tx.Get(credentialsKey)
  724. result.Callback, _ = tx.Get(callbackKey)
  725. result.AdditionalNicks, _ = tx.Get(nicksKey)
  726. result.VHost, _ = tx.Get(vhostKey)
  727. if _, e = tx.Get(verifiedKey); e == nil {
  728. result.Verified = true
  729. }
  730. return
  731. }
  732. func (am *AccountManager) Unregister(account string) error {
  733. config := am.server.Config()
  734. casefoldedAccount, err := CasefoldName(account)
  735. if err != nil {
  736. return errAccountDoesNotExist
  737. }
  738. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  739. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  740. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  741. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  742. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  743. verificationCodeKey := fmt.Sprintf(keyAccountVerificationCode, casefoldedAccount)
  744. verifiedKey := fmt.Sprintf(keyAccountVerified, casefoldedAccount)
  745. nicksKey := fmt.Sprintf(keyAccountAdditionalNicks, casefoldedAccount)
  746. enforcementKey := fmt.Sprintf(keyAccountEnforcement, casefoldedAccount)
  747. vhostKey := fmt.Sprintf(keyAccountVHost, casefoldedAccount)
  748. vhostQueueKey := fmt.Sprintf(keyVHostQueueAcctToId, casefoldedAccount)
  749. channelsKey := fmt.Sprintf(keyAccountChannels, casefoldedAccount)
  750. var clients []*Client
  751. var registeredChannels []string
  752. // on our way out, unregister all the account's channels and delete them from the db
  753. defer func() {
  754. for _, channelName := range registeredChannels {
  755. am.server.channels.SetUnregistered(channelName, casefoldedAccount)
  756. }
  757. }()
  758. var credText string
  759. var rawNicks string
  760. am.serialCacheUpdateMutex.Lock()
  761. defer am.serialCacheUpdateMutex.Unlock()
  762. var accountName string
  763. var channelsStr string
  764. am.server.store.Update(func(tx *buntdb.Tx) error {
  765. tx.Delete(accountKey)
  766. accountName, _ = tx.Get(accountNameKey)
  767. tx.Delete(accountNameKey)
  768. tx.Delete(verifiedKey)
  769. tx.Delete(registeredTimeKey)
  770. tx.Delete(callbackKey)
  771. tx.Delete(verificationCodeKey)
  772. tx.Delete(enforcementKey)
  773. rawNicks, _ = tx.Get(nicksKey)
  774. tx.Delete(nicksKey)
  775. credText, err = tx.Get(credentialsKey)
  776. tx.Delete(credentialsKey)
  777. tx.Delete(vhostKey)
  778. channelsStr, _ = tx.Get(channelsKey)
  779. tx.Delete(channelsKey)
  780. _, err := tx.Delete(vhostQueueKey)
  781. am.decrementVHostQueueCount(casefoldedAccount, err)
  782. return nil
  783. })
  784. if err == nil {
  785. var creds AccountCredentials
  786. if err = json.Unmarshal([]byte(credText), &creds); err == nil && creds.Certificate != "" {
  787. certFPKey := fmt.Sprintf(keyCertToAccount, creds.Certificate)
  788. am.server.store.Update(func(tx *buntdb.Tx) error {
  789. if account, err := tx.Get(certFPKey); err == nil && account == casefoldedAccount {
  790. tx.Delete(certFPKey)
  791. }
  792. return nil
  793. })
  794. }
  795. }
  796. skeleton, _ := Skeleton(accountName)
  797. additionalNicks := unmarshalReservedNicks(rawNicks)
  798. registeredChannels = unmarshalRegisteredChannels(channelsStr)
  799. am.Lock()
  800. defer am.Unlock()
  801. clients = am.accountToClients[casefoldedAccount]
  802. delete(am.accountToClients, casefoldedAccount)
  803. delete(am.nickToAccount, casefoldedAccount)
  804. delete(am.skeletonToAccount, skeleton)
  805. for _, nick := range additionalNicks {
  806. delete(am.nickToAccount, nick)
  807. additionalSkel, _ := Skeleton(nick)
  808. delete(am.skeletonToAccount, additionalSkel)
  809. }
  810. for _, client := range clients {
  811. if config.Accounts.RequireSasl.Enabled {
  812. client.Quit(client.t("You are no longer authorized to be on this server"))
  813. // destroy acquires a semaphore so we can't call it while holding a lock
  814. go client.destroy(false)
  815. } else {
  816. am.logoutOfAccount(client)
  817. }
  818. }
  819. if err != nil {
  820. return errAccountDoesNotExist
  821. }
  822. return nil
  823. }
  824. func unmarshalRegisteredChannels(channelsStr string) (result []string) {
  825. if channelsStr != "" {
  826. result = strings.Split(channelsStr, ",")
  827. }
  828. return
  829. }
  830. func (am *AccountManager) ChannelsForAccount(account string) (channels []string) {
  831. cfaccount, err := CasefoldName(account)
  832. if err != nil {
  833. return
  834. }
  835. var channelStr string
  836. key := fmt.Sprintf(keyAccountChannels, cfaccount)
  837. am.server.store.View(func(tx *buntdb.Tx) error {
  838. channelStr, _ = tx.Get(key)
  839. return nil
  840. })
  841. return unmarshalRegisteredChannels(channelStr)
  842. }
  843. func (am *AccountManager) AuthenticateByCertFP(client *Client) error {
  844. if client.certfp == "" {
  845. return errAccountInvalidCredentials
  846. }
  847. var account string
  848. var rawAccount rawClientAccount
  849. certFPKey := fmt.Sprintf(keyCertToAccount, client.certfp)
  850. err := am.server.store.Update(func(tx *buntdb.Tx) error {
  851. var err error
  852. account, _ = tx.Get(certFPKey)
  853. if account == "" {
  854. return errAccountInvalidCredentials
  855. }
  856. rawAccount, err = am.loadRawAccount(tx, account)
  857. if err != nil || !rawAccount.Verified {
  858. return errAccountUnverified
  859. }
  860. return nil
  861. })
  862. if err != nil {
  863. return err
  864. }
  865. // ok, we found an account corresponding to their certificate
  866. clientAccount, err := am.deserializeRawAccount(rawAccount)
  867. if err != nil {
  868. return err
  869. }
  870. am.Login(client, clientAccount)
  871. return nil
  872. }
  873. // represents someone's status in hostserv
  874. type VHostInfo struct {
  875. ApprovedVHost string
  876. Enabled bool
  877. RequestedVHost string
  878. RejectedVHost string
  879. RejectionReason string
  880. LastRequestTime time.Time
  881. }
  882. // pair type, <VHostInfo, accountName>
  883. type PendingVHostRequest struct {
  884. VHostInfo
  885. Account string
  886. }
  887. // callback type implementing the actual business logic of vhost operations
  888. type vhostMunger func(input VHostInfo) (output VHostInfo, err error)
  889. func (am *AccountManager) VHostSet(account string, vhost string) (result VHostInfo, err error) {
  890. munger := func(input VHostInfo) (output VHostInfo, err error) {
  891. output = input
  892. output.Enabled = true
  893. output.ApprovedVHost = vhost
  894. return
  895. }
  896. return am.performVHostChange(account, munger)
  897. }
  898. func (am *AccountManager) VHostRequest(account string, vhost string) (result VHostInfo, err error) {
  899. munger := func(input VHostInfo) (output VHostInfo, err error) {
  900. output = input
  901. output.RequestedVHost = vhost
  902. output.RejectedVHost = ""
  903. output.RejectionReason = ""
  904. output.LastRequestTime = time.Now().UTC()
  905. return
  906. }
  907. return am.performVHostChange(account, munger)
  908. }
  909. func (am *AccountManager) VHostApprove(account string) (result VHostInfo, err error) {
  910. munger := func(input VHostInfo) (output VHostInfo, err error) {
  911. output = input
  912. output.Enabled = true
  913. output.ApprovedVHost = input.RequestedVHost
  914. output.RequestedVHost = ""
  915. output.RejectionReason = ""
  916. return
  917. }
  918. return am.performVHostChange(account, munger)
  919. }
  920. func (am *AccountManager) VHostReject(account string, reason string) (result VHostInfo, err error) {
  921. munger := func(input VHostInfo) (output VHostInfo, err error) {
  922. output = input
  923. output.RejectedVHost = output.RequestedVHost
  924. output.RequestedVHost = ""
  925. output.RejectionReason = reason
  926. return
  927. }
  928. return am.performVHostChange(account, munger)
  929. }
  930. func (am *AccountManager) VHostSetEnabled(client *Client, enabled bool) (result VHostInfo, err error) {
  931. munger := func(input VHostInfo) (output VHostInfo, err error) {
  932. output = input
  933. output.Enabled = enabled
  934. return
  935. }
  936. return am.performVHostChange(client.Account(), munger)
  937. }
  938. func (am *AccountManager) performVHostChange(account string, munger vhostMunger) (result VHostInfo, err error) {
  939. account, err = CasefoldName(account)
  940. if err != nil || account == "" {
  941. err = errAccountDoesNotExist
  942. return
  943. }
  944. am.vHostUpdateMutex.Lock()
  945. defer am.vHostUpdateMutex.Unlock()
  946. clientAccount, err := am.LoadAccount(account)
  947. if err != nil {
  948. err = errAccountDoesNotExist
  949. return
  950. } else if !clientAccount.Verified {
  951. err = errAccountUnverified
  952. return
  953. }
  954. result, err = munger(clientAccount.VHost)
  955. if err != nil {
  956. return
  957. }
  958. vhtext, err := json.Marshal(result)
  959. if err != nil {
  960. err = errAccountUpdateFailed
  961. return
  962. }
  963. vhstr := string(vhtext)
  964. key := fmt.Sprintf(keyAccountVHost, account)
  965. queueKey := fmt.Sprintf(keyVHostQueueAcctToId, account)
  966. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  967. if _, _, err := tx.Set(key, vhstr, nil); err != nil {
  968. return err
  969. }
  970. // update request queue
  971. if clientAccount.VHost.RequestedVHost == "" && result.RequestedVHost != "" {
  972. id := atomic.AddUint64(&am.vhostRequestID, 1)
  973. if _, _, err = tx.Set(queueKey, strconv.FormatUint(id, 10), nil); err != nil {
  974. return err
  975. }
  976. atomic.AddUint64(&am.vhostRequestPendingCount, 1)
  977. } else if clientAccount.VHost.RequestedVHost != "" && result.RequestedVHost == "" {
  978. _, err = tx.Delete(queueKey)
  979. am.decrementVHostQueueCount(account, err)
  980. }
  981. return nil
  982. })
  983. if err != nil {
  984. err = errAccountUpdateFailed
  985. return
  986. }
  987. am.applyVhostToClients(account, result)
  988. return result, nil
  989. }
  990. // XXX annoying helper method for keeping the queue count in sync with the DB
  991. // `err` is the buntdb error returned from deleting the queue key
  992. func (am *AccountManager) decrementVHostQueueCount(account string, err error) {
  993. if err == nil {
  994. // successfully deleted a queue entry, do a 2's complement decrement:
  995. atomic.AddUint64(&am.vhostRequestPendingCount, ^uint64(0))
  996. } else if err != buntdb.ErrNotFound {
  997. am.server.logger.Error("internal", "buntdb dequeue error", account, err.Error())
  998. }
  999. }
  1000. func (am *AccountManager) VHostListRequests(limit int) (requests []PendingVHostRequest, total int) {
  1001. am.vHostUpdateMutex.Lock()
  1002. defer am.vHostUpdateMutex.Unlock()
  1003. total = int(atomic.LoadUint64(&am.vhostRequestPendingCount))
  1004. prefix := fmt.Sprintf(keyVHostQueueAcctToId, "")
  1005. accounts := make([]string, 0, limit)
  1006. err := am.server.store.View(func(tx *buntdb.Tx) error {
  1007. return tx.Ascend(vhostRequestIdx, func(key, value string) bool {
  1008. accounts = append(accounts, strings.TrimPrefix(key, prefix))
  1009. return len(accounts) < limit
  1010. })
  1011. })
  1012. if err != nil {
  1013. am.server.logger.Error("internal", "couldn't traverse vhost queue", err.Error())
  1014. return
  1015. }
  1016. for _, account := range accounts {
  1017. accountInfo, err := am.LoadAccount(account)
  1018. if err == nil {
  1019. requests = append(requests, PendingVHostRequest{
  1020. Account: account,
  1021. VHostInfo: accountInfo.VHost,
  1022. })
  1023. } else {
  1024. am.server.logger.Error("internal", "corrupt account", account, err.Error())
  1025. }
  1026. }
  1027. return
  1028. }
  1029. func (am *AccountManager) applyVHostInfo(client *Client, info VHostInfo) {
  1030. // if hostserv is disabled in config, then don't grant vhosts
  1031. // that were previously approved while it was enabled
  1032. if !am.server.AccountConfig().VHosts.Enabled {
  1033. return
  1034. }
  1035. vhost := ""
  1036. if info.Enabled {
  1037. vhost = info.ApprovedVHost
  1038. }
  1039. oldNickmask := client.NickMaskString()
  1040. updated := client.SetVHost(vhost)
  1041. if updated {
  1042. // TODO: doing I/O here is kind of a kludge
  1043. go client.sendChghost(oldNickmask, client.Hostname())
  1044. }
  1045. }
  1046. func (am *AccountManager) applyVhostToClients(account string, result VHostInfo) {
  1047. am.RLock()
  1048. clients := am.accountToClients[account]
  1049. am.RUnlock()
  1050. for _, client := range clients {
  1051. am.applyVHostInfo(client, result)
  1052. }
  1053. }
  1054. func (am *AccountManager) Login(client *Client, account ClientAccount) {
  1055. changed := client.SetAccountName(account.Name)
  1056. if !changed {
  1057. return
  1058. }
  1059. client.nickTimer.Touch()
  1060. am.applyVHostInfo(client, account.VHost)
  1061. casefoldedAccount := client.Account()
  1062. am.Lock()
  1063. defer am.Unlock()
  1064. am.accountToClients[casefoldedAccount] = append(am.accountToClients[casefoldedAccount], client)
  1065. }
  1066. func (am *AccountManager) Logout(client *Client) {
  1067. am.Lock()
  1068. defer am.Unlock()
  1069. casefoldedAccount := client.Account()
  1070. if casefoldedAccount == "" {
  1071. return
  1072. }
  1073. am.logoutOfAccount(client)
  1074. clients := am.accountToClients[casefoldedAccount]
  1075. if len(clients) <= 1 {
  1076. delete(am.accountToClients, casefoldedAccount)
  1077. return
  1078. }
  1079. remainingClients := make([]*Client, len(clients)-1)
  1080. remainingPos := 0
  1081. for currentPos := 0; currentPos < len(clients); currentPos++ {
  1082. if clients[currentPos] != client {
  1083. remainingClients[remainingPos] = clients[currentPos]
  1084. remainingPos++
  1085. }
  1086. }
  1087. am.accountToClients[casefoldedAccount] = remainingClients
  1088. return
  1089. }
  1090. var (
  1091. // EnabledSaslMechanisms contains the SASL mechanisms that exist and that we support.
  1092. // This can be moved to some other data structure/place if we need to load/unload mechs later.
  1093. EnabledSaslMechanisms = map[string]func(*Server, *Client, string, []byte, *ResponseBuffer) bool{
  1094. "PLAIN": authPlainHandler,
  1095. "EXTERNAL": authExternalHandler,
  1096. }
  1097. )
  1098. // AccountCredentials stores the various methods for verifying accounts.
  1099. type AccountCredentials struct {
  1100. Version uint
  1101. PassphraseSalt []byte // legacy field, not used by v1 and later
  1102. PassphraseHash []byte
  1103. Certificate string // fingerprint
  1104. }
  1105. // ClientAccount represents a user account.
  1106. type ClientAccount struct {
  1107. // Name of the account.
  1108. Name string
  1109. // RegisteredAt represents the time that the account was registered.
  1110. RegisteredAt time.Time
  1111. Credentials AccountCredentials
  1112. Verified bool
  1113. AdditionalNicks []string
  1114. VHost VHostInfo
  1115. }
  1116. // convenience for passing around raw serialized account data
  1117. type rawClientAccount struct {
  1118. Name string
  1119. RegisteredAt string
  1120. Credentials string
  1121. Callback string
  1122. Verified bool
  1123. AdditionalNicks string
  1124. VHost string
  1125. }
  1126. // logoutOfAccount logs the client out of their current account.
  1127. func (am *AccountManager) logoutOfAccount(client *Client) {
  1128. if client.Account() == "" {
  1129. // already logged out
  1130. return
  1131. }
  1132. client.SetAccountName("")
  1133. go client.nickTimer.Touch()
  1134. // dispatch account-notify
  1135. // TODO: doing the I/O here is kind of a kludge, let's move this somewhere else
  1136. go func() {
  1137. for friend := range client.Friends(caps.AccountNotify) {
  1138. friend.Send(nil, client.NickMaskString(), "ACCOUNT", "*")
  1139. }
  1140. }()
  1141. }