profile.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. // This file is subject to a 1-clause BSD license.
  2. // Its contents can be found in the enclosed LICENSE file.
  3. // Package irc defines some utility types and functions for an IRC bot.
  4. package irc
  5. import (
  6. "strings"
  7. "sync"
  8. "github.com/monkeybird/autimaat/app/util"
  9. )
  10. // Profile defines bot configuration data.
  11. type Profile interface {
  12. // Root defines the root directory with the bot's configuration data.
  13. Root() string
  14. // Channels yields all channels the bot should join on startup.
  15. Channels() []Channel
  16. // Address defines the host and port of the server/network to connect to.
  17. Address() string
  18. // TKSKey defines the TLS key file. Along with TLSCert, it defines the
  19. // components needed to establish an encrypted connection to the server.
  20. TLSKey() string
  21. // TLSCert defines the TLS certificate file. Along with TLSKey, it
  22. // defines the components needed to establish an encrypted connection
  23. // to the server.
  24. TLSCert() string
  25. // CAPemData defines one ore more, PEM encoded, server root certificates.
  26. // This is optional and is used to replace the client's existing root CA
  27. // pool. This can be useful if you are connecting to a server whos
  28. // certificate is not present in any system wide CA pools.
  29. CAPemData() string
  30. // Nickname yields the bot's nickname.
  31. Nickname() string
  32. // SetNickname sets the bot's nickname. This is generally only called
  33. // when the bot logs in and finds its name alredy in use. If the nick
  34. // can not be regained, this function is used to alter it to something
  35. // which is still available.
  36. SetNickname(string)
  37. // NickservPassword defines the bot's nickserv password. This will be
  38. // used to register the bot when it logs in. It is only relevant if the
  39. // bot has a registered nickname and nickserv exists on the server.
  40. NickservPassword() string
  41. // SetNickservPassword sets the bot's nickserv password. This is be
  42. // used to register the bot when it logs in. It is only relevant if the
  43. // bot has a registered nickname and nickserv exists on the server.
  44. SetNickservPassword(string)
  45. // OperPassword defines the bot's OPER password. If present, this will
  46. // register the bot as a server operator.
  47. OperPassword() string
  48. // Some connections may be secured and require a password to connect to.
  49. ConnectionPassword() string
  50. // CommandPrefix this is the prefix used for all bot commands. Whenever
  51. // the bot reads incoming PRIVMSG data, it looks for this prefix to
  52. // determine if a command call was issued or not.
  53. CommandPrefix() string
  54. // Save saves the profile to disk.
  55. Save() error
  56. // Load loads the profile from disk.
  57. Load() error
  58. // IsWhitelisted returns true if the given hostmask is in the whitelist.
  59. // This means the user to whom it belongs is allowed to execute restricted
  60. // commands. This performs a case-insensitive comparison.
  61. IsWhitelisted(string) bool
  62. // Whitelist returns a copy of the current whitelist.
  63. Whitelist() []string
  64. // WhitelistAdd adds the given hostmask to the whitelist,
  65. // provided it does not already exist.
  66. WhitelistAdd(string)
  67. // WhitelistRemove removes the given hostmask from the whitelist,
  68. // provided it exists.
  69. WhitelistRemove(string)
  70. // IsNick returns true if the given name equals the bot's nickname.
  71. // This is used in request handlers to quickly check if a request
  72. // is targeted specifically at this bot or not.
  73. IsNick(string) bool
  74. // ForkArgs returns a list of command line arguments which should be
  75. // passed to a forked child process.
  76. ForkArgs() []string
  77. // Logging returns true if incoming data logging is enabled.
  78. Logging() bool
  79. // Logging determines if logging of incoming data should be enabled or not.
  80. SetLogging(bool)
  81. }
  82. // profile defines bot configuration data.
  83. //
  84. // The fields are embedded in a sub struct to differentiate them from the
  85. // method names needed to qualify as a Profile interface. I would rather
  86. // just make these field names lower case, but Go's JSON decoder will not
  87. // work on non-exported fields. Thus breaking the Load/Save functionality.
  88. type profile struct {
  89. m sync.RWMutex
  90. root string
  91. data profileData
  92. }
  93. // profileData defines the parts of the profile which are saved to
  94. // an external configuration file.
  95. type profileData struct {
  96. Whitelist []string
  97. Channels []Channel
  98. Address string
  99. TLSKey string
  100. TLSCert string
  101. CAPemData string
  102. Nickname string
  103. NickservPassword string
  104. OperPassword string
  105. ConnectionPassword string
  106. CommandPrefix string
  107. Logging bool
  108. }
  109. // NewProfile creates a new profile for the given root directory.
  110. func NewProfile(root string) Profile {
  111. return &profile{
  112. root: root,
  113. data: profileData{
  114. Logging: false,
  115. Address: "server.net:6667",
  116. Nickname: "bot_name",
  117. Channels: []Channel{
  118. {Name: "#test_channel"},
  119. },
  120. Whitelist: []string{
  121. "~user@server.com",
  122. },
  123. CommandPrefix: "!",
  124. },
  125. }
  126. }
  127. func (p *profile) Root() string {
  128. p.m.RLock()
  129. defer p.m.RUnlock()
  130. return p.root
  131. }
  132. func (p *profile) ForkArgs() []string {
  133. p.m.RLock()
  134. defer p.m.RUnlock()
  135. return []string{p.root}
  136. }
  137. func (p *profile) Channels() []Channel {
  138. p.m.RLock()
  139. defer p.m.RUnlock()
  140. return p.data.Channels
  141. }
  142. func (p *profile) Address() string {
  143. p.m.RLock()
  144. defer p.m.RUnlock()
  145. return p.data.Address
  146. }
  147. func (p *profile) TLSKey() string {
  148. p.m.RLock()
  149. defer p.m.RUnlock()
  150. return p.data.TLSKey
  151. }
  152. func (p *profile) TLSCert() string {
  153. p.m.RLock()
  154. defer p.m.RUnlock()
  155. return p.data.TLSCert
  156. }
  157. func (p *profile) CAPemData() string {
  158. p.m.RLock()
  159. defer p.m.RUnlock()
  160. return p.data.CAPemData
  161. }
  162. func (p *profile) Nickname() string {
  163. p.m.RLock()
  164. defer p.m.RUnlock()
  165. return p.data.Nickname
  166. }
  167. func (p *profile) SetNickname(v string) {
  168. p.m.Lock()
  169. p.data.Nickname = v
  170. p.m.Unlock()
  171. p.Save()
  172. }
  173. func (p *profile) NickservPassword() string {
  174. p.m.RLock()
  175. defer p.m.RUnlock()
  176. return p.data.NickservPassword
  177. }
  178. func (p *profile) SetNickservPassword(v string) {
  179. p.m.Lock()
  180. p.data.NickservPassword = v
  181. p.m.Unlock()
  182. p.Save()
  183. }
  184. func (p *profile) OperPassword() string {
  185. p.m.RLock()
  186. defer p.m.RUnlock()
  187. return p.data.OperPassword
  188. }
  189. func (p *profile) ConnectionPassword() string {
  190. p.m.RLock()
  191. defer p.m.RUnlock()
  192. return p.data.ConnectionPassword
  193. }
  194. func (p *profile) CommandPrefix() string {
  195. p.m.RLock()
  196. defer p.m.RUnlock()
  197. return p.data.CommandPrefix
  198. }
  199. func (p *profile) Whitelist() []string {
  200. p.m.RLock()
  201. defer p.m.RUnlock()
  202. out := make([]string, len(p.data.Whitelist))
  203. copy(out, p.data.Whitelist)
  204. return out
  205. }
  206. func (p *profile) WhitelistAdd(mask string) {
  207. p.m.Lock()
  208. for _, str := range p.data.Whitelist {
  209. if strings.EqualFold(str, mask) {
  210. p.m.Unlock()
  211. return
  212. }
  213. }
  214. p.data.Whitelist = append(p.data.Whitelist, mask)
  215. p.m.Unlock()
  216. p.Save()
  217. }
  218. func (p *profile) WhitelistRemove(mask string) {
  219. p.m.Lock()
  220. for i, str := range p.data.Whitelist {
  221. if !strings.EqualFold(str, mask) {
  222. continue
  223. }
  224. copy(p.data.Whitelist[i:], p.data.Whitelist[i+1:])
  225. p.data.Whitelist = p.data.Whitelist[:len(p.data.Whitelist)-1]
  226. break
  227. }
  228. p.m.Unlock()
  229. p.Save()
  230. }
  231. func (p *profile) IsWhitelisted(mask string) bool {
  232. p.m.RLock()
  233. defer p.m.RUnlock()
  234. for _, str := range p.data.Whitelist {
  235. if strings.EqualFold(str, mask) {
  236. return true
  237. }
  238. }
  239. return false
  240. }
  241. func (p *profile) IsNick(name string) bool {
  242. p.m.RLock()
  243. defer p.m.RUnlock()
  244. return strings.EqualFold(p.data.Nickname, name)
  245. }
  246. func (p *profile) Logging() bool {
  247. p.m.RLock()
  248. defer p.m.RUnlock()
  249. return p.data.Logging
  250. }
  251. func (p *profile) SetLogging(v bool) {
  252. p.m.Lock()
  253. p.data.Logging = v
  254. p.m.Unlock()
  255. p.Save()
  256. }
  257. func (p *profile) Save() error {
  258. p.m.RLock()
  259. err := util.WriteFile("profile.cfg", p.data, false)
  260. p.m.RUnlock()
  261. return err
  262. }
  263. func (p *profile) Load() error {
  264. p.m.Lock()
  265. err := util.ReadFile("profile.cfg", &p.data, false)
  266. p.m.Unlock()
  267. return err
  268. }