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

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