You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

accounts.go 57KB

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