client.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package main
  2. import (
  3. "bytes"
  4. "crypto/tls"
  5. "net/http"
  6. "strings"
  7. "github.com/AudriusButkevicius/cli"
  8. )
  9. type APIClient struct {
  10. httpClient http.Client
  11. endpoint string
  12. apikey string
  13. username string
  14. password string
  15. id string
  16. csrf string
  17. }
  18. var instance *APIClient
  19. func getClient(c *cli.Context) *APIClient {
  20. if instance != nil {
  21. return instance
  22. }
  23. endpoint := c.GlobalString("endpoint")
  24. if !strings.HasPrefix(endpoint, "http") {
  25. endpoint = "http://" + endpoint
  26. }
  27. httpClient := http.Client{
  28. Transport: &http.Transport{
  29. TLSClientConfig: &tls.Config{
  30. InsecureSkipVerify: c.GlobalBool("insecure"),
  31. },
  32. },
  33. }
  34. client := APIClient{
  35. httpClient: httpClient,
  36. endpoint: endpoint,
  37. apikey: c.GlobalString("apikey"),
  38. username: c.GlobalString("username"),
  39. password: c.GlobalString("password"),
  40. }
  41. if client.apikey == "" {
  42. request, err := http.NewRequest("GET", client.endpoint, nil)
  43. die(err)
  44. response := client.handleRequest(request)
  45. client.id = response.Header.Get("X-Syncthing-ID")
  46. if client.id == "" {
  47. die("Failed to get device ID")
  48. }
  49. for _, item := range response.Cookies() {
  50. if item.Name == "CSRF-Token-"+client.id[:5] {
  51. client.csrf = item.Value
  52. goto csrffound
  53. }
  54. }
  55. die("Failed to get CSRF token")
  56. csrffound:
  57. }
  58. instance = &client
  59. return &client
  60. }
  61. func (client *APIClient) handleRequest(request *http.Request) *http.Response {
  62. if client.apikey != "" {
  63. request.Header.Set("X-API-Key", client.apikey)
  64. }
  65. if client.username != "" || client.password != "" {
  66. request.SetBasicAuth(client.username, client.password)
  67. }
  68. if client.csrf != "" {
  69. request.Header.Set("X-CSRF-Token-"+client.id[:5], client.csrf)
  70. }
  71. response, err := client.httpClient.Do(request)
  72. die(err)
  73. if response.StatusCode == 404 {
  74. die("Invalid endpoint or API call")
  75. } else if response.StatusCode == 401 {
  76. die("Invalid username or password")
  77. } else if response.StatusCode == 403 {
  78. if client.apikey == "" {
  79. die("Invalid CSRF token")
  80. }
  81. die("Invalid API key")
  82. } else if response.StatusCode != 200 {
  83. body := strings.TrimSpace(string(responseToBArray(response)))
  84. if body != "" {
  85. die(body)
  86. }
  87. die("Unknown HTTP status returned: " + response.Status)
  88. }
  89. return response
  90. }
  91. func httpGet(c *cli.Context, url string) *http.Response {
  92. client := getClient(c)
  93. request, err := http.NewRequest("GET", client.endpoint+"/rest/"+url, nil)
  94. die(err)
  95. return client.handleRequest(request)
  96. }
  97. func httpPost(c *cli.Context, url string, body string) *http.Response {
  98. client := getClient(c)
  99. request, err := http.NewRequest("POST", client.endpoint+"/rest/"+url, bytes.NewBufferString(body))
  100. die(err)
  101. return client.handleRequest(request)
  102. }