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.

getters.go 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. // Copyright (c) 2017 Shivaram Lingamneni <slingamn@cs.stanford.edu>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "fmt"
  6. "net"
  7. "time"
  8. "github.com/ergochat/ergo/irc/caps"
  9. "github.com/ergochat/ergo/irc/languages"
  10. "github.com/ergochat/ergo/irc/modes"
  11. "github.com/ergochat/ergo/irc/utils"
  12. )
  13. func (server *Server) Config() (config *Config) {
  14. return server.config.Load()
  15. }
  16. func (server *Server) ChannelRegistrationEnabled() bool {
  17. return server.Config().Channels.Registration.Enabled
  18. }
  19. func (server *Server) GetOperator(name string) (oper *Oper) {
  20. name, err := CasefoldName(name)
  21. if err != nil {
  22. return
  23. }
  24. return server.Config().operators[name]
  25. }
  26. func (server *Server) Languages() (lm *languages.Manager) {
  27. return server.Config().languageManager
  28. }
  29. func (server *Server) Defcon() uint32 {
  30. return server.defcon.Load()
  31. }
  32. func (server *Server) SetDefcon(defcon uint32) {
  33. server.defcon.Store(defcon)
  34. }
  35. func (client *Client) Sessions() (sessions []*Session) {
  36. client.stateMutex.RLock()
  37. sessions = client.sessions
  38. client.stateMutex.RUnlock()
  39. return
  40. }
  41. type SessionData struct {
  42. ctime time.Time
  43. atime time.Time
  44. ip net.IP
  45. hostname string
  46. certfp string
  47. deviceID string
  48. connInfo string
  49. sessionID int64
  50. caps []string
  51. }
  52. func (client *Client) AllSessionData(currentSession *Session, hasPrivs bool) (data []SessionData, currentIndex int) {
  53. currentIndex = -1
  54. client.stateMutex.RLock()
  55. defer client.stateMutex.RUnlock()
  56. data = make([]SessionData, len(client.sessions))
  57. for i, session := range client.sessions {
  58. if session == currentSession {
  59. currentIndex = i
  60. }
  61. data[i] = SessionData{
  62. atime: session.lastActive,
  63. ctime: session.ctime,
  64. hostname: session.rawHostname,
  65. certfp: session.certfp,
  66. deviceID: session.deviceID,
  67. sessionID: session.sessionID,
  68. }
  69. if session.proxiedIP != nil {
  70. data[i].ip = session.proxiedIP
  71. } else {
  72. data[i].ip = session.realIP
  73. }
  74. if hasPrivs {
  75. data[i].connInfo = utils.DescribeConn(session.socket.conn.UnderlyingConn().Conn)
  76. }
  77. data[i].caps = session.capabilities.Strings(caps.Cap302, nil, 300)
  78. }
  79. return
  80. }
  81. func (client *Client) AddSession(session *Session) (success bool, numSessions int, lastSeen time.Time, wasAway, nowAway string) {
  82. config := client.server.Config()
  83. client.stateMutex.Lock()
  84. defer client.stateMutex.Unlock()
  85. // client may be dying and ineligible to receive another session
  86. if client.destroyed {
  87. return
  88. }
  89. // success, attach the new session to the client
  90. session.client = client
  91. session.sessionID = client.nextSessionID
  92. client.nextSessionID++
  93. newSessions := make([]*Session, len(client.sessions)+1)
  94. copy(newSessions, client.sessions)
  95. newSessions[len(newSessions)-1] = session
  96. if client.accountSettings.AutoreplayMissed || session.deviceID != "" {
  97. lastSeen = client.lastSeen[session.deviceID]
  98. client.setLastSeen(time.Now().UTC(), session.deviceID)
  99. }
  100. client.sessions = newSessions
  101. wasAway = client.awayMessage
  102. if client.autoAwayEnabledNoMutex(config) {
  103. client.setAutoAwayNoMutex(config)
  104. } else {
  105. if session.awayMessage != "" && session.awayMessage != "*" {
  106. // set the away message
  107. client.awayMessage = session.awayMessage
  108. } else if session.awayMessage == "" && !session.awayAt.IsZero() {
  109. // weird edge case: explicit `AWAY` or `AWAY :` during pre-registration makes the client back
  110. client.awayMessage = ""
  111. }
  112. // else: the client sent no AWAY command at all, no-op
  113. // or: the client sent `AWAY *`, which should not modify the publicly visible away state
  114. }
  115. nowAway = client.awayMessage
  116. return true, len(client.sessions), lastSeen, wasAway, nowAway
  117. }
  118. func (client *Client) removeSession(session *Session) (success bool, length int) {
  119. if len(client.sessions) == 0 {
  120. return
  121. }
  122. sessions := make([]*Session, 0, len(client.sessions)-1)
  123. for _, currentSession := range client.sessions {
  124. if session == currentSession {
  125. success = true
  126. } else {
  127. sessions = append(sessions, currentSession)
  128. }
  129. }
  130. client.sessions = sessions
  131. length = len(sessions)
  132. return
  133. }
  134. // #1650: show an arbitrarily chosen session IP and hostname in RPL_WHOISACTUALLY
  135. func (client *Client) getWhoisActually() (ip net.IP, hostname string) {
  136. client.stateMutex.RLock()
  137. defer client.stateMutex.RUnlock()
  138. for _, session := range client.sessions {
  139. return session.IP(), session.rawHostname
  140. }
  141. return utils.IPv4LoopbackAddress, client.server.name
  142. }
  143. func (client *Client) Nick() string {
  144. client.stateMutex.RLock()
  145. defer client.stateMutex.RUnlock()
  146. return client.nick
  147. }
  148. func (client *Client) NickMaskString() string {
  149. client.stateMutex.RLock()
  150. defer client.stateMutex.RUnlock()
  151. return client.nickMaskString
  152. }
  153. func (client *Client) NickCasefolded() string {
  154. client.stateMutex.RLock()
  155. defer client.stateMutex.RUnlock()
  156. return client.nickCasefolded
  157. }
  158. func (client *Client) NickMaskCasefolded() string {
  159. client.stateMutex.RLock()
  160. defer client.stateMutex.RUnlock()
  161. return client.nickMaskCasefolded
  162. }
  163. func (client *Client) Username() string {
  164. client.stateMutex.RLock()
  165. defer client.stateMutex.RUnlock()
  166. return client.username
  167. }
  168. func (client *Client) Hostname() string {
  169. client.stateMutex.RLock()
  170. defer client.stateMutex.RUnlock()
  171. return client.hostname
  172. }
  173. func (client *Client) Away() (result bool, message string) {
  174. client.stateMutex.Lock()
  175. message = client.awayMessage
  176. client.stateMutex.Unlock()
  177. result = client.awayMessage != ""
  178. return
  179. }
  180. func (session *Session) SetAway(awayMessage string) (wasAway, nowAway string) {
  181. client := session.client
  182. config := client.server.Config()
  183. client.stateMutex.Lock()
  184. defer client.stateMutex.Unlock()
  185. session.awayMessage = awayMessage
  186. session.awayAt = time.Now().UTC()
  187. wasAway = client.awayMessage
  188. if client.autoAwayEnabledNoMutex(config) {
  189. client.setAutoAwayNoMutex(config)
  190. } else if awayMessage != "*" {
  191. client.awayMessage = awayMessage
  192. } // else: `AWAY *`, should not modify publicly visible away state
  193. nowAway = client.awayMessage
  194. return
  195. }
  196. func (client *Client) autoAwayEnabledNoMutex(config *Config) bool {
  197. return client.registered && client.alwaysOn &&
  198. persistenceEnabled(config.Accounts.Multiclient.AutoAway, client.accountSettings.AutoAway)
  199. }
  200. func (client *Client) setAutoAwayNoMutex(config *Config) {
  201. // aggregate the away statuses of the individual sessions:
  202. var globalAwayState string
  203. var awaySetAt time.Time
  204. for _, cSession := range client.sessions {
  205. if cSession.awayMessage == "" {
  206. // a session is active, we are not auto-away
  207. client.awayMessage = ""
  208. return
  209. } else if cSession.awayAt.After(awaySetAt) && cSession.awayMessage != "*" {
  210. // choose the latest valid away message from any session
  211. globalAwayState = cSession.awayMessage
  212. awaySetAt = cSession.awayAt
  213. }
  214. }
  215. if awaySetAt.IsZero() {
  216. // no sessions, enable auto-away
  217. client.awayMessage = config.languageManager.Translate(client.languages, `User is currently disconnected`)
  218. } else {
  219. client.awayMessage = globalAwayState
  220. }
  221. }
  222. func (client *Client) AlwaysOn() (alwaysOn bool) {
  223. client.stateMutex.RLock()
  224. alwaysOn = client.registered && client.alwaysOn
  225. client.stateMutex.RUnlock()
  226. return
  227. }
  228. // uniqueIdentifiers returns the strings for which the server enforces per-client
  229. // uniqueness/ownership; no two clients can have colliding casefolded nicks or
  230. // skeletons.
  231. func (client *Client) uniqueIdentifiers() (nickCasefolded string, skeleton string) {
  232. client.stateMutex.RLock()
  233. defer client.stateMutex.RUnlock()
  234. return client.nickCasefolded, client.skeleton
  235. }
  236. func (client *Client) Oper() *Oper {
  237. client.stateMutex.RLock()
  238. defer client.stateMutex.RUnlock()
  239. return client.oper
  240. }
  241. func (client *Client) Registered() (result bool) {
  242. // `registered` is only written from the client's own goroutine, but may be
  243. // read from other goroutines; therefore, the client's own goroutine may read
  244. // the value without synchronization, but must write it with synchronization,
  245. // and other goroutines must read it with synchronization
  246. client.stateMutex.RLock()
  247. result = client.registered
  248. client.stateMutex.RUnlock()
  249. return
  250. }
  251. func (client *Client) RawHostname() (result string) {
  252. client.stateMutex.Lock()
  253. result = client.rawHostname
  254. client.stateMutex.Unlock()
  255. return
  256. }
  257. func (client *Client) AwayMessage() (result string) {
  258. client.stateMutex.RLock()
  259. result = client.awayMessage
  260. client.stateMutex.RUnlock()
  261. return
  262. }
  263. func (client *Client) Account() string {
  264. client.stateMutex.RLock()
  265. defer client.stateMutex.RUnlock()
  266. return client.account
  267. }
  268. func (client *Client) AccountName() string {
  269. client.stateMutex.RLock()
  270. defer client.stateMutex.RUnlock()
  271. return client.accountName
  272. }
  273. func (client *Client) Login(account ClientAccount) {
  274. alwaysOn := persistenceEnabled(client.server.Config().Accounts.Multiclient.AlwaysOn, account.Settings.AlwaysOn)
  275. client.stateMutex.Lock()
  276. defer client.stateMutex.Unlock()
  277. client.account = account.NameCasefolded
  278. client.accountName = account.Name
  279. client.accountSettings = account.Settings
  280. // mark always-on here: it will not be respected until the client is registered
  281. client.alwaysOn = alwaysOn
  282. client.accountRegDate = account.RegisteredAt
  283. return
  284. }
  285. func (client *Client) setAccountName(name string) {
  286. // XXX this assumes validation elsewhere
  287. client.stateMutex.Lock()
  288. defer client.stateMutex.Unlock()
  289. client.accountName = name
  290. }
  291. func (client *Client) setCloakedHostname(cloak string) {
  292. client.stateMutex.Lock()
  293. defer client.stateMutex.Unlock()
  294. client.cloakedHostname = cloak
  295. client.updateNickMaskNoMutex()
  296. }
  297. func (client *Client) CloakedHostname() string {
  298. client.stateMutex.Lock()
  299. defer client.stateMutex.Unlock()
  300. return client.cloakedHostname
  301. }
  302. func (client *Client) historyCutoff() (cutoff time.Time) {
  303. client.stateMutex.Lock()
  304. if client.account != "" {
  305. cutoff = client.accountRegDate
  306. } else {
  307. cutoff = client.ctime
  308. }
  309. client.stateMutex.Unlock()
  310. return
  311. }
  312. func (client *Client) Logout() {
  313. client.stateMutex.Lock()
  314. client.account = ""
  315. client.accountName = "*"
  316. client.alwaysOn = false
  317. client.accountRegDate = time.Time{}
  318. client.accountSettings = AccountSettings{}
  319. client.stateMutex.Unlock()
  320. }
  321. func (client *Client) AccountSettings() (result AccountSettings) {
  322. client.stateMutex.RLock()
  323. result = client.accountSettings
  324. client.stateMutex.RUnlock()
  325. return
  326. }
  327. func (client *Client) SetAccountSettings(settings AccountSettings) {
  328. // we mark dirty if the client is transitioning to always-on
  329. var becameAlwaysOn bool
  330. alwaysOn := persistenceEnabled(client.server.Config().Accounts.Multiclient.AlwaysOn, settings.AlwaysOn)
  331. client.stateMutex.Lock()
  332. if client.registered {
  333. // only allow the client to become always-on if their nick equals their account name
  334. alwaysOn = alwaysOn && client.nick == client.accountName
  335. becameAlwaysOn = (!client.alwaysOn && alwaysOn)
  336. client.alwaysOn = alwaysOn
  337. }
  338. client.accountSettings = settings
  339. client.stateMutex.Unlock()
  340. if becameAlwaysOn {
  341. client.markDirty(IncludeAllAttrs)
  342. }
  343. }
  344. func (client *Client) Languages() (languages []string) {
  345. client.stateMutex.RLock()
  346. languages = client.languages
  347. client.stateMutex.RUnlock()
  348. return languages
  349. }
  350. func (client *Client) SetLanguages(languages []string) {
  351. client.stateMutex.Lock()
  352. client.languages = languages
  353. client.stateMutex.Unlock()
  354. }
  355. func (client *Client) HasMode(mode modes.Mode) bool {
  356. // client.flags has its own synch
  357. return client.modes.HasMode(mode)
  358. }
  359. func (client *Client) SetMode(mode modes.Mode, on bool) bool {
  360. return client.modes.SetMode(mode, on)
  361. }
  362. func (client *Client) SetRealname(realname string) {
  363. client.stateMutex.Lock()
  364. client.realname = realname
  365. alwaysOn := client.registered && client.alwaysOn
  366. client.stateMutex.Unlock()
  367. if alwaysOn {
  368. client.markDirty(IncludeRealname)
  369. }
  370. }
  371. func (client *Client) Channels() (result []*Channel) {
  372. client.stateMutex.RLock()
  373. defer client.stateMutex.RUnlock()
  374. length := len(client.channels)
  375. result = make([]*Channel, length)
  376. i := 0
  377. for channel := range client.channels {
  378. result[i] = channel
  379. i++
  380. }
  381. return
  382. }
  383. func (client *Client) NumChannels() int {
  384. client.stateMutex.RLock()
  385. defer client.stateMutex.RUnlock()
  386. return len(client.channels)
  387. }
  388. func (client *Client) WhoWas() (result WhoWas) {
  389. return client.Details().WhoWas
  390. }
  391. func (client *Client) Details() (result ClientDetails) {
  392. client.stateMutex.RLock()
  393. defer client.stateMutex.RUnlock()
  394. return client.detailsNoMutex()
  395. }
  396. func (client *Client) detailsNoMutex() (result ClientDetails) {
  397. result.nick = client.nick
  398. result.nickCasefolded = client.nickCasefolded
  399. result.username = client.username
  400. result.hostname = client.hostname
  401. result.realname = client.realname
  402. result.ip = client.getIPNoMutex()
  403. result.nickMask = client.nickMaskString
  404. result.nickMaskCasefolded = client.nickMaskCasefolded
  405. result.account = client.account
  406. result.accountName = client.accountName
  407. return
  408. }
  409. func (client *Client) UpdateActive(session *Session) {
  410. now := time.Now().UTC()
  411. client.stateMutex.Lock()
  412. defer client.stateMutex.Unlock()
  413. client.lastActive = now
  414. session.lastActive = now
  415. }
  416. func (client *Client) Realname() string {
  417. client.stateMutex.RLock()
  418. result := client.realname
  419. client.stateMutex.RUnlock()
  420. return result
  421. }
  422. func (client *Client) IsExpiredAlwaysOn(config *Config) (result bool) {
  423. client.stateMutex.Lock()
  424. defer client.stateMutex.Unlock()
  425. return client.checkAlwaysOnExpirationNoMutex(config, false)
  426. }
  427. func (client *Client) checkAlwaysOnExpirationNoMutex(config *Config, ignoreRegistration bool) (result bool) {
  428. if !((client.registered || ignoreRegistration) && client.alwaysOn) {
  429. return false
  430. }
  431. deadline := time.Duration(config.Accounts.Multiclient.AlwaysOnExpiration)
  432. if deadline == 0 {
  433. return false
  434. }
  435. now := time.Now()
  436. for _, ts := range client.lastSeen {
  437. if now.Sub(ts) < deadline {
  438. return false
  439. }
  440. }
  441. return true
  442. }
  443. func (client *Client) GetReadMarker(cfname string) (result string) {
  444. client.stateMutex.RLock()
  445. t, ok := client.readMarkers[cfname]
  446. client.stateMutex.RUnlock()
  447. if ok {
  448. return fmt.Sprintf("timestamp=%s", t.Format(IRCv3TimestampFormat))
  449. }
  450. return "*"
  451. }
  452. func (client *Client) copyReadMarkers() (result map[string]time.Time) {
  453. client.stateMutex.RLock()
  454. defer client.stateMutex.RUnlock()
  455. return utils.CopyMap(client.readMarkers)
  456. }
  457. func (client *Client) SetReadMarker(cfname string, now time.Time) (result time.Time) {
  458. client.stateMutex.Lock()
  459. defer client.stateMutex.Unlock()
  460. if client.readMarkers == nil {
  461. client.readMarkers = make(map[string]time.Time)
  462. }
  463. result = updateLRUMap(client.readMarkers, cfname, now, maxReadMarkers)
  464. client.dirtyTimestamps = true
  465. return
  466. }
  467. func updateLRUMap(lru map[string]time.Time, key string, val time.Time, maxItems int) (result time.Time) {
  468. if currentVal := lru[key]; currentVal.After(val) {
  469. return currentVal
  470. }
  471. lru[key] = val
  472. // evict the least-recently-used entry if necessary
  473. if maxItems < len(lru) {
  474. var minKey string
  475. var minVal time.Time
  476. for key, val := range lru {
  477. if minVal.IsZero() || val.Before(minVal) {
  478. minKey, minVal = key, val
  479. }
  480. }
  481. delete(lru, minKey)
  482. }
  483. return val
  484. }
  485. func (client *Client) shouldFlushTimestamps() (result bool) {
  486. client.stateMutex.Lock()
  487. defer client.stateMutex.Unlock()
  488. result = client.dirtyTimestamps && client.registered && client.alwaysOn
  489. client.dirtyTimestamps = false
  490. return
  491. }
  492. func (client *Client) setKlined() {
  493. client.stateMutex.Lock()
  494. client.isKlined = true
  495. client.stateMutex.Unlock()
  496. }
  497. func (channel *Channel) Name() string {
  498. channel.stateMutex.RLock()
  499. defer channel.stateMutex.RUnlock()
  500. return channel.name
  501. }
  502. func (channel *Channel) NameCasefolded() string {
  503. channel.stateMutex.RLock()
  504. defer channel.stateMutex.RUnlock()
  505. return channel.nameCasefolded
  506. }
  507. func (channel *Channel) Rename(name, nameCasefolded string) {
  508. channel.stateMutex.Lock()
  509. channel.name = name
  510. if channel.nameCasefolded != nameCasefolded {
  511. channel.nameCasefolded = nameCasefolded
  512. if channel.registeredFounder != "" {
  513. channel.registeredTime = time.Now().UTC()
  514. }
  515. }
  516. channel.stateMutex.Unlock()
  517. }
  518. func (channel *Channel) Members() (result []*Client) {
  519. channel.stateMutex.RLock()
  520. defer channel.stateMutex.RUnlock()
  521. return channel.membersCache
  522. }
  523. func (channel *Channel) setUserLimit(limit int) {
  524. channel.stateMutex.Lock()
  525. channel.userLimit = limit
  526. channel.stateMutex.Unlock()
  527. }
  528. func (channel *Channel) setKey(key string) {
  529. channel.stateMutex.Lock()
  530. defer channel.stateMutex.Unlock()
  531. channel.key = key
  532. }
  533. func (channel *Channel) Founder() string {
  534. channel.stateMutex.RLock()
  535. defer channel.stateMutex.RUnlock()
  536. return channel.registeredFounder
  537. }
  538. func (channel *Channel) HighestUserMode(client *Client) (result modes.Mode) {
  539. channel.stateMutex.RLock()
  540. clientModes := channel.members[client].modes
  541. channel.stateMutex.RUnlock()
  542. return clientModes.HighestChannelUserMode()
  543. }
  544. func (channel *Channel) Settings() (result ChannelSettings) {
  545. channel.stateMutex.RLock()
  546. result = channel.settings
  547. channel.stateMutex.RUnlock()
  548. return result
  549. }
  550. func (channel *Channel) SetSettings(settings ChannelSettings) {
  551. channel.stateMutex.Lock()
  552. channel.settings = settings
  553. channel.stateMutex.Unlock()
  554. channel.MarkDirty(IncludeSettings)
  555. }
  556. func (channel *Channel) setForward(forward string) {
  557. channel.stateMutex.Lock()
  558. channel.forward = forward
  559. channel.stateMutex.Unlock()
  560. }
  561. func (channel *Channel) Ctime() (ctime time.Time) {
  562. channel.stateMutex.RLock()
  563. ctime = channel.createdTime
  564. channel.stateMutex.RUnlock()
  565. return
  566. }
  567. func (channel *Channel) getAmode(cfaccount string) (result modes.Mode) {
  568. channel.stateMutex.RLock()
  569. defer channel.stateMutex.RUnlock()
  570. return channel.accountToUMode[cfaccount]
  571. }
  572. func (channel *Channel) UUID() utils.UUID {
  573. channel.stateMutex.RLock()
  574. defer channel.stateMutex.RUnlock()
  575. return channel.uuid
  576. }