您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

accounts.go 54KB

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