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.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright (c) 2016- 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 restDLinesResp struct {
  29. DLines map[string]IPBanInfo `json:"dlines"`
  30. }
  31. type restAcct struct {
  32. Name string `json:"name"`
  33. RegisteredAt time.Time `json:"registered-at"`
  34. Clients int `json:"clients"`
  35. }
  36. type restAccountsResp struct {
  37. Verified map[string]restAcct `json:"verified"`
  38. }
  39. type restRehashResp struct {
  40. Successful bool `json:"successful"`
  41. Error string `json:"error"`
  42. Time time.Time `json:"time"`
  43. }
  44. func restInfo(w http.ResponseWriter, r *http.Request) {
  45. rs := restInfoResp{
  46. Version: SemVer,
  47. ServerName: restAPIServer.name,
  48. NetworkName: restAPIServer.networkName,
  49. }
  50. b, err := json.Marshal(rs)
  51. if err != nil {
  52. fmt.Fprintln(w, restErr)
  53. } else {
  54. fmt.Fprintln(w, string(b))
  55. }
  56. }
  57. func restStatus(w http.ResponseWriter, r *http.Request) {
  58. rs := restStatusResp{
  59. Clients: restAPIServer.clients.Count(),
  60. Opers: len(restAPIServer.operators),
  61. Channels: len(restAPIServer.channels),
  62. }
  63. b, err := json.Marshal(rs)
  64. if err != nil {
  65. fmt.Fprintln(w, restErr)
  66. } else {
  67. fmt.Fprintln(w, string(b))
  68. }
  69. }
  70. func restGetDLines(w http.ResponseWriter, r *http.Request) {
  71. rs := restDLinesResp{
  72. DLines: restAPIServer.dlines.AllBans(),
  73. }
  74. b, err := json.Marshal(rs)
  75. if err != nil {
  76. fmt.Fprintln(w, restErr)
  77. } else {
  78. fmt.Fprintln(w, string(b))
  79. }
  80. }
  81. func restGetAccounts(w http.ResponseWriter, r *http.Request) {
  82. rs := restAccountsResp{
  83. Verified: make(map[string]restAcct),
  84. }
  85. // get accounts
  86. err := restAPIServer.store.View(func(tx *buntdb.Tx) error {
  87. tx.AscendKeys("account.exists *", func(key, value string) bool {
  88. key = key[len("account.exists "):]
  89. _, err := tx.Get(fmt.Sprintf(keyAccountVerified, key))
  90. verified := err == nil
  91. fmt.Println(fmt.Sprintf(keyAccountVerified, key))
  92. // get other details
  93. name, _ := tx.Get(fmt.Sprintf(keyAccountName, key))
  94. regTimeStr, _ := tx.Get(fmt.Sprintf(keyAccountRegTime, key))
  95. regTimeInt, _ := strconv.ParseInt(regTimeStr, 10, 64)
  96. regTime := time.Unix(regTimeInt, 0)
  97. var clients int
  98. acct := restAPIServer.accounts[key]
  99. if acct != nil {
  100. clients = len(acct.Clients)
  101. }
  102. if verified {
  103. rs.Verified[key] = restAcct{
  104. Name: name,
  105. RegisteredAt: regTime,
  106. Clients: clients,
  107. }
  108. } else {
  109. //TODO(dan): Add to unverified list
  110. }
  111. return true // true to continue I guess?
  112. })
  113. return nil
  114. })
  115. b, err := json.Marshal(rs)
  116. if err != nil {
  117. fmt.Fprintln(w, restErr)
  118. } else {
  119. fmt.Fprintln(w, string(b))
  120. }
  121. }
  122. func restRehash(w http.ResponseWriter, r *http.Request) {
  123. err := restAPIServer.rehash()
  124. rs := restRehashResp{
  125. Successful: err == nil,
  126. Time: time.Now(),
  127. }
  128. if err != nil {
  129. rs.Error = err.Error()
  130. }
  131. b, err := json.Marshal(rs)
  132. if err != nil {
  133. fmt.Fprintln(w, restErr)
  134. } else {
  135. fmt.Fprintln(w, string(b))
  136. }
  137. }
  138. func (s *Server) startRestAPI() {
  139. // so handlers can ref it later
  140. restAPIServer = s
  141. // start router
  142. r := mux.NewRouter()
  143. // GET methods
  144. rg := r.Methods("GET").Subrouter()
  145. rg.HandleFunc("/info", restInfo)
  146. rg.HandleFunc("/status", restStatus)
  147. rg.HandleFunc("/dlines", restGetDLines)
  148. rg.HandleFunc("/accounts", restGetAccounts)
  149. // PUT methods
  150. rp := r.Methods("POST").Subrouter()
  151. rp.HandleFunc("/rehash", restRehash)
  152. // start api
  153. go http.ListenAndServe(s.restAPI.Listen, r)
  154. }