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.

modes.go 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. // Copyright (c) 2012-2014 Jeremy Latt
  2. // Copyright (c) 2014-2015 Edmund Huber
  3. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  4. // released under the MIT license
  5. package irc
  6. import (
  7. "strconv"
  8. "strings"
  9. "github.com/goshuirc/irc-go/ircmsg"
  10. "github.com/oragono/oragono/irc/sno"
  11. "github.com/tidwall/buntdb"
  12. )
  13. // ModeOp is an operation performed with modes
  14. type ModeOp rune
  15. func (op ModeOp) String() string {
  16. return string(op)
  17. }
  18. const (
  19. // Add is used when adding the given key.
  20. Add ModeOp = '+'
  21. // List is used when listing modes (for instance, listing the current bans on a channel).
  22. List ModeOp = '='
  23. // Remove is used when taking away the given key.
  24. Remove ModeOp = '-'
  25. )
  26. // Mode represents a user/channel/server mode
  27. type Mode rune
  28. func (mode Mode) String() string {
  29. return string(mode)
  30. }
  31. // ModeChange is a single mode changing
  32. type ModeChange struct {
  33. mode Mode
  34. op ModeOp
  35. arg string
  36. }
  37. func (change *ModeChange) String() (str string) {
  38. if (change.op == Add) || (change.op == Remove) {
  39. str = change.op.String()
  40. }
  41. str += change.mode.String()
  42. if change.arg != "" {
  43. str += " " + change.arg
  44. }
  45. return
  46. }
  47. // ModeChanges are a collection of 'ModeChange's
  48. type ModeChanges []ModeChange
  49. func (changes ModeChanges) String() string {
  50. if len(changes) == 0 {
  51. return ""
  52. }
  53. op := changes[0].op
  54. str := changes[0].op.String()
  55. for _, change := range changes {
  56. if change.op != op {
  57. op = change.op
  58. str += change.op.String()
  59. }
  60. str += change.mode.String()
  61. }
  62. for _, change := range changes {
  63. if change.arg == "" {
  64. continue
  65. }
  66. str += " " + change.arg
  67. }
  68. return str
  69. }
  70. // Modes is just a raw list of modes
  71. type Modes []Mode
  72. func (modes Modes) String() string {
  73. strs := make([]string, len(modes))
  74. for index, mode := range modes {
  75. strs[index] = mode.String()
  76. }
  77. return strings.Join(strs, "")
  78. }
  79. // User Modes
  80. const (
  81. Away Mode = 'a'
  82. Invisible Mode = 'i'
  83. LocalOperator Mode = 'O'
  84. Operator Mode = 'o'
  85. Restricted Mode = 'r'
  86. ServerNotice Mode = 's'
  87. TLS Mode = 'Z'
  88. UserRoleplaying Mode = 'E'
  89. WallOps Mode = 'w'
  90. )
  91. var (
  92. // SupportedUserModes are the user modes that we actually support (modifying).
  93. SupportedUserModes = Modes{
  94. Away, Invisible, Operator, ServerNotice, UserRoleplaying,
  95. }
  96. // supportedUserModesString acts as a cache for when we introduce users
  97. supportedUserModesString = SupportedUserModes.String()
  98. )
  99. // Channel Modes
  100. const (
  101. BanMask Mode = 'b' // arg
  102. ChanRoleplaying Mode = 'E' // flag
  103. ExceptMask Mode = 'e' // arg
  104. InviteMask Mode = 'I' // arg
  105. InviteOnly Mode = 'i' // flag
  106. Key Mode = 'k' // flag arg
  107. Moderated Mode = 'm' // flag
  108. NoOutside Mode = 'n' // flag
  109. OpOnlyTopic Mode = 't' // flag
  110. RegisteredOnly Mode = 'r' // flag
  111. Secret Mode = 's' // flag
  112. UserLimit Mode = 'l' // flag arg
  113. )
  114. var (
  115. ChannelFounder Mode = 'q' // arg
  116. ChannelAdmin Mode = 'a' // arg
  117. ChannelOperator Mode = 'o' // arg
  118. Halfop Mode = 'h' // arg
  119. Voice Mode = 'v' // arg
  120. // SupportedChannelModes are the channel modes that we support.
  121. SupportedChannelModes = Modes{
  122. BanMask, ExceptMask, InviteMask, InviteOnly, Key, NoOutside,
  123. OpOnlyTopic, Secret, UserLimit, ChanRoleplaying,
  124. }
  125. // supportedChannelModesString acts as a cache for when we introduce users
  126. supportedChannelModesString = SupportedChannelModes.String()
  127. // DefaultChannelModes are enabled on brand new channels when they're created.
  128. DefaultChannelModes = Modes{
  129. NoOutside, OpOnlyTopic,
  130. }
  131. // ChannelPrivModes holds the list of modes that are privileged, ie founder/op/halfop, in order.
  132. // voice is not in this list because it cannot perform channel operator actions.
  133. ChannelPrivModes = Modes{
  134. ChannelFounder, ChannelAdmin, ChannelOperator, Halfop,
  135. }
  136. ChannelModePrefixes = map[Mode]string{
  137. ChannelFounder: "~",
  138. ChannelAdmin: "&",
  139. ChannelOperator: "@",
  140. Halfop: "%",
  141. Voice: "+",
  142. }
  143. )
  144. //
  145. // channel membership prefixes
  146. //
  147. // SplitChannelMembershipPrefixes takes a target and returns the prefixes on it, then the name.
  148. func SplitChannelMembershipPrefixes(target string) (prefixes string, name string) {
  149. name = target
  150. for {
  151. if len(name) > 0 && strings.Contains("~&@%+", string(name[0])) {
  152. prefixes += string(name[0])
  153. name = name[1:]
  154. } else {
  155. break
  156. }
  157. }
  158. return prefixes, name
  159. }
  160. // GetLowestChannelModePrefix returns the lowest channel prefix mode out of the given prefixes.
  161. func GetLowestChannelModePrefix(prefixes string) *Mode {
  162. var lowest *Mode
  163. if strings.Contains(prefixes, "+") {
  164. lowest = &Voice
  165. } else {
  166. for i, mode := range ChannelPrivModes {
  167. if strings.Contains(prefixes, ChannelModePrefixes[mode]) {
  168. lowest = &ChannelPrivModes[i]
  169. }
  170. }
  171. }
  172. return lowest
  173. }
  174. //
  175. // commands
  176. //
  177. // MODE <target> [<modestring> [<mode arguments>...]]
  178. func modeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  179. _, errChan := CasefoldChannel(msg.Params[0])
  180. if errChan == nil {
  181. return cmodeHandler(server, client, msg)
  182. }
  183. return umodeHandler(server, client, msg)
  184. }
  185. // ParseUserModeChanges returns the valid changes, and the list of unknown chars.
  186. func ParseUserModeChanges(params ...string) (ModeChanges, map[rune]bool) {
  187. changes := make(ModeChanges, 0)
  188. unknown := make(map[rune]bool)
  189. if 0 < len(params) {
  190. modeArg := params[0]
  191. op := ModeOp(modeArg[0])
  192. if (op == Add) || (op == Remove) {
  193. modeArg = modeArg[1:]
  194. } else {
  195. unknown[rune(modeArg[0])] = true
  196. return changes, unknown
  197. }
  198. skipArgs := 1
  199. for _, mode := range modeArg {
  200. if mode == '-' || mode == '+' {
  201. op = ModeOp(mode)
  202. continue
  203. }
  204. change := ModeChange{
  205. mode: Mode(mode),
  206. op: op,
  207. }
  208. // put arg into modechange if needed
  209. switch Mode(mode) {
  210. case ServerNotice:
  211. // always require arg
  212. if len(params) > skipArgs {
  213. change.arg = params[skipArgs]
  214. skipArgs++
  215. } else {
  216. continue
  217. }
  218. }
  219. var isKnown bool
  220. for _, supportedMode := range SupportedUserModes {
  221. if rune(supportedMode) == mode {
  222. isKnown = true
  223. break
  224. }
  225. }
  226. if !isKnown {
  227. unknown[mode] = true
  228. continue
  229. }
  230. changes = append(changes, change)
  231. }
  232. }
  233. return changes, unknown
  234. }
  235. // applyUserModeChanges applies the given changes, and returns the applied changes.
  236. func (client *Client) applyUserModeChanges(force bool, changes ModeChanges) ModeChanges {
  237. applied := make(ModeChanges, 0)
  238. for _, change := range changes {
  239. switch change.mode {
  240. case Invisible, WallOps, UserRoleplaying, Operator, LocalOperator:
  241. switch change.op {
  242. case Add:
  243. if !force && (change.mode == Operator || change.mode == LocalOperator) {
  244. continue
  245. }
  246. if client.flags[change.mode] {
  247. continue
  248. }
  249. client.flags[change.mode] = true
  250. applied = append(applied, change)
  251. case Remove:
  252. if !client.flags[change.mode] {
  253. continue
  254. }
  255. delete(client.flags, change.mode)
  256. applied = append(applied, change)
  257. }
  258. case ServerNotice:
  259. if !client.flags[Operator] {
  260. continue
  261. }
  262. var masks []sno.Mask
  263. if change.op == Add || change.op == Remove {
  264. for _, char := range change.arg {
  265. masks = append(masks, sno.Mask(char))
  266. }
  267. }
  268. if change.op == Add {
  269. client.server.snomasks.AddMasks(client, masks...)
  270. applied = append(applied, change)
  271. } else if change.op == Remove {
  272. client.server.snomasks.RemoveMasks(client, masks...)
  273. applied = append(applied, change)
  274. }
  275. }
  276. // can't do anything to TLS mode
  277. }
  278. // return the changes we could actually apply
  279. return applied
  280. }
  281. // MODE <target> [<modestring> [<mode arguments>...]]
  282. func umodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  283. nickname, err := CasefoldName(msg.Params[0])
  284. target := server.clients.Get(nickname)
  285. if err != nil || target == nil {
  286. if len(msg.Params[0]) > 0 {
  287. client.Send(nil, server.name, ERR_NOSUCHNICK, client.nick, msg.Params[0], "No such nick")
  288. }
  289. return false
  290. }
  291. if client != target && msg.Command != "SAMODE" {
  292. if len(msg.Params) > 1 {
  293. client.Send(nil, server.name, ERR_USERSDONTMATCH, client.nick, "Can't change modes for other users")
  294. } else {
  295. client.Send(nil, server.name, ERR_USERSDONTMATCH, client.nick, "Can't view modes for other users")
  296. }
  297. return false
  298. }
  299. // applied mode changes
  300. applied := make(ModeChanges, 0)
  301. if 1 < len(msg.Params) {
  302. // parse out real mode changes
  303. params := msg.Params[1:]
  304. changes, unknown := ParseUserModeChanges(params...)
  305. // alert for unknown mode changes
  306. for char := range unknown {
  307. client.Send(nil, server.name, ERR_UNKNOWNMODE, client.nick, string(char), "is an unknown mode character to me")
  308. }
  309. if len(unknown) == 1 && len(changes) == 0 {
  310. return false
  311. }
  312. // apply mode changes
  313. applied = target.applyUserModeChanges(msg.Command == "SAMODE", changes)
  314. }
  315. if len(applied) > 0 {
  316. client.Send(nil, client.nickMaskString, "MODE", target.nick, applied.String())
  317. } else if client == target {
  318. client.Send(nil, target.nickMaskString, RPL_UMODEIS, target.nick, target.ModeString())
  319. if client.flags[LocalOperator] || client.flags[Operator] {
  320. masks := server.snomasks.String(client)
  321. if 0 < len(masks) {
  322. client.Send(nil, target.nickMaskString, RPL_SNOMASKIS, target.nick, masks, "Server notice masks")
  323. }
  324. }
  325. }
  326. return false
  327. }
  328. // ParseChannelModeChanges returns the valid changes, and the list of unknown chars.
  329. func ParseChannelModeChanges(params ...string) (ModeChanges, map[rune]bool) {
  330. changes := make(ModeChanges, 0)
  331. unknown := make(map[rune]bool)
  332. if 0 < len(params) {
  333. modeArg := params[0]
  334. op := ModeOp(modeArg[0])
  335. if (op == Add) || (op == Remove) {
  336. modeArg = modeArg[1:]
  337. } else {
  338. unknown[rune(modeArg[0])] = true
  339. return changes, unknown
  340. }
  341. skipArgs := 1
  342. for _, mode := range modeArg {
  343. if mode == '-' || mode == '+' {
  344. op = ModeOp(mode)
  345. continue
  346. }
  347. change := ModeChange{
  348. mode: Mode(mode),
  349. op: op,
  350. }
  351. // put arg into modechange if needed
  352. switch Mode(mode) {
  353. case BanMask, ExceptMask, InviteMask:
  354. if len(params) > skipArgs {
  355. change.arg = params[skipArgs]
  356. skipArgs++
  357. } else {
  358. change.op = List
  359. }
  360. case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
  361. if len(params) > skipArgs {
  362. change.arg = params[skipArgs]
  363. skipArgs++
  364. } else {
  365. continue
  366. }
  367. case Key, UserLimit:
  368. // don't require value when removing
  369. if change.op == Add {
  370. if len(params) > skipArgs {
  371. change.arg = params[skipArgs]
  372. skipArgs++
  373. } else {
  374. continue
  375. }
  376. }
  377. }
  378. var isKnown bool
  379. for _, supportedMode := range SupportedChannelModes {
  380. if rune(supportedMode) == mode {
  381. isKnown = true
  382. break
  383. }
  384. }
  385. if !isKnown {
  386. unknown[mode] = true
  387. continue
  388. }
  389. changes = append(changes, change)
  390. }
  391. }
  392. return changes, unknown
  393. }
  394. // ApplyChannelModeChanges applies a given set of mode changes.
  395. func ApplyChannelModeChanges(channel *Channel, client *Client, isSamode bool, changes ModeChanges) ModeChanges {
  396. // so we only output one warning for each list type when full
  397. listFullWarned := make(map[Mode]bool)
  398. clientIsOp := channel.clientIsAtLeastNoMutex(client, ChannelOperator)
  399. var alreadySentPrivError bool
  400. applied := make(ModeChanges, 0)
  401. for _, change := range changes {
  402. // chan priv modes are checked specially so ignore them
  403. // means regular users can't view ban/except lists... but I'm not worried about that
  404. if isSamode && ChannelModePrefixes[change.mode] == "" && !clientIsOp {
  405. if !alreadySentPrivError {
  406. alreadySentPrivError = true
  407. client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
  408. }
  409. continue
  410. }
  411. switch change.mode {
  412. case BanMask, ExceptMask, InviteMask:
  413. mask := change.arg
  414. list := channel.lists[change.mode]
  415. if list == nil {
  416. // This should never happen, but better safe than panicky.
  417. client.Send(nil, client.server.name, ERR_UNKNOWNERROR, client.nick, "MODE", "Could not complete MODE command")
  418. return changes
  419. }
  420. if (change.op == List) || (mask == "") {
  421. channel.ShowMaskList(client, change.mode)
  422. continue
  423. }
  424. // confirm mask looks valid
  425. mask, err := Casefold(mask)
  426. if err != nil {
  427. continue
  428. }
  429. switch change.op {
  430. case Add:
  431. if len(list.masks) >= client.server.limits.ChanListModes {
  432. if !listFullWarned[change.mode] {
  433. client.Send(nil, client.server.name, ERR_BANLISTFULL, client.nick, channel.name, change.mode.String(), "Channel list is full")
  434. listFullWarned[change.mode] = true
  435. }
  436. continue
  437. }
  438. list.Add(mask)
  439. applied = append(applied, change)
  440. case Remove:
  441. list.Remove(mask)
  442. applied = append(applied, change)
  443. }
  444. case UserLimit:
  445. switch change.op {
  446. case Add:
  447. val, err := strconv.ParseUint(change.arg, 10, 64)
  448. if err == nil {
  449. channel.userLimit = val
  450. applied = append(applied, change)
  451. }
  452. case Remove:
  453. channel.userLimit = 0
  454. applied = append(applied, change)
  455. }
  456. case Key:
  457. switch change.op {
  458. case Add:
  459. channel.key = change.arg
  460. case Remove:
  461. channel.key = ""
  462. }
  463. applied = append(applied, change)
  464. case InviteOnly, Moderated, NoOutside, OpOnlyTopic, RegisteredOnly, Secret, ChanRoleplaying:
  465. switch change.op {
  466. case Add:
  467. if channel.flags[change.mode] {
  468. continue
  469. }
  470. channel.flags[change.mode] = true
  471. applied = append(applied, change)
  472. case Remove:
  473. if !channel.flags[change.mode] {
  474. continue
  475. }
  476. delete(channel.flags, change.mode)
  477. applied = append(applied, change)
  478. }
  479. case ChannelFounder, ChannelAdmin, ChannelOperator, Halfop, Voice:
  480. // make sure client has privs to edit the given prefix
  481. hasPrivs := isSamode
  482. if !hasPrivs {
  483. for _, mode := range ChannelPrivModes {
  484. if channel.members[client][mode] {
  485. hasPrivs = true
  486. // Admins can't give other people Admin or remove it from others,
  487. // standard for that channel mode, we worry about this later
  488. if mode == ChannelAdmin && change.mode == ChannelAdmin {
  489. hasPrivs = false
  490. }
  491. break
  492. } else if mode == change.mode {
  493. break
  494. }
  495. }
  496. }
  497. casefoldedName, err := CasefoldName(change.arg)
  498. if err != nil {
  499. continue
  500. }
  501. if !hasPrivs {
  502. if change.op == Remove && casefoldedName == client.nickCasefolded {
  503. // success!
  504. } else {
  505. if !alreadySentPrivError {
  506. alreadySentPrivError = true
  507. client.Send(nil, client.server.name, ERR_CHANOPRIVSNEEDED, channel.name, "You're not a channel operator")
  508. }
  509. continue
  510. }
  511. }
  512. change := channel.applyModeMemberNoMutex(client, change.mode, change.op, change.arg)
  513. if change != nil {
  514. applied = append(applied, *change)
  515. }
  516. }
  517. }
  518. return applied
  519. }
  520. // MODE <target> [<modestring> [<mode arguments>...]]
  521. func cmodeHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
  522. channelName, err := CasefoldChannel(msg.Params[0])
  523. channel := server.channels.Get(channelName)
  524. if err != nil || channel == nil {
  525. client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, msg.Params[0], "No such channel")
  526. return false
  527. }
  528. channel.membersMutex.Lock()
  529. defer channel.membersMutex.Unlock()
  530. // applied mode changes
  531. applied := make(ModeChanges, 0)
  532. if 1 < len(msg.Params) {
  533. // parse out real mode changes
  534. params := msg.Params[1:]
  535. changes, unknown := ParseChannelModeChanges(params...)
  536. // alert for unknown mode changes
  537. for char := range unknown {
  538. client.Send(nil, server.name, ERR_UNKNOWNMODE, client.nick, string(char), "is an unknown mode character to me")
  539. }
  540. if len(unknown) == 1 && len(changes) == 0 {
  541. return false
  542. }
  543. // apply mode changes
  544. applied = ApplyChannelModeChanges(channel, client, msg.Command == "SAMODE", changes)
  545. }
  546. // save changes to banlist/exceptlist/invexlist
  547. var banlistUpdated, exceptlistUpdated, invexlistUpdated bool
  548. for _, change := range applied {
  549. if change.mode == BanMask {
  550. banlistUpdated = true
  551. } else if change.mode == ExceptMask {
  552. exceptlistUpdated = true
  553. } else if change.mode == InviteMask {
  554. invexlistUpdated = true
  555. }
  556. }
  557. server.registeredChannelsMutex.Lock()
  558. if 0 < len(applied) && server.registeredChannels[channel.nameCasefolded] != nil && (banlistUpdated || exceptlistUpdated || invexlistUpdated) {
  559. server.store.Update(func(tx *buntdb.Tx) error {
  560. chanInfo := server.loadChannelNoMutex(tx, channel.nameCasefolded)
  561. if banlistUpdated {
  562. var banlist []string
  563. for mask := range channel.lists[BanMask].masks {
  564. banlist = append(banlist, mask)
  565. }
  566. chanInfo.Banlist = banlist
  567. }
  568. if exceptlistUpdated {
  569. var exceptlist []string
  570. for mask := range channel.lists[ExceptMask].masks {
  571. exceptlist = append(exceptlist, mask)
  572. }
  573. chanInfo.Exceptlist = exceptlist
  574. }
  575. if invexlistUpdated {
  576. var invitelist []string
  577. for mask := range channel.lists[InviteMask].masks {
  578. invitelist = append(invitelist, mask)
  579. }
  580. chanInfo.Invitelist = invitelist
  581. }
  582. server.saveChannelNoMutex(tx, channel.nameCasefolded, *chanInfo)
  583. return nil
  584. })
  585. }
  586. server.registeredChannelsMutex.Unlock()
  587. // send out changes
  588. if len(applied) > 0 {
  589. //TODO(dan): we should change the name of String and make it return a slice here
  590. args := append([]string{channel.name}, strings.Split(applied.String(), " ")...)
  591. for member := range channel.members {
  592. member.Send(nil, client.nickMaskString, "MODE", args...)
  593. }
  594. } else {
  595. //TODO(dan): we should just make ModeString return a slice here
  596. args := append([]string{client.nick, channel.name}, strings.Split(channel.modeStringNoLock(client), " ")...)
  597. client.Send(nil, client.nickMaskString, RPL_CHANNELMODEIS, args...)
  598. client.Send(nil, client.nickMaskString, RPL_CHANNELCREATED, client.nick, channel.name, strconv.FormatInt(channel.createdTime.Unix(), 10))
  599. }
  600. return false
  601. }