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

accounts.go 39KB

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