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.

rest_api.go 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
  2. // released under the MIT license
  3. // viewing and modifying accounts, registered channels, dlines, rehashing, etc
  4. package irc
  5. import (
  6. "encoding/json"
  7. "net/http"
  8. "strconv"
  9. "time"
  10. "fmt"
  11. "github.com/gorilla/mux"
  12. "github.com/tidwall/buntdb"
  13. )
  14. const restErr = "{\"error\":\"An unknown error occurred\"}"
  15. // restAPIServer is used to keep a link to the current running server since this is the best
  16. // way to do it, given how HTTP handlers dispatch and work.
  17. var restAPIServer *Server
  18. type restInfoResp struct {
  19. ServerName string `json:"server-name"`
  20. NetworkName string `json:"network-name"`
  21. Version string `json:"version"`
  22. }
  23. type restStatusResp struct {
  24. Clients int `json:"clients"`
  25. Opers int `json:"opers"`
  26. Channels int `json:"channels"`
  27. }
  28. type restXLinesResp struct {
  29. DLines map[string]IPBanInfo `json:"dlines"`
  30. KLines map[string]IPBanInfo `json:"klines"`
  31. }
  32. type restAcct struct {
  33. Name string `json:"name"`
  34. RegisteredAt time.Time `json:"registered-at"`
  35. Clients int `json:"clients"`
  36. }
  37. type restAccountsResp struct {
  38. Verified map[string]restAcct `json:"verified"`
  39. }
  40. type restRehashResp struct {
  41. Successful bool `json:"successful"`
  42. Error string `json:"error"`
  43. Time time.Time `json:"time"`
  44. }
  45. func restInfo(w http.ResponseWriter, r *http.Request) {
  46. rs := restInfoResp{
  47. Version: SemVer,
  48. ServerName: restAPIServer.name,
  49. NetworkName: restAPIServer.networkName,
  50. }
  51. b, err := json.Marshal(rs)
  52. if err != nil {
  53. fmt.Fprintln(w, restErr)
  54. } else {
  55. fmt.Fprintln(w, string(b))
  56. }
  57. }
  58. func restStatus(w http.ResponseWriter, r *http.Request) {
  59. rs := restStatusResp{
  60. Clients: restAPIServer.clients.Count(),
  61. Opers: len(restAPIServer.operators),
  62. Channels: restAPIServer.channels.Len(),
  63. }
  64. b, err := json.Marshal(rs)
  65. if err != nil {
  66. fmt.Fprintln(w, restErr)
  67. } else {
  68. fmt.Fprintln(w, string(b))
  69. }
  70. }
  71. func restGetXLines(w http.ResponseWriter, r *http.Request) {
  72. rs := restXLinesResp{
  73. DLines: restAPIServer.dlines.AllBans(),
  74. KLines: restAPIServer.klines.AllBans(),
  75. }
  76. b, err := json.Marshal(rs)
  77. if err != nil {
  78. fmt.Fprintln(w, restErr)
  79. } else {
  80. fmt.Fprintln(w, string(b))
  81. }
  82. }
  83. func restGetAccounts(w http.ResponseWriter, r *http.Request) {
  84. rs := restAccountsResp{
  85. Verified: make(map[string]restAcct),
  86. }
  87. // get accounts
  88. err := restAPIServer.store.View(func(tx *buntdb.Tx) error {
  89. tx.AscendKeys("account.exists *", func(key, value string) bool {
  90. key = key[len("account.exists "):]
  91. _, err := tx.Get(fmt.Sprintf(keyAccountVerified, key))
  92. verified := err == nil
  93. fmt.Println(fmt.Sprintf(keyAccountVerified, key))
  94. // get other details
  95. name, _ := tx.Get(fmt.Sprintf(keyAccountName, key))
  96. regTimeStr, _ := tx.Get(fmt.Sprintf(keyAccountRegTime, key))
  97. regTimeInt, _ := strconv.ParseInt(regTimeStr, 10, 64)
  98. regTime := time.Unix(regTimeInt, 0)
  99. var clients int
  100. acct := restAPIServer.accounts[key]
  101. if acct != nil {
  102. clients = len(acct.Clients)
  103. }
  104. if verified {
  105. rs.Verified[key] = restAcct{
  106. Name: name,
  107. RegisteredAt: regTime,
  108. Clients: clients,
  109. }
  110. } else {
  111. //TODO(dan): Add to unverified list
  112. }
  113. return true // true to continue I guess?
  114. })
  115. return nil
  116. })
  117. b, err := json.Marshal(rs)
  118. if err != nil {
  119. fmt.Fprintln(w, restErr)
  120. } else {
  121. fmt.Fprintln(w, string(b))
  122. }
  123. }
  124. func restRehash(w http.ResponseWriter, r *http.Request) {
  125. err := restAPIServer.rehash()
  126. rs := restRehashResp{
  127. Successful: err == nil,
  128. Time: time.Now(),
  129. }
  130. if err != nil {
  131. rs.Error = err.Error()
  132. }
  133. b, err := json.Marshal(rs)
  134. if err != nil {
  135. fmt.Fprintln(w, restErr)
  136. } else {
  137. fmt.Fprintln(w, string(b))
  138. }
  139. }
  140. func (s *Server) startRestAPI() {
  141. // so handlers can ref it later
  142. restAPIServer = s
  143. // start router
  144. r := mux.NewRouter()
  145. // GET methods
  146. rg := r.Methods("GET").Subrouter()
  147. rg.HandleFunc("/info", restInfo)
  148. rg.HandleFunc("/status", restStatus)
  149. rg.HandleFunc("/xlines", restGetXLines)
  150. rg.HandleFunc("/accounts", restGetAccounts)
  151. // PUT methods
  152. rp := r.Methods("POST").Subrouter()
  153. rp.HandleFunc("/rehash", restRehash)
  154. // start api
  155. go http.ListenAndServe(s.restAPI.Listen, r)
  156. }