client.go 2.7 KB

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