Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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