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 56KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948
  1. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "bytes"
  6. "encoding/json"
  7. "fmt"
  8. "sort"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. "sync/atomic"
  13. "time"
  14. "unicode"
  15. "github.com/oragono/oragono/irc/connection_limits"
  16. "github.com/oragono/oragono/irc/email"
  17. "github.com/oragono/oragono/irc/ldap"
  18. "github.com/oragono/oragono/irc/modes"
  19. "github.com/oragono/oragono/irc/passwd"
  20. "github.com/oragono/oragono/irc/utils"
  21. "github.com/tidwall/buntdb"
  22. )
  23. const (
  24. keyAccountExists = "account.exists %s"
  25. keyAccountVerified = "account.verified %s"
  26. keyAccountUnregistered = "account.unregistered %s"
  27. keyAccountCallback = "account.callback %s"
  28. keyAccountVerificationCode = "account.verificationcode %s"
  29. keyAccountName = "account.name %s" // stores the 'preferred name' of the account, not casemapped
  30. keyAccountRegTime = "account.registered.time %s"
  31. keyAccountCredentials = "account.credentials %s"
  32. keyAccountAdditionalNicks = "account.additionalnicks %s"
  33. keyAccountSettings = "account.settings %s"
  34. keyAccountVHost = "account.vhost %s"
  35. keyCertToAccount = "account.creds.certfp %s"
  36. keyAccountChannels = "account.channels %s" // channels registered to the account
  37. keyAccountJoinedChannels = "account.joinedto %s" // channels a persistent client has joined
  38. keyAccountLastSeen = "account.lastseen %s"
  39. keyAccountModes = "account.modes %s" // user modes for the always-on client as a string
  40. keyVHostQueueAcctToId = "vhostQueue %s"
  41. vhostRequestIdx = "vhostQueue"
  42. maxCertfpsPerAccount = 5
  43. )
  44. // everything about accounts is persistent; therefore, the database is the authoritative
  45. // source of truth for all account information. anything on the heap is just a cache
  46. type AccountManager struct {
  47. // XXX these are up here so they can be aligned to a 64-bit boundary, please forgive me
  48. // autoincrementing ID for vhost requests:
  49. vhostRequestID uint64
  50. vhostRequestPendingCount uint64
  51. sync.RWMutex // tier 2
  52. serialCacheUpdateMutex sync.Mutex // tier 3
  53. vHostUpdateMutex sync.Mutex // tier 3
  54. server *Server
  55. // track clients logged in to accounts
  56. accountToClients map[string][]*Client
  57. nickToAccount map[string]string
  58. skeletonToAccount map[string]string
  59. accountToMethod map[string]NickEnforcementMethod
  60. registerThrottle connection_limits.GenericThrottle
  61. }
  62. func (am *AccountManager) Initialize(server *Server) {
  63. am.accountToClients = make(map[string][]*Client)
  64. am.nickToAccount = make(map[string]string)
  65. am.skeletonToAccount = make(map[string]string)
  66. am.accountToMethod = make(map[string]NickEnforcementMethod)
  67. am.server = server
  68. config := server.Config()
  69. am.buildNickToAccountIndex(config)
  70. am.initVHostRequestQueue(config)
  71. am.createAlwaysOnClients(config)
  72. am.resetRegisterThrottle(config)
  73. }
  74. func (am *AccountManager) resetRegisterThrottle(config *Config) {
  75. am.Lock()
  76. defer am.Unlock()
  77. am.registerThrottle = connection_limits.GenericThrottle{
  78. Duration: config.Accounts.Registration.Throttling.Duration,
  79. Limit: config.Accounts.Registration.Throttling.MaxAttempts,
  80. }
  81. }
  82. func (am *AccountManager) touchRegisterThrottle() (throttled bool) {
  83. am.Lock()
  84. defer am.Unlock()
  85. throttled, _ = am.registerThrottle.Touch()
  86. return
  87. }
  88. func (am *AccountManager) createAlwaysOnClients(config *Config) {
  89. if config.Accounts.Multiclient.AlwaysOn == PersistentDisabled {
  90. return
  91. }
  92. verifiedPrefix := fmt.Sprintf(keyAccountVerified, "")
  93. am.serialCacheUpdateMutex.Lock()
  94. defer am.serialCacheUpdateMutex.Unlock()
  95. var accounts []string
  96. am.server.store.View(func(tx *buntdb.Tx) error {
  97. err := tx.AscendGreaterOrEqual("", verifiedPrefix, func(key, value string) bool {
  98. if !strings.HasPrefix(key, verifiedPrefix) {
  99. return false
  100. }
  101. account := strings.TrimPrefix(key, verifiedPrefix)
  102. accounts = append(accounts, account)
  103. return true
  104. })
  105. return err
  106. })
  107. for _, accountName := range accounts {
  108. account, err := am.LoadAccount(accountName)
  109. if err == nil && account.Verified &&
  110. persistenceEnabled(config.Accounts.Multiclient.AlwaysOn, account.Settings.AlwaysOn) {
  111. am.server.AddAlwaysOnClient(account, am.loadChannels(accountName), am.loadLastSeen(accountName), am.loadModes(accountName))
  112. }
  113. }
  114. }
  115. func (am *AccountManager) buildNickToAccountIndex(config *Config) {
  116. if !config.Accounts.NickReservation.Enabled {
  117. return
  118. }
  119. nickToAccount := make(map[string]string)
  120. skeletonToAccount := make(map[string]string)
  121. accountToMethod := make(map[string]NickEnforcementMethod)
  122. existsPrefix := fmt.Sprintf(keyAccountExists, "")
  123. am.serialCacheUpdateMutex.Lock()
  124. defer am.serialCacheUpdateMutex.Unlock()
  125. err := am.server.store.View(func(tx *buntdb.Tx) error {
  126. err := tx.AscendGreaterOrEqual("", existsPrefix, func(key, value string) bool {
  127. if !strings.HasPrefix(key, existsPrefix) {
  128. return false
  129. }
  130. account := strings.TrimPrefix(key, existsPrefix)
  131. if _, err := tx.Get(fmt.Sprintf(keyAccountVerified, account)); err == nil {
  132. nickToAccount[account] = account
  133. accountName, err := tx.Get(fmt.Sprintf(keyAccountName, account))
  134. if err != nil {
  135. am.server.logger.Error("internal", "missing account name for", account)
  136. } else {
  137. skeleton, _ := Skeleton(accountName)
  138. skeletonToAccount[skeleton] = account
  139. }
  140. }
  141. if rawNicks, err := tx.Get(fmt.Sprintf(keyAccountAdditionalNicks, account)); err == nil {
  142. additionalNicks := unmarshalReservedNicks(rawNicks)
  143. for _, nick := range additionalNicks {
  144. cfnick, _ := CasefoldName(nick)
  145. nickToAccount[cfnick] = account
  146. skeleton, _ := Skeleton(nick)
  147. skeletonToAccount[skeleton] = account
  148. }
  149. }
  150. if rawPrefs, err := tx.Get(fmt.Sprintf(keyAccountSettings, account)); err == nil {
  151. var prefs AccountSettings
  152. err := json.Unmarshal([]byte(rawPrefs), &prefs)
  153. if err == nil && prefs.NickEnforcement != NickEnforcementOptional {
  154. accountToMethod[account] = prefs.NickEnforcement
  155. } else if err != nil {
  156. am.server.logger.Error("internal", "corrupt account creds", account)
  157. }
  158. }
  159. return true
  160. })
  161. return err
  162. })
  163. if config.Accounts.NickReservation.Method == NickEnforcementStrict {
  164. unregisteredPrefix := fmt.Sprintf(keyAccountUnregistered, "")
  165. am.server.store.View(func(tx *buntdb.Tx) error {
  166. tx.AscendGreaterOrEqual("", unregisteredPrefix, func(key, value string) bool {
  167. if !strings.HasPrefix(key, unregisteredPrefix) {
  168. return false
  169. }
  170. account := strings.TrimPrefix(key, unregisteredPrefix)
  171. accountName := value
  172. nickToAccount[account] = account
  173. skeleton, _ := Skeleton(accountName)
  174. skeletonToAccount[skeleton] = account
  175. return true
  176. })
  177. return nil
  178. })
  179. }
  180. if err != nil {
  181. am.server.logger.Error("internal", "couldn't read reserved nicks", err.Error())
  182. } else {
  183. am.Lock()
  184. am.nickToAccount = nickToAccount
  185. am.skeletonToAccount = skeletonToAccount
  186. am.accountToMethod = accountToMethod
  187. am.Unlock()
  188. }
  189. }
  190. func (am *AccountManager) initVHostRequestQueue(config *Config) {
  191. if !config.Accounts.VHosts.Enabled {
  192. return
  193. }
  194. am.vHostUpdateMutex.Lock()
  195. defer am.vHostUpdateMutex.Unlock()
  196. // the db maps the account name to the autoincrementing integer ID of its request
  197. // create an numerically ordered index on ID, so we can list the oldest requests
  198. // finally, collect the integer id of the newest request and the total request count
  199. var total uint64
  200. var lastIDStr string
  201. err := am.server.store.Update(func(tx *buntdb.Tx) error {
  202. err := tx.CreateIndex(vhostRequestIdx, fmt.Sprintf(keyVHostQueueAcctToId, "*"), buntdb.IndexInt)
  203. if err != nil {
  204. return err
  205. }
  206. return tx.Descend(vhostRequestIdx, func(key, value string) bool {
  207. if lastIDStr == "" {
  208. lastIDStr = value
  209. }
  210. total++
  211. return true
  212. })
  213. })
  214. if err != nil {
  215. am.server.logger.Error("internal", "could not create vhost queue index", err.Error())
  216. }
  217. lastID, _ := strconv.ParseUint(lastIDStr, 10, 64)
  218. am.server.logger.Debug("services", fmt.Sprintf("vhost queue length is %d, autoincrementing id is %d", total, lastID))
  219. atomic.StoreUint64(&am.vhostRequestID, lastID)
  220. atomic.StoreUint64(&am.vhostRequestPendingCount, total)
  221. }
  222. func (am *AccountManager) NickToAccount(nick string) string {
  223. cfnick, err := CasefoldName(nick)
  224. if err != nil {
  225. return ""
  226. }
  227. am.RLock()
  228. defer am.RUnlock()
  229. return am.nickToAccount[cfnick]
  230. }
  231. // given an account, combine stored enforcement method with the config settings
  232. // to compute the actual enforcement method
  233. func configuredEnforcementMethod(config *Config, storedMethod NickEnforcementMethod) (result NickEnforcementMethod) {
  234. if !config.Accounts.NickReservation.Enabled {
  235. return NickEnforcementNone
  236. }
  237. result = storedMethod
  238. // if they don't have a custom setting, or customization is disabled, use the default
  239. if result == NickEnforcementOptional || !config.Accounts.NickReservation.AllowCustomEnforcement {
  240. result = config.Accounts.NickReservation.Method
  241. }
  242. if result == NickEnforcementOptional {
  243. // enforcement was explicitly enabled neither in the config or by the user
  244. result = NickEnforcementNone
  245. }
  246. return
  247. }
  248. // Given a nick, looks up the account that owns it and the method (none/timeout/strict)
  249. // used to enforce ownership.
  250. func (am *AccountManager) EnforcementStatus(cfnick, skeleton string) (account string, method NickEnforcementMethod) {
  251. config := am.server.Config()
  252. if !config.Accounts.NickReservation.Enabled {
  253. return "", NickEnforcementNone
  254. }
  255. am.RLock()
  256. defer am.RUnlock()
  257. finalEnforcementMethod := func(account_ string) (result NickEnforcementMethod) {
  258. storedMethod := am.accountToMethod[account_]
  259. return configuredEnforcementMethod(config, storedMethod)
  260. }
  261. nickAccount := am.nickToAccount[cfnick]
  262. skelAccount := am.skeletonToAccount[skeleton]
  263. if nickAccount == "" && skelAccount == "" {
  264. return "", NickEnforcementNone
  265. } else if nickAccount != "" && (skelAccount == nickAccount || skelAccount == "") {
  266. return nickAccount, finalEnforcementMethod(nickAccount)
  267. } else if skelAccount != "" && nickAccount == "" {
  268. return skelAccount, finalEnforcementMethod(skelAccount)
  269. } else {
  270. // nickAccount != skelAccount and both are nonempty:
  271. // two people have competing claims on (this casefolding of) this nick!
  272. nickMethod := finalEnforcementMethod(nickAccount)
  273. skelMethod := finalEnforcementMethod(skelAccount)
  274. switch {
  275. case skelMethod == NickEnforcementNone:
  276. return nickAccount, nickMethod
  277. case nickMethod == NickEnforcementNone:
  278. return skelAccount, skelMethod
  279. default:
  280. // nobody can use this nick
  281. return "!", NickEnforcementStrict
  282. }
  283. }
  284. }
  285. // Sets a custom enforcement method for an account and stores it in the database.
  286. func (am *AccountManager) SetEnforcementStatus(account string, method NickEnforcementMethod) (finalSettings AccountSettings, err error) {
  287. config := am.server.Config()
  288. if !(config.Accounts.NickReservation.Enabled && config.Accounts.NickReservation.AllowCustomEnforcement) {
  289. err = errFeatureDisabled
  290. return
  291. }
  292. setter := func(in AccountSettings) (out AccountSettings, err error) {
  293. out = in
  294. out.NickEnforcement = method
  295. return out, nil
  296. }
  297. _, err = am.ModifyAccountSettings(account, setter)
  298. if err != nil {
  299. return
  300. }
  301. // this update of the data plane is racey, but it's probably fine
  302. am.Lock()
  303. defer am.Unlock()
  304. if method == NickEnforcementOptional {
  305. delete(am.accountToMethod, account)
  306. } else {
  307. am.accountToMethod[account] = method
  308. }
  309. return
  310. }
  311. func (am *AccountManager) AccountToClients(account string) (result []*Client) {
  312. cfaccount, err := CasefoldName(account)
  313. if err != nil {
  314. return
  315. }
  316. am.RLock()
  317. defer am.RUnlock()
  318. return am.accountToClients[cfaccount]
  319. }
  320. func (am *AccountManager) Register(client *Client, account string, callbackNamespace string, callbackValue string, passphrase string, certfp string) error {
  321. casefoldedAccount, err := CasefoldName(account)
  322. skeleton, skerr := Skeleton(account)
  323. if err != nil || skerr != nil || account == "" || account == "*" {
  324. return errAccountCreation
  325. }
  326. if restrictedCasefoldedNicks[casefoldedAccount] || restrictedSkeletons[skeleton] {
  327. return errAccountAlreadyRegistered
  328. }
  329. config := am.server.Config()
  330. // final "is registration allowed" check, probably redundant:
  331. if !(config.Accounts.Registration.Enabled || callbackNamespace == "admin") {
  332. return errFeatureDisabled
  333. }
  334. if client != nil && client.Account() != "" {
  335. return errAccountAlreadyLoggedIn
  336. }
  337. if client != nil && am.touchRegisterThrottle() {
  338. am.server.logger.Warning("accounts", "global registration throttle exceeded by client", client.Nick())
  339. return errLimitExceeded
  340. }
  341. // if nick reservation is enabled, you can only register your current nickname
  342. // as an account; this prevents "land-grab" situations where someone else
  343. // registers your nick out from under you and then NS GHOSTs you
  344. // n.b. client is nil during a SAREGISTER
  345. // n.b. if ForceGuestFormat, then there's no concern, because you can't
  346. // register a guest nickname anyway, and the actual registration system
  347. // will prevent any double-register
  348. if client != nil && config.Accounts.NickReservation.Enabled &&
  349. !config.Accounts.NickReservation.ForceGuestFormat &&
  350. client.NickCasefolded() != casefoldedAccount {
  351. return errAccountMustHoldNick
  352. }
  353. // can't register a guest nickname
  354. if config.Accounts.NickReservation.guestRegexpFolded.MatchString(casefoldedAccount) {
  355. return errAccountAlreadyRegistered
  356. }
  357. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  358. unregisteredKey := fmt.Sprintf(keyAccountUnregistered, casefoldedAccount)
  359. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  360. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  361. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  362. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  363. verificationCodeKey := fmt.Sprintf(keyAccountVerificationCode, casefoldedAccount)
  364. certFPKey := fmt.Sprintf(keyCertToAccount, certfp)
  365. var creds AccountCredentials
  366. creds.Version = 1
  367. err = creds.SetPassphrase(passphrase, am.server.Config().Accounts.Registration.BcryptCost)
  368. if err != nil {
  369. return err
  370. }
  371. creds.AddCertfp(certfp)
  372. credStr, err := creds.Serialize()
  373. if err != nil {
  374. return err
  375. }
  376. registeredTimeStr := strconv.FormatInt(time.Now().UnixNano(), 10)
  377. callbackSpec := fmt.Sprintf("%s:%s", callbackNamespace, callbackValue)
  378. var setOptions *buntdb.SetOptions
  379. ttl := time.Duration(config.Accounts.Registration.VerifyTimeout)
  380. if ttl != 0 {
  381. setOptions = &buntdb.SetOptions{Expires: true, TTL: ttl}
  382. }
  383. err = func() error {
  384. am.serialCacheUpdateMutex.Lock()
  385. defer am.serialCacheUpdateMutex.Unlock()
  386. // can't register an account with the same name as a registered nick
  387. if am.NickToAccount(casefoldedAccount) != "" {
  388. return errAccountAlreadyRegistered
  389. }
  390. return am.server.store.Update(func(tx *buntdb.Tx) error {
  391. if _, err := tx.Get(unregisteredKey); err == nil {
  392. return errAccountAlreadyUnregistered
  393. }
  394. _, err = am.loadRawAccount(tx, casefoldedAccount)
  395. if err != errAccountDoesNotExist {
  396. return errAccountAlreadyRegistered
  397. }
  398. if certfp != "" {
  399. // make sure certfp doesn't already exist because that'd be silly
  400. _, err := tx.Get(certFPKey)
  401. if err != buntdb.ErrNotFound {
  402. return errCertfpAlreadyExists
  403. }
  404. }
  405. tx.Set(accountKey, "1", setOptions)
  406. tx.Set(accountNameKey, account, setOptions)
  407. tx.Set(registeredTimeKey, registeredTimeStr, setOptions)
  408. tx.Set(credentialsKey, credStr, setOptions)
  409. tx.Set(callbackKey, callbackSpec, setOptions)
  410. if certfp != "" {
  411. tx.Set(certFPKey, casefoldedAccount, setOptions)
  412. }
  413. return nil
  414. })
  415. }()
  416. if err != nil {
  417. return err
  418. }
  419. code, err := am.dispatchCallback(client, account, callbackNamespace, callbackValue)
  420. if err != nil {
  421. am.Unregister(casefoldedAccount, true)
  422. return errCallbackFailed
  423. } else {
  424. return am.server.store.Update(func(tx *buntdb.Tx) error {
  425. _, _, err = tx.Set(verificationCodeKey, code, setOptions)
  426. return err
  427. })
  428. }
  429. }
  430. // validatePassphrase checks whether a passphrase is allowed by our rules
  431. func validatePassphrase(passphrase string) error {
  432. // sanity check the length
  433. if len(passphrase) == 0 || len(passphrase) > 300 {
  434. return errAccountBadPassphrase
  435. }
  436. // we use * as a placeholder in some places, if it's gotten this far then fail
  437. if passphrase == "*" {
  438. return errAccountBadPassphrase
  439. }
  440. // for now, just enforce that spaces are not allowed
  441. for _, r := range passphrase {
  442. if unicode.IsSpace(r) {
  443. return errAccountBadPassphrase
  444. }
  445. }
  446. return nil
  447. }
  448. // changes the password for an account
  449. func (am *AccountManager) setPassword(account string, password string, hasPrivs bool) (err error) {
  450. cfAccount, err := CasefoldName(account)
  451. if err != nil {
  452. return errAccountDoesNotExist
  453. }
  454. credKey := fmt.Sprintf(keyAccountCredentials, cfAccount)
  455. var credStr string
  456. am.server.store.View(func(tx *buntdb.Tx) error {
  457. // no need to check verification status here or below;
  458. // you either need to be auth'ed to the account or be an oper to do this
  459. credStr, err = tx.Get(credKey)
  460. return nil
  461. })
  462. if err != nil {
  463. return errAccountDoesNotExist
  464. }
  465. var creds AccountCredentials
  466. err = json.Unmarshal([]byte(credStr), &creds)
  467. if err != nil {
  468. return err
  469. }
  470. if !hasPrivs && creds.Empty() {
  471. return errCredsExternallyManaged
  472. }
  473. err = creds.SetPassphrase(password, am.server.Config().Accounts.Registration.BcryptCost)
  474. if err != nil {
  475. return err
  476. }
  477. if creds.Empty() && !hasPrivs {
  478. return errEmptyCredentials
  479. }
  480. newCredStr, err := creds.Serialize()
  481. if err != nil {
  482. return err
  483. }
  484. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  485. curCredStr, err := tx.Get(credKey)
  486. if credStr != curCredStr {
  487. return errCASFailed
  488. }
  489. _, _, err = tx.Set(credKey, newCredStr, nil)
  490. return err
  491. })
  492. return err
  493. }
  494. func (am *AccountManager) saveChannels(account string, channels []string) {
  495. channelsStr := strings.Join(channels, ",")
  496. key := fmt.Sprintf(keyAccountJoinedChannels, account)
  497. am.server.store.Update(func(tx *buntdb.Tx) error {
  498. tx.Set(key, channelsStr, nil)
  499. return nil
  500. })
  501. }
  502. func (am *AccountManager) loadChannels(account string) (channels []string) {
  503. key := fmt.Sprintf(keyAccountJoinedChannels, account)
  504. var channelsStr string
  505. am.server.store.View(func(tx *buntdb.Tx) error {
  506. channelsStr, _ = tx.Get(key)
  507. return nil
  508. })
  509. if channelsStr != "" {
  510. return strings.Split(channelsStr, ",")
  511. }
  512. return
  513. }
  514. func (am *AccountManager) saveModes(account string, uModes modes.Modes) {
  515. modeStr := uModes.String()
  516. key := fmt.Sprintf(keyAccountModes, account)
  517. am.server.store.Update(func(tx *buntdb.Tx) error {
  518. tx.Set(key, modeStr, nil)
  519. return nil
  520. })
  521. }
  522. func (am *AccountManager) loadModes(account string) (uModes modes.Modes) {
  523. key := fmt.Sprintf(keyAccountModes, account)
  524. var modeStr string
  525. am.server.store.View(func(tx *buntdb.Tx) error {
  526. modeStr, _ = tx.Get(key)
  527. return nil
  528. })
  529. for _, m := range modeStr {
  530. uModes = append(uModes, modes.Mode(m))
  531. }
  532. return
  533. }
  534. func (am *AccountManager) saveLastSeen(account string, lastSeen time.Time) {
  535. key := fmt.Sprintf(keyAccountLastSeen, account)
  536. var val string
  537. if !lastSeen.IsZero() {
  538. val = strconv.FormatInt(lastSeen.UnixNano(), 10)
  539. }
  540. am.server.store.Update(func(tx *buntdb.Tx) error {
  541. if val != "" {
  542. tx.Set(key, val, nil)
  543. } else {
  544. tx.Delete(key)
  545. }
  546. return nil
  547. })
  548. }
  549. func (am *AccountManager) loadLastSeen(account string) (lastSeen time.Time) {
  550. key := fmt.Sprintf(keyAccountLastSeen, account)
  551. var lsText string
  552. am.server.store.Update(func(tx *buntdb.Tx) error {
  553. lsText, _ = tx.Get(key)
  554. // XXX clear this on startup, because it's not clear when it's
  555. // going to be overwritten, and restarting the server twice in a row
  556. // could result in a large amount of duplicated history replay
  557. tx.Delete(key)
  558. return nil
  559. })
  560. lsNum, err := strconv.ParseInt(lsText, 10, 64)
  561. if err == nil {
  562. return time.Unix(0, lsNum).UTC()
  563. }
  564. return
  565. }
  566. func (am *AccountManager) addRemoveCertfp(account, certfp string, add bool, hasPrivs bool) (err error) {
  567. certfp, err = utils.NormalizeCertfp(certfp)
  568. if err != nil {
  569. return err
  570. }
  571. cfAccount, err := CasefoldName(account)
  572. if err != nil {
  573. return errAccountDoesNotExist
  574. }
  575. credKey := fmt.Sprintf(keyAccountCredentials, cfAccount)
  576. var credStr string
  577. am.server.store.View(func(tx *buntdb.Tx) error {
  578. credStr, err = tx.Get(credKey)
  579. return nil
  580. })
  581. if err != nil {
  582. return errAccountDoesNotExist
  583. }
  584. var creds AccountCredentials
  585. err = json.Unmarshal([]byte(credStr), &creds)
  586. if err != nil {
  587. return err
  588. }
  589. if !hasPrivs && creds.Empty() {
  590. return errCredsExternallyManaged
  591. }
  592. if add {
  593. err = creds.AddCertfp(certfp)
  594. } else {
  595. err = creds.RemoveCertfp(certfp)
  596. }
  597. if err != nil {
  598. return err
  599. }
  600. if creds.Empty() && !hasPrivs {
  601. return errEmptyCredentials
  602. }
  603. newCredStr, err := creds.Serialize()
  604. if err != nil {
  605. return err
  606. }
  607. certfpKey := fmt.Sprintf(keyCertToAccount, certfp)
  608. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  609. curCredStr, err := tx.Get(credKey)
  610. if credStr != curCredStr {
  611. return errCASFailed
  612. }
  613. if add {
  614. _, err = tx.Get(certfpKey)
  615. if err != buntdb.ErrNotFound {
  616. return errCertfpAlreadyExists
  617. }
  618. tx.Set(certfpKey, cfAccount, nil)
  619. } else {
  620. tx.Delete(certfpKey)
  621. }
  622. _, _, err = tx.Set(credKey, newCredStr, nil)
  623. return err
  624. })
  625. return err
  626. }
  627. func (am *AccountManager) dispatchCallback(client *Client, account string, callbackNamespace string, callbackValue string) (string, error) {
  628. if callbackNamespace == "*" || callbackNamespace == "none" || callbackNamespace == "admin" {
  629. return "", nil
  630. } else if callbackNamespace == "mailto" {
  631. return am.dispatchMailtoCallback(client, account, callbackValue)
  632. } else {
  633. return "", fmt.Errorf("Callback not implemented: %s", callbackNamespace)
  634. }
  635. }
  636. func (am *AccountManager) dispatchMailtoCallback(client *Client, account string, callbackValue string) (code string, err error) {
  637. config := am.server.Config().Accounts.Registration.Callbacks.Mailto
  638. code = utils.GenerateSecretToken()
  639. subject := config.VerifyMessageSubject
  640. if subject == "" {
  641. subject = fmt.Sprintf(client.t("Verify your account on %s"), am.server.name)
  642. }
  643. var message bytes.Buffer
  644. fmt.Fprintf(&message, "From: %s\r\n", config.Sender)
  645. fmt.Fprintf(&message, "To: %s\r\n", callbackValue)
  646. if config.DKIM.Domain != "" {
  647. fmt.Fprintf(&message, "Message-ID: <%s@%s>\r\n", utils.GenerateSecretKey(), config.DKIM.Domain)
  648. }
  649. fmt.Fprintf(&message, "Date: %s\r\n", time.Now().UTC().Format(time.RFC1123Z))
  650. fmt.Fprintf(&message, "Subject: %s\r\n", subject)
  651. message.WriteString("\r\n") // blank line: end headers, begin message body
  652. fmt.Fprintf(&message, client.t("Account: %s"), account)
  653. message.WriteString("\r\n")
  654. fmt.Fprintf(&message, client.t("Verification code: %s"), code)
  655. message.WriteString("\r\n")
  656. message.WriteString("\r\n")
  657. message.WriteString(client.t("To verify your account, issue the following command:"))
  658. message.WriteString("\r\n")
  659. fmt.Fprintf(&message, "/MSG NickServ VERIFY %s %s\r\n", account, code)
  660. err = email.SendMail(config, callbackValue, message.Bytes())
  661. if err != nil {
  662. am.server.logger.Error("internal", "Failed to dispatch e-mail to", callbackValue, err.Error())
  663. }
  664. return
  665. }
  666. func (am *AccountManager) Verify(client *Client, account string, code string) error {
  667. casefoldedAccount, err := CasefoldName(account)
  668. var skeleton string
  669. if err != nil || account == "" || account == "*" {
  670. return errAccountVerificationFailed
  671. }
  672. if client != nil && client.Account() != "" {
  673. return errAccountAlreadyLoggedIn
  674. }
  675. verifiedKey := fmt.Sprintf(keyAccountVerified, casefoldedAccount)
  676. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  677. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  678. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  679. verificationCodeKey := fmt.Sprintf(keyAccountVerificationCode, casefoldedAccount)
  680. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  681. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  682. var raw rawClientAccount
  683. func() {
  684. am.serialCacheUpdateMutex.Lock()
  685. defer am.serialCacheUpdateMutex.Unlock()
  686. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  687. raw, err = am.loadRawAccount(tx, casefoldedAccount)
  688. if err == errAccountDoesNotExist {
  689. return errAccountDoesNotExist
  690. } else if err != nil {
  691. return errAccountVerificationFailed
  692. } else if raw.Verified {
  693. return errAccountAlreadyVerified
  694. }
  695. // actually verify the code
  696. // a stored code of "" means a none callback / no code required
  697. success := false
  698. storedCode, err := tx.Get(verificationCodeKey)
  699. if err == nil {
  700. // this is probably unnecessary
  701. if storedCode == "" || utils.SecretTokensMatch(storedCode, code) {
  702. success = true
  703. }
  704. }
  705. if !success {
  706. return errAccountVerificationInvalidCode
  707. }
  708. // verify the account
  709. tx.Set(verifiedKey, "1", nil)
  710. // don't need the code anymore
  711. tx.Delete(verificationCodeKey)
  712. // re-set all other keys, removing the TTL
  713. tx.Set(accountKey, "1", nil)
  714. tx.Set(accountNameKey, raw.Name, nil)
  715. tx.Set(registeredTimeKey, raw.RegisteredAt, nil)
  716. tx.Set(callbackKey, raw.Callback, nil)
  717. tx.Set(credentialsKey, raw.Credentials, nil)
  718. var creds AccountCredentials
  719. // XXX we shouldn't do (de)serialization inside the txn,
  720. // but this is like 2 usec on my system
  721. json.Unmarshal([]byte(raw.Credentials), &creds)
  722. for _, cert := range creds.Certfps {
  723. certFPKey := fmt.Sprintf(keyCertToAccount, cert)
  724. tx.Set(certFPKey, casefoldedAccount, nil)
  725. }
  726. return nil
  727. })
  728. if err == nil {
  729. skeleton, _ = Skeleton(raw.Name)
  730. am.Lock()
  731. am.nickToAccount[casefoldedAccount] = casefoldedAccount
  732. am.skeletonToAccount[skeleton] = casefoldedAccount
  733. am.Unlock()
  734. }
  735. }()
  736. if err != nil {
  737. return err
  738. }
  739. nick := "[server admin]"
  740. if client != nil {
  741. nick = client.Nick()
  742. }
  743. am.server.logger.Info("accounts", "client", nick, "registered account", casefoldedAccount)
  744. raw.Verified = true
  745. clientAccount, err := am.deserializeRawAccount(raw, casefoldedAccount)
  746. if err != nil {
  747. return err
  748. }
  749. if client != nil {
  750. am.Login(client, clientAccount)
  751. }
  752. _, method := am.EnforcementStatus(casefoldedAccount, skeleton)
  753. if method != NickEnforcementNone {
  754. currentClient := am.server.clients.Get(casefoldedAccount)
  755. if currentClient == nil || currentClient == client || currentClient.Account() == casefoldedAccount {
  756. return nil
  757. }
  758. if method == NickEnforcementStrict {
  759. am.server.RandomlyRename(currentClient)
  760. } else if method == NickEnforcementWithTimeout {
  761. currentClient.nickTimer.Touch(nil)
  762. }
  763. }
  764. return nil
  765. }
  766. // register and verify an account, for internal use
  767. func (am *AccountManager) SARegister(account, passphrase string) (err error) {
  768. err = am.Register(nil, account, "admin", "", passphrase, "")
  769. if err == nil {
  770. err = am.Verify(nil, account, "")
  771. }
  772. return
  773. }
  774. func marshalReservedNicks(nicks []string) string {
  775. return strings.Join(nicks, ",")
  776. }
  777. func unmarshalReservedNicks(nicks string) (result []string) {
  778. if nicks == "" {
  779. return
  780. }
  781. return strings.Split(nicks, ",")
  782. }
  783. func (am *AccountManager) SetNickReserved(client *Client, nick string, saUnreserve bool, reserve bool) error {
  784. cfnick, err := CasefoldName(nick)
  785. skeleton, skerr := Skeleton(nick)
  786. // garbage nick, or garbage options, or disabled
  787. nrconfig := am.server.Config().Accounts.NickReservation
  788. if err != nil || skerr != nil || cfnick == "" || (reserve && saUnreserve) || !nrconfig.Enabled {
  789. return errAccountNickReservationFailed
  790. }
  791. // the cache is in sync with the DB while we hold serialCacheUpdateMutex
  792. am.serialCacheUpdateMutex.Lock()
  793. defer am.serialCacheUpdateMutex.Unlock()
  794. // find the affected account, which is usually the client's:
  795. account := client.Account()
  796. if saUnreserve {
  797. // unless this is a sadrop:
  798. account = am.NickToAccount(cfnick)
  799. if account == "" {
  800. // nothing to do
  801. return nil
  802. }
  803. }
  804. if account == "" {
  805. return errAccountNotLoggedIn
  806. }
  807. am.Lock()
  808. accountForNick := am.nickToAccount[cfnick]
  809. var accountForSkeleton string
  810. if reserve {
  811. accountForSkeleton = am.skeletonToAccount[skeleton]
  812. }
  813. am.Unlock()
  814. if reserve && (accountForNick != "" || accountForSkeleton != "") {
  815. return errNicknameReserved
  816. } else if !reserve && !saUnreserve && accountForNick != account {
  817. return errNicknameReserved
  818. } else if !reserve && cfnick == account {
  819. return errAccountCantDropPrimaryNick
  820. }
  821. nicksKey := fmt.Sprintf(keyAccountAdditionalNicks, account)
  822. unverifiedAccountKey := fmt.Sprintf(keyAccountExists, cfnick)
  823. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  824. if reserve {
  825. // unverified accounts don't show up in NickToAccount yet (which is intentional),
  826. // however you shouldn't be able to reserve a nick out from under them
  827. _, err := tx.Get(unverifiedAccountKey)
  828. if err == nil {
  829. return errNicknameReserved
  830. }
  831. }
  832. rawNicks, err := tx.Get(nicksKey)
  833. if err != nil && err != buntdb.ErrNotFound {
  834. return err
  835. }
  836. nicks := unmarshalReservedNicks(rawNicks)
  837. if reserve {
  838. if len(nicks) >= nrconfig.AdditionalNickLimit {
  839. return errAccountTooManyNicks
  840. }
  841. nicks = append(nicks, nick)
  842. } else {
  843. // compute (original reserved nicks) minus cfnick
  844. var newNicks []string
  845. for _, reservedNick := range nicks {
  846. cfreservednick, _ := CasefoldName(reservedNick)
  847. if cfreservednick != cfnick {
  848. newNicks = append(newNicks, reservedNick)
  849. } else {
  850. // found the original, unfolded version of the nick we're dropping;
  851. // recompute the true skeleton from it
  852. skeleton, _ = Skeleton(reservedNick)
  853. }
  854. }
  855. nicks = newNicks
  856. }
  857. marshaledNicks := marshalReservedNicks(nicks)
  858. _, _, err = tx.Set(nicksKey, string(marshaledNicks), nil)
  859. return err
  860. })
  861. if err == errAccountTooManyNicks || err == errNicknameReserved {
  862. return err
  863. } else if err != nil {
  864. return errAccountNickReservationFailed
  865. }
  866. // success
  867. am.Lock()
  868. defer am.Unlock()
  869. if reserve {
  870. am.nickToAccount[cfnick] = account
  871. am.skeletonToAccount[skeleton] = account
  872. } else {
  873. delete(am.nickToAccount, cfnick)
  874. delete(am.skeletonToAccount, skeleton)
  875. }
  876. return nil
  877. }
  878. func (am *AccountManager) checkPassphrase(accountName, passphrase string) (account ClientAccount, err error) {
  879. account, err = am.LoadAccount(accountName)
  880. if err != nil {
  881. return
  882. }
  883. if !account.Verified {
  884. err = errAccountUnverified
  885. return
  886. }
  887. switch account.Credentials.Version {
  888. case 0:
  889. err = handleLegacyPasswordV0(am.server, accountName, account.Credentials, passphrase)
  890. case 1:
  891. if passwd.CompareHashAndPassword(account.Credentials.PassphraseHash, []byte(passphrase)) != nil {
  892. err = errAccountInvalidCredentials
  893. }
  894. default:
  895. err = errAccountInvalidCredentials
  896. }
  897. return
  898. }
  899. func (am *AccountManager) AuthenticateByPassphrase(client *Client, accountName string, passphrase string) (err error) {
  900. // XXX check this now, so we don't allow a redundant login for an always-on client
  901. // even for a brief period. the other potential source of nick-account conflicts
  902. // is from force-nick-equals-account, but those will be caught later by
  903. // fixupNickEqualsAccount and if there is a conflict, they will be logged out.
  904. if client.registered {
  905. if clientAlready := am.server.clients.Get(accountName); clientAlready != nil && clientAlready.AlwaysOn() {
  906. return errNickAccountMismatch
  907. }
  908. }
  909. var account ClientAccount
  910. defer func() {
  911. if err == nil {
  912. am.Login(client, account)
  913. }
  914. }()
  915. ldapConf := am.server.Config().Accounts.LDAP
  916. if ldapConf.Enabled {
  917. err = ldap.CheckLDAPPassphrase(ldapConf, accountName, passphrase, am.server.logger)
  918. if err == nil {
  919. account, err = am.LoadAccount(accountName)
  920. // autocreate if necessary:
  921. if err == errAccountDoesNotExist && ldapConf.Autocreate {
  922. err = am.SARegister(accountName, "")
  923. if err != nil {
  924. return
  925. }
  926. account, err = am.LoadAccount(accountName)
  927. }
  928. return
  929. }
  930. }
  931. account, err = am.checkPassphrase(accountName, passphrase)
  932. return err
  933. }
  934. // AllNicks returns the uncasefolded nicknames for all accounts, including additional (grouped) nicks.
  935. func (am *AccountManager) AllNicks() (result []string) {
  936. accountNamePrefix := fmt.Sprintf(keyAccountName, "")
  937. accountAdditionalNicksPrefix := fmt.Sprintf(keyAccountAdditionalNicks, "")
  938. am.server.store.View(func(tx *buntdb.Tx) error {
  939. // Account names
  940. err := tx.AscendGreaterOrEqual("", accountNamePrefix, func(key, value string) bool {
  941. if !strings.HasPrefix(key, accountNamePrefix) {
  942. return false
  943. }
  944. result = append(result, value)
  945. return true
  946. })
  947. if err != nil {
  948. return err
  949. }
  950. // Additional nicks
  951. return tx.AscendGreaterOrEqual("", accountAdditionalNicksPrefix, func(key, value string) bool {
  952. if !strings.HasPrefix(key, accountAdditionalNicksPrefix) {
  953. return false
  954. }
  955. additionalNicks := unmarshalReservedNicks(value)
  956. for _, additionalNick := range additionalNicks {
  957. result = append(result, additionalNick)
  958. }
  959. return true
  960. })
  961. })
  962. sort.Strings(result)
  963. return
  964. }
  965. func (am *AccountManager) LoadAccount(accountName string) (result ClientAccount, err error) {
  966. casefoldedAccount, err := CasefoldName(accountName)
  967. if err != nil {
  968. err = errAccountDoesNotExist
  969. return
  970. }
  971. var raw rawClientAccount
  972. am.server.store.View(func(tx *buntdb.Tx) error {
  973. raw, err = am.loadRawAccount(tx, casefoldedAccount)
  974. return nil
  975. })
  976. if err != nil {
  977. return
  978. }
  979. result, err = am.deserializeRawAccount(raw, casefoldedAccount)
  980. return
  981. }
  982. // look up the unfolded version of an account name, possibly after deletion
  983. func (am *AccountManager) AccountToAccountName(account string) (result string) {
  984. casefoldedAccount, err := CasefoldName(account)
  985. if err != nil {
  986. return
  987. }
  988. unregisteredKey := fmt.Sprintf(keyAccountUnregistered, casefoldedAccount)
  989. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  990. am.server.store.View(func(tx *buntdb.Tx) error {
  991. if name, err := tx.Get(accountNameKey); err == nil {
  992. result = name
  993. return nil
  994. }
  995. if name, err := tx.Get(unregisteredKey); err == nil {
  996. result = name
  997. }
  998. return nil
  999. })
  1000. return
  1001. }
  1002. func (am *AccountManager) deserializeRawAccount(raw rawClientAccount, cfName string) (result ClientAccount, err error) {
  1003. result.Name = raw.Name
  1004. result.NameCasefolded = cfName
  1005. regTimeInt, _ := strconv.ParseInt(raw.RegisteredAt, 10, 64)
  1006. result.RegisteredAt = time.Unix(0, regTimeInt).UTC()
  1007. e := json.Unmarshal([]byte(raw.Credentials), &result.Credentials)
  1008. if e != nil {
  1009. am.server.logger.Error("internal", "could not unmarshal credentials", e.Error())
  1010. err = errAccountDoesNotExist
  1011. return
  1012. }
  1013. result.AdditionalNicks = unmarshalReservedNicks(raw.AdditionalNicks)
  1014. result.Verified = raw.Verified
  1015. if raw.VHost != "" {
  1016. e := json.Unmarshal([]byte(raw.VHost), &result.VHost)
  1017. if e != nil {
  1018. am.server.logger.Warning("internal", "could not unmarshal vhost for account", result.Name, e.Error())
  1019. // pretend they have no vhost and move on
  1020. }
  1021. }
  1022. if raw.Settings != "" {
  1023. e := json.Unmarshal([]byte(raw.Settings), &result.Settings)
  1024. if e != nil {
  1025. am.server.logger.Warning("internal", "could not unmarshal settings for account", result.Name, e.Error())
  1026. }
  1027. }
  1028. return
  1029. }
  1030. func (am *AccountManager) loadRawAccount(tx *buntdb.Tx, casefoldedAccount string) (result rawClientAccount, err error) {
  1031. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  1032. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  1033. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  1034. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  1035. verifiedKey := fmt.Sprintf(keyAccountVerified, casefoldedAccount)
  1036. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  1037. nicksKey := fmt.Sprintf(keyAccountAdditionalNicks, casefoldedAccount)
  1038. vhostKey := fmt.Sprintf(keyAccountVHost, casefoldedAccount)
  1039. settingsKey := fmt.Sprintf(keyAccountSettings, casefoldedAccount)
  1040. _, e := tx.Get(accountKey)
  1041. if e == buntdb.ErrNotFound {
  1042. err = errAccountDoesNotExist
  1043. return
  1044. }
  1045. result.Name, _ = tx.Get(accountNameKey)
  1046. result.RegisteredAt, _ = tx.Get(registeredTimeKey)
  1047. result.Credentials, _ = tx.Get(credentialsKey)
  1048. result.Callback, _ = tx.Get(callbackKey)
  1049. result.AdditionalNicks, _ = tx.Get(nicksKey)
  1050. result.VHost, _ = tx.Get(vhostKey)
  1051. result.Settings, _ = tx.Get(settingsKey)
  1052. if _, e = tx.Get(verifiedKey); e == nil {
  1053. result.Verified = true
  1054. }
  1055. return
  1056. }
  1057. func (am *AccountManager) Unregister(account string, erase bool) error {
  1058. config := am.server.Config()
  1059. casefoldedAccount, err := CasefoldName(account)
  1060. if err != nil {
  1061. return errAccountDoesNotExist
  1062. }
  1063. accountKey := fmt.Sprintf(keyAccountExists, casefoldedAccount)
  1064. accountNameKey := fmt.Sprintf(keyAccountName, casefoldedAccount)
  1065. registeredTimeKey := fmt.Sprintf(keyAccountRegTime, casefoldedAccount)
  1066. credentialsKey := fmt.Sprintf(keyAccountCredentials, casefoldedAccount)
  1067. callbackKey := fmt.Sprintf(keyAccountCallback, casefoldedAccount)
  1068. verificationCodeKey := fmt.Sprintf(keyAccountVerificationCode, casefoldedAccount)
  1069. verifiedKey := fmt.Sprintf(keyAccountVerified, casefoldedAccount)
  1070. nicksKey := fmt.Sprintf(keyAccountAdditionalNicks, casefoldedAccount)
  1071. settingsKey := fmt.Sprintf(keyAccountSettings, casefoldedAccount)
  1072. vhostKey := fmt.Sprintf(keyAccountVHost, casefoldedAccount)
  1073. vhostQueueKey := fmt.Sprintf(keyVHostQueueAcctToId, casefoldedAccount)
  1074. channelsKey := fmt.Sprintf(keyAccountChannels, casefoldedAccount)
  1075. joinedChannelsKey := fmt.Sprintf(keyAccountJoinedChannels, casefoldedAccount)
  1076. lastSeenKey := fmt.Sprintf(keyAccountLastSeen, casefoldedAccount)
  1077. unregisteredKey := fmt.Sprintf(keyAccountUnregistered, casefoldedAccount)
  1078. var clients []*Client
  1079. var registeredChannels []string
  1080. // on our way out, unregister all the account's channels and delete them from the db
  1081. defer func() {
  1082. for _, channelName := range registeredChannels {
  1083. err := am.server.channels.SetUnregistered(channelName, casefoldedAccount)
  1084. if err != nil {
  1085. am.server.logger.Error("internal", "couldn't unregister channel", channelName, err.Error())
  1086. }
  1087. }
  1088. }()
  1089. var credText string
  1090. var rawNicks string
  1091. am.serialCacheUpdateMutex.Lock()
  1092. defer am.serialCacheUpdateMutex.Unlock()
  1093. var accountName string
  1094. var channelsStr string
  1095. keepProtections := false
  1096. am.server.store.Update(func(tx *buntdb.Tx) error {
  1097. // get the unfolded account name; for an active account, this is
  1098. // stored under accountNameKey, for an unregistered account under unregisteredKey
  1099. accountName, _ = tx.Get(accountNameKey)
  1100. if accountName == "" {
  1101. accountName, _ = tx.Get(unregisteredKey)
  1102. }
  1103. if erase {
  1104. tx.Delete(unregisteredKey)
  1105. } else {
  1106. if _, err := tx.Get(verifiedKey); err == nil {
  1107. tx.Set(unregisteredKey, accountName, nil)
  1108. keepProtections = true
  1109. }
  1110. }
  1111. tx.Delete(accountKey)
  1112. tx.Delete(accountNameKey)
  1113. tx.Delete(verifiedKey)
  1114. tx.Delete(registeredTimeKey)
  1115. tx.Delete(callbackKey)
  1116. tx.Delete(verificationCodeKey)
  1117. tx.Delete(settingsKey)
  1118. rawNicks, _ = tx.Get(nicksKey)
  1119. tx.Delete(nicksKey)
  1120. credText, err = tx.Get(credentialsKey)
  1121. tx.Delete(credentialsKey)
  1122. tx.Delete(vhostKey)
  1123. channelsStr, _ = tx.Get(channelsKey)
  1124. tx.Delete(channelsKey)
  1125. tx.Delete(joinedChannelsKey)
  1126. tx.Delete(lastSeenKey)
  1127. _, err := tx.Delete(vhostQueueKey)
  1128. am.decrementVHostQueueCount(casefoldedAccount, err)
  1129. return nil
  1130. })
  1131. if err == nil {
  1132. var creds AccountCredentials
  1133. if err := json.Unmarshal([]byte(credText), &creds); err == nil {
  1134. for _, cert := range creds.Certfps {
  1135. certFPKey := fmt.Sprintf(keyCertToAccount, cert)
  1136. am.server.store.Update(func(tx *buntdb.Tx) error {
  1137. if account, err := tx.Get(certFPKey); err == nil && account == casefoldedAccount {
  1138. tx.Delete(certFPKey)
  1139. }
  1140. return nil
  1141. })
  1142. }
  1143. }
  1144. }
  1145. skeleton, _ := Skeleton(accountName)
  1146. additionalNicks := unmarshalReservedNicks(rawNicks)
  1147. registeredChannels = unmarshalRegisteredChannels(channelsStr)
  1148. am.Lock()
  1149. defer am.Unlock()
  1150. clients = am.accountToClients[casefoldedAccount]
  1151. delete(am.accountToClients, casefoldedAccount)
  1152. // protect the account name itself where applicable, but not any grouped nicks
  1153. if !(keepProtections && config.Accounts.NickReservation.Method == NickEnforcementStrict) {
  1154. delete(am.nickToAccount, casefoldedAccount)
  1155. delete(am.skeletonToAccount, skeleton)
  1156. }
  1157. for _, nick := range additionalNicks {
  1158. delete(am.nickToAccount, nick)
  1159. additionalSkel, _ := Skeleton(nick)
  1160. delete(am.skeletonToAccount, additionalSkel)
  1161. }
  1162. for _, client := range clients {
  1163. client.Logout()
  1164. client.Quit(client.t("You are no longer authorized to be on this server"), nil)
  1165. // destroy acquires a semaphore so we can't call it while holding a lock
  1166. go client.destroy(nil)
  1167. }
  1168. if err != nil && !erase {
  1169. return errAccountDoesNotExist
  1170. }
  1171. return nil
  1172. }
  1173. func unmarshalRegisteredChannels(channelsStr string) (result []string) {
  1174. if channelsStr != "" {
  1175. result = strings.Split(channelsStr, ",")
  1176. }
  1177. return
  1178. }
  1179. func (am *AccountManager) ChannelsForAccount(account string) (channels []string) {
  1180. cfaccount, err := CasefoldName(account)
  1181. if err != nil {
  1182. return
  1183. }
  1184. var channelStr string
  1185. key := fmt.Sprintf(keyAccountChannels, cfaccount)
  1186. am.server.store.View(func(tx *buntdb.Tx) error {
  1187. channelStr, _ = tx.Get(key)
  1188. return nil
  1189. })
  1190. return unmarshalRegisteredChannels(channelStr)
  1191. }
  1192. func (am *AccountManager) AuthenticateByCertFP(client *Client, certfp, authzid string) error {
  1193. if certfp == "" {
  1194. return errAccountInvalidCredentials
  1195. }
  1196. var account string
  1197. certFPKey := fmt.Sprintf(keyCertToAccount, certfp)
  1198. err := am.server.store.View(func(tx *buntdb.Tx) error {
  1199. account, _ = tx.Get(certFPKey)
  1200. if account == "" {
  1201. return errAccountInvalidCredentials
  1202. }
  1203. return nil
  1204. })
  1205. if err != nil {
  1206. return err
  1207. }
  1208. if authzid != "" && authzid != account {
  1209. return errAuthzidAuthcidMismatch
  1210. }
  1211. // ok, we found an account corresponding to their certificate
  1212. clientAccount, err := am.LoadAccount(account)
  1213. if err != nil {
  1214. return err
  1215. } else if !clientAccount.Verified {
  1216. return errAccountUnverified
  1217. }
  1218. if client.registered {
  1219. if clientAlready := am.server.clients.Get(clientAccount.Name); clientAlready != nil && clientAlready.AlwaysOn() {
  1220. return errNickAccountMismatch
  1221. }
  1222. }
  1223. am.Login(client, clientAccount)
  1224. return nil
  1225. }
  1226. type settingsMunger func(input AccountSettings) (output AccountSettings, err error)
  1227. func (am *AccountManager) ModifyAccountSettings(account string, munger settingsMunger) (newSettings AccountSettings, err error) {
  1228. casefoldedAccount, err := CasefoldName(account)
  1229. if err != nil {
  1230. return newSettings, errAccountDoesNotExist
  1231. }
  1232. // TODO implement this in general via a compare-and-swap API
  1233. accountData, err := am.LoadAccount(casefoldedAccount)
  1234. if err != nil {
  1235. return
  1236. } else if !accountData.Verified {
  1237. return newSettings, errAccountUnverified
  1238. }
  1239. newSettings, err = munger(accountData.Settings)
  1240. if err != nil {
  1241. return
  1242. }
  1243. text, err := json.Marshal(newSettings)
  1244. if err != nil {
  1245. return
  1246. }
  1247. key := fmt.Sprintf(keyAccountSettings, casefoldedAccount)
  1248. serializedValue := string(text)
  1249. err = am.server.store.Update(func(tx *buntdb.Tx) (err error) {
  1250. _, _, err = tx.Set(key, serializedValue, nil)
  1251. return
  1252. })
  1253. if err != nil {
  1254. err = errAccountUpdateFailed
  1255. return
  1256. }
  1257. // success, push new settings into the client objects
  1258. am.Lock()
  1259. defer am.Unlock()
  1260. for _, client := range am.accountToClients[casefoldedAccount] {
  1261. client.SetAccountSettings(newSettings)
  1262. }
  1263. return
  1264. }
  1265. // represents someone's status in hostserv
  1266. type VHostInfo struct {
  1267. ApprovedVHost string
  1268. Enabled bool
  1269. Forbidden bool
  1270. RequestedVHost string
  1271. RejectedVHost string
  1272. RejectionReason string
  1273. LastRequestTime time.Time
  1274. }
  1275. // pair type, <VHostInfo, accountName>
  1276. type PendingVHostRequest struct {
  1277. VHostInfo
  1278. Account string
  1279. }
  1280. type vhostThrottleExceeded struct {
  1281. timeRemaining time.Duration
  1282. }
  1283. func (vhe *vhostThrottleExceeded) Error() string {
  1284. return fmt.Sprintf("Wait at least %v and try again", vhe.timeRemaining)
  1285. }
  1286. func (vh *VHostInfo) checkThrottle(cooldown time.Duration) (err error) {
  1287. if cooldown == 0 {
  1288. return nil
  1289. }
  1290. now := time.Now().UTC()
  1291. elapsed := now.Sub(vh.LastRequestTime)
  1292. if elapsed > cooldown {
  1293. // success
  1294. vh.LastRequestTime = now
  1295. return nil
  1296. } else {
  1297. return &vhostThrottleExceeded{timeRemaining: cooldown - elapsed}
  1298. }
  1299. }
  1300. // callback type implementing the actual business logic of vhost operations
  1301. type vhostMunger func(input VHostInfo) (output VHostInfo, err error)
  1302. func (am *AccountManager) VHostSet(account string, vhost string) (result VHostInfo, err error) {
  1303. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1304. output = input
  1305. output.Enabled = true
  1306. output.ApprovedVHost = vhost
  1307. return
  1308. }
  1309. return am.performVHostChange(account, munger)
  1310. }
  1311. func (am *AccountManager) VHostRequest(account string, vhost string, cooldown time.Duration) (result VHostInfo, err error) {
  1312. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1313. output = input
  1314. if input.Forbidden {
  1315. err = errVhostsForbidden
  1316. return
  1317. }
  1318. // you can update your existing request, but if you were approved or rejected,
  1319. // you can't spam a new request
  1320. if output.RequestedVHost == "" {
  1321. err = output.checkThrottle(cooldown)
  1322. }
  1323. if err != nil {
  1324. return
  1325. }
  1326. output.RequestedVHost = vhost
  1327. output.RejectedVHost = ""
  1328. output.RejectionReason = ""
  1329. output.LastRequestTime = time.Now().UTC()
  1330. return
  1331. }
  1332. return am.performVHostChange(account, munger)
  1333. }
  1334. func (am *AccountManager) VHostTake(account string, vhost string, cooldown time.Duration) (result VHostInfo, err error) {
  1335. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1336. output = input
  1337. if input.Forbidden {
  1338. err = errVhostsForbidden
  1339. return
  1340. }
  1341. // if you have a request pending, you can cancel it using take;
  1342. // otherwise, you're subject to the same throttling as if you were making a request
  1343. if output.RequestedVHost == "" {
  1344. err = output.checkThrottle(cooldown)
  1345. }
  1346. if err != nil {
  1347. return
  1348. }
  1349. output.ApprovedVHost = vhost
  1350. output.RequestedVHost = ""
  1351. output.RejectedVHost = ""
  1352. output.RejectionReason = ""
  1353. output.LastRequestTime = time.Now().UTC()
  1354. return
  1355. }
  1356. return am.performVHostChange(account, munger)
  1357. }
  1358. func (am *AccountManager) VHostApprove(account string) (result VHostInfo, err error) {
  1359. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1360. output = input
  1361. output.Enabled = true
  1362. output.ApprovedVHost = input.RequestedVHost
  1363. output.RequestedVHost = ""
  1364. output.RejectionReason = ""
  1365. return
  1366. }
  1367. return am.performVHostChange(account, munger)
  1368. }
  1369. func (am *AccountManager) VHostReject(account string, reason string) (result VHostInfo, err error) {
  1370. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1371. output = input
  1372. output.RejectedVHost = output.RequestedVHost
  1373. output.RequestedVHost = ""
  1374. output.RejectionReason = reason
  1375. return
  1376. }
  1377. return am.performVHostChange(account, munger)
  1378. }
  1379. func (am *AccountManager) VHostSetEnabled(client *Client, enabled bool) (result VHostInfo, err error) {
  1380. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1381. if input.ApprovedVHost == "" {
  1382. err = errNoVhost
  1383. return
  1384. }
  1385. output = input
  1386. output.Enabled = enabled
  1387. return
  1388. }
  1389. return am.performVHostChange(client.Account(), munger)
  1390. }
  1391. func (am *AccountManager) VHostForbid(account string, forbid bool) (result VHostInfo, err error) {
  1392. munger := func(input VHostInfo) (output VHostInfo, err error) {
  1393. output = input
  1394. output.Forbidden = forbid
  1395. return
  1396. }
  1397. return am.performVHostChange(account, munger)
  1398. }
  1399. func (am *AccountManager) performVHostChange(account string, munger vhostMunger) (result VHostInfo, err error) {
  1400. account, err = CasefoldName(account)
  1401. if err != nil || account == "" {
  1402. err = errAccountDoesNotExist
  1403. return
  1404. }
  1405. am.vHostUpdateMutex.Lock()
  1406. defer am.vHostUpdateMutex.Unlock()
  1407. clientAccount, err := am.LoadAccount(account)
  1408. if err != nil {
  1409. err = errAccountDoesNotExist
  1410. return
  1411. } else if !clientAccount.Verified {
  1412. err = errAccountUnverified
  1413. return
  1414. }
  1415. result, err = munger(clientAccount.VHost)
  1416. if err != nil {
  1417. return
  1418. }
  1419. vhtext, err := json.Marshal(result)
  1420. if err != nil {
  1421. err = errAccountUpdateFailed
  1422. return
  1423. }
  1424. vhstr := string(vhtext)
  1425. key := fmt.Sprintf(keyAccountVHost, account)
  1426. queueKey := fmt.Sprintf(keyVHostQueueAcctToId, account)
  1427. err = am.server.store.Update(func(tx *buntdb.Tx) error {
  1428. if _, _, err := tx.Set(key, vhstr, nil); err != nil {
  1429. return err
  1430. }
  1431. // update request queue
  1432. if clientAccount.VHost.RequestedVHost == "" && result.RequestedVHost != "" {
  1433. id := atomic.AddUint64(&am.vhostRequestID, 1)
  1434. if _, _, err = tx.Set(queueKey, strconv.FormatUint(id, 10), nil); err != nil {
  1435. return err
  1436. }
  1437. atomic.AddUint64(&am.vhostRequestPendingCount, 1)
  1438. } else if clientAccount.VHost.RequestedVHost != "" && result.RequestedVHost == "" {
  1439. _, err = tx.Delete(queueKey)
  1440. am.decrementVHostQueueCount(account, err)
  1441. }
  1442. return nil
  1443. })
  1444. if err != nil {
  1445. err = errAccountUpdateFailed
  1446. return
  1447. }
  1448. am.applyVhostToClients(account, result)
  1449. return result, nil
  1450. }
  1451. // XXX annoying helper method for keeping the queue count in sync with the DB
  1452. // `err` is the buntdb error returned from deleting the queue key
  1453. func (am *AccountManager) decrementVHostQueueCount(account string, err error) {
  1454. if err == nil {
  1455. // successfully deleted a queue entry, do a 2's complement decrement:
  1456. atomic.AddUint64(&am.vhostRequestPendingCount, ^uint64(0))
  1457. } else if err != buntdb.ErrNotFound {
  1458. am.server.logger.Error("internal", "buntdb dequeue error", account, err.Error())
  1459. }
  1460. }
  1461. func (am *AccountManager) VHostListRequests(limit int) (requests []PendingVHostRequest, total int) {
  1462. am.vHostUpdateMutex.Lock()
  1463. defer am.vHostUpdateMutex.Unlock()
  1464. total = int(atomic.LoadUint64(&am.vhostRequestPendingCount))
  1465. prefix := fmt.Sprintf(keyVHostQueueAcctToId, "")
  1466. accounts := make([]string, 0, limit)
  1467. err := am.server.store.View(func(tx *buntdb.Tx) error {
  1468. return tx.Ascend(vhostRequestIdx, func(key, value string) bool {
  1469. accounts = append(accounts, strings.TrimPrefix(key, prefix))
  1470. return len(accounts) < limit
  1471. })
  1472. })
  1473. if err != nil {
  1474. am.server.logger.Error("internal", "couldn't traverse vhost queue", err.Error())
  1475. return
  1476. }
  1477. for _, account := range accounts {
  1478. accountInfo, err := am.LoadAccount(account)
  1479. if err == nil {
  1480. requests = append(requests, PendingVHostRequest{
  1481. Account: account,
  1482. VHostInfo: accountInfo.VHost,
  1483. })
  1484. } else {
  1485. am.server.logger.Error("internal", "corrupt account", account, err.Error())
  1486. }
  1487. }
  1488. return
  1489. }
  1490. func (am *AccountManager) applyVHostInfo(client *Client, info VHostInfo) {
  1491. // if hostserv is disabled in config, then don't grant vhosts
  1492. // that were previously approved while it was enabled
  1493. if !am.server.Config().Accounts.VHosts.Enabled {
  1494. return
  1495. }
  1496. vhost := ""
  1497. if info.Enabled && !info.Forbidden {
  1498. vhost = info.ApprovedVHost
  1499. }
  1500. oldNickmask := client.NickMaskString()
  1501. updated := client.SetVHost(vhost)
  1502. if updated {
  1503. // TODO: doing I/O here is kind of a kludge
  1504. go client.sendChghost(oldNickmask, client.Hostname())
  1505. }
  1506. }
  1507. func (am *AccountManager) applyVhostToClients(account string, result VHostInfo) {
  1508. am.RLock()
  1509. clients := am.accountToClients[account]
  1510. am.RUnlock()
  1511. for _, client := range clients {
  1512. am.applyVHostInfo(client, result)
  1513. }
  1514. }
  1515. func (am *AccountManager) Login(client *Client, account ClientAccount) {
  1516. client.Login(account)
  1517. client.nickTimer.Touch(nil)
  1518. am.applyVHostInfo(client, account.VHost)
  1519. casefoldedAccount := client.Account()
  1520. am.Lock()
  1521. defer am.Unlock()
  1522. am.accountToClients[casefoldedAccount] = append(am.accountToClients[casefoldedAccount], client)
  1523. }
  1524. func (am *AccountManager) Logout(client *Client) {
  1525. am.Lock()
  1526. defer am.Unlock()
  1527. casefoldedAccount := client.Account()
  1528. if casefoldedAccount == "" {
  1529. return
  1530. }
  1531. am.logoutOfAccount(client)
  1532. clients := am.accountToClients[casefoldedAccount]
  1533. if len(clients) <= 1 {
  1534. delete(am.accountToClients, casefoldedAccount)
  1535. return
  1536. }
  1537. remainingClients := make([]*Client, len(clients)-1)
  1538. remainingPos := 0
  1539. for currentPos := 0; currentPos < len(clients); currentPos++ {
  1540. if clients[currentPos] != client {
  1541. remainingClients[remainingPos] = clients[currentPos]
  1542. remainingPos++
  1543. }
  1544. }
  1545. am.accountToClients[casefoldedAccount] = remainingClients
  1546. }
  1547. var (
  1548. // EnabledSaslMechanisms contains the SASL mechanisms that exist and that we support.
  1549. // This can be moved to some other data structure/place if we need to load/unload mechs later.
  1550. EnabledSaslMechanisms = map[string]func(*Server, *Client, string, []byte, *ResponseBuffer) bool{
  1551. "PLAIN": authPlainHandler,
  1552. "EXTERNAL": authExternalHandler,
  1553. }
  1554. )
  1555. // AccountCredentials stores the various methods for verifying accounts.
  1556. type AccountCredentials struct {
  1557. Version uint
  1558. PassphraseSalt []byte // legacy field, not used by v1 and later
  1559. PassphraseHash []byte
  1560. Certfps []string
  1561. }
  1562. func (ac *AccountCredentials) Empty() bool {
  1563. return len(ac.PassphraseHash) == 0 && len(ac.Certfps) == 0
  1564. }
  1565. // helper to assemble the serialized JSON for an account's credentials
  1566. func (ac *AccountCredentials) Serialize() (result string, err error) {
  1567. ac.Version = 1
  1568. credText, err := json.Marshal(*ac)
  1569. if err != nil {
  1570. return "", err
  1571. }
  1572. return string(credText), nil
  1573. }
  1574. func (ac *AccountCredentials) SetPassphrase(passphrase string, bcryptCost uint) (err error) {
  1575. if passphrase == "" {
  1576. ac.PassphraseHash = nil
  1577. return nil
  1578. }
  1579. if validatePassphrase(passphrase) != nil {
  1580. return errAccountBadPassphrase
  1581. }
  1582. ac.PassphraseHash, err = passwd.GenerateFromPassword([]byte(passphrase), int(bcryptCost))
  1583. if err != nil {
  1584. return errAccountBadPassphrase
  1585. }
  1586. return nil
  1587. }
  1588. func (ac *AccountCredentials) AddCertfp(certfp string) (err error) {
  1589. // XXX we require that certfp is already normalized (rather than normalize here
  1590. // and pass back the normalized version as an additional return parameter);
  1591. // this is just a final sanity check:
  1592. if len(certfp) != 64 {
  1593. return utils.ErrInvalidCertfp
  1594. }
  1595. for _, current := range ac.Certfps {
  1596. if certfp == current {
  1597. return errNoop
  1598. }
  1599. }
  1600. if maxCertfpsPerAccount <= len(ac.Certfps) {
  1601. return errLimitExceeded
  1602. }
  1603. ac.Certfps = append(ac.Certfps, certfp)
  1604. return nil
  1605. }
  1606. func (ac *AccountCredentials) RemoveCertfp(certfp string) (err error) {
  1607. found := false
  1608. newList := make([]string, 0, len(ac.Certfps))
  1609. for _, current := range ac.Certfps {
  1610. if current == certfp {
  1611. found = true
  1612. } else {
  1613. newList = append(newList, current)
  1614. }
  1615. }
  1616. if !found {
  1617. // this is important because it prevents you from deleting someone else's
  1618. // fingerprint record
  1619. return errNoop
  1620. }
  1621. ac.Certfps = newList
  1622. return nil
  1623. }
  1624. type MulticlientAllowedSetting int
  1625. const (
  1626. MulticlientAllowedServerDefault MulticlientAllowedSetting = iota
  1627. MulticlientDisallowedByUser
  1628. MulticlientAllowedByUser
  1629. )
  1630. // controls whether/when clients without event-playback support see fake
  1631. // PRIVMSGs for JOINs
  1632. type ReplayJoinsSetting uint
  1633. const (
  1634. ReplayJoinsCommandsOnly = iota // replay in HISTORY or CHATHISTORY output
  1635. ReplayJoinsAlways // replay in HISTORY, CHATHISTORY, or autoreplay
  1636. ReplayJoinsNever // never replay
  1637. )
  1638. func replayJoinsSettingFromString(str string) (result ReplayJoinsSetting, err error) {
  1639. switch strings.ToLower(str) {
  1640. case "commands-only":
  1641. result = ReplayJoinsCommandsOnly
  1642. case "always":
  1643. result = ReplayJoinsAlways
  1644. case "never":
  1645. result = ReplayJoinsNever
  1646. default:
  1647. err = errInvalidParams
  1648. }
  1649. return
  1650. }
  1651. // XXX: AllowBouncer cannot be renamed AllowMulticlient because it is stored in
  1652. // persistent JSON blobs in the database
  1653. type AccountSettings struct {
  1654. AutoreplayLines *int
  1655. NickEnforcement NickEnforcementMethod
  1656. AllowBouncer MulticlientAllowedSetting
  1657. ReplayJoins ReplayJoinsSetting
  1658. AlwaysOn PersistentStatus
  1659. AutoreplayMissed bool
  1660. DMHistory HistoryStatus
  1661. AutoAway PersistentStatus
  1662. }
  1663. // ClientAccount represents a user account.
  1664. type ClientAccount struct {
  1665. // Name of the account.
  1666. Name string
  1667. NameCasefolded string
  1668. RegisteredAt time.Time
  1669. Credentials AccountCredentials
  1670. Verified bool
  1671. AdditionalNicks []string
  1672. VHost VHostInfo
  1673. Settings AccountSettings
  1674. }
  1675. // convenience for passing around raw serialized account data
  1676. type rawClientAccount struct {
  1677. Name string
  1678. RegisteredAt string
  1679. Credentials string
  1680. Callback string
  1681. Verified bool
  1682. AdditionalNicks string
  1683. VHost string
  1684. Settings string
  1685. }
  1686. // logoutOfAccount logs the client out of their current account.
  1687. // TODO(#1027) delete this entire method and just use client.Logout()
  1688. func (am *AccountManager) logoutOfAccount(client *Client) {
  1689. if client.Account() == "" {
  1690. // already logged out
  1691. return
  1692. }
  1693. client.Logout()
  1694. go client.nickTimer.Touch(nil)
  1695. }