client.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package gluetun
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "os"
  9. "strings"
  10. "git.aetherial.dev/aeth/gluetun-qbitt-sidecar/pkg/shared"
  11. "github.com/pelletier/go-toml/v2"
  12. )
  13. /*
  14. will need to parse a configuration like this:
  15. [[roles]]
  16. name = "qbittorrent"
  17. # Define a list of routes with the syntax "Http-Method /path"
  18. routes = ["GET /v1/portforward"]
  19. # Define an authentication method with its parameters
  20. auth = "basic"
  21. username = "myusername"
  22. password = "mypassword"
  23. Or if using the API key authentication method:
  24. auth = "apikey"
  25. apikey = "myapikey"
  26. the 'apikey' is then sent in the X-API-Key header
  27. we will need to extract the username and password for authentication to gluetun. This will be done by mounting the same
  28. config file that gluetun has to a static location, like /gluetun-qbitt-sidecar/config.toml
  29. will need to just retrieve the exposed port via the route:
  30. GET /v1/portforward ----> {"port":5914}
  31. */
  32. const (
  33. PORT_FORWARD_PATH = "v1/portforward"
  34. STATUS_PATH = "v1/vpn/status"
  35. API_KEY_HEADER = "X-API-Key"
  36. GLUETUN_ADDRESS = "GLUETUN_ADDRESS"
  37. )
  38. type GluetunClient struct {
  39. client *http.Client
  40. server shared.Server
  41. }
  42. type Port struct {
  43. Port int `json:"port"`
  44. }
  45. type Configuration struct {
  46. Roles []Role `toml:"roles"`
  47. }
  48. type Role struct {
  49. Name string `toml:"name"`
  50. Routes []string `toml:"routes"`
  51. Auth string `toml:"auth"`
  52. Username string `toml:"username,omitempty"`
  53. Password string `toml:"password,omitempty"`
  54. Apikey string `toml:"apikey,omitempty"`
  55. }
  56. func NewGluetunClient() {}
  57. /*
  58. Read in the config.toml file that gluetun uses to set the api key / username and password
  59. :param path: the path to the config file. Use the path for where this is running, since this
  60. can be either ran as a container next to your deployment, or on the host itself
  61. */
  62. func GetAuthentication(path string) (Role, error) {
  63. var config Configuration
  64. var role Role
  65. fb, err := os.ReadFile(path)
  66. if err != nil {
  67. return role, err
  68. }
  69. fmt.Printf("%s\n", string(fb))
  70. err = toml.Unmarshal(fb, &config)
  71. if err != nil {
  72. return role, err
  73. }
  74. for i := range config.Roles {
  75. for x := range config.Roles[i].Routes {
  76. if strings.Contains(config.Roles[i].Routes[x], PORT_FORWARD_PATH) {
  77. return config.Roles[i], nil
  78. }
  79. }
  80. }
  81. return role, errors.New(fmt.Sprintf("No routes found that contained the path: '%s'", PORT_FORWARD_PATH))
  82. }
  83. // get the gluetun address
  84. func GetGluetunAddress() (shared.Server, error) {
  85. var srv shared.Server
  86. client := http.Client{}
  87. srv, err := shared.ParseServer("http://gluetun:8000")
  88. if err != nil {
  89. return srv, err
  90. }
  91. req, err := http.NewRequest(http.MethodGet, srv.FormatWith(STATUS_PATH), nil)
  92. if err != nil {
  93. return srv, err
  94. }
  95. resp, err := client.Do(req)
  96. if err != nil {
  97. return srv, err
  98. }
  99. if resp.StatusCode == http.StatusUnauthorized { // can assume that unauthorized means that the server is alive on that endpoint
  100. return srv, nil
  101. }
  102. // try to parse out the environment variable that supposed to carry the value (if it is different)
  103. addressFromEnv := os.Getenv(GLUETUN_ADDRESS)
  104. srv, err = shared.ParseServer(addressFromEnv)
  105. if err != nil {
  106. return srv, err
  107. }
  108. return srv, nil
  109. }
  110. /*
  111. Gets the forwarded port from the server
  112. */
  113. func GetForwardedPort(address string, apiKey string) (Port, error) {
  114. formattedUrl := fmt.Sprintf("http://%s/%s", sanitizeUrl(address), PORT_FORWARD_PATH)
  115. req, err := http.NewRequest(http.MethodGet, formattedUrl, nil)
  116. if err != nil {
  117. return Port{}, err
  118. }
  119. req.Header.Add(API_KEY_HEADER, apiKey)
  120. client := http.Client{}
  121. resp, err := client.Do(req)
  122. if err != nil {
  123. return Port{}, err
  124. }
  125. var b []byte
  126. defer resp.Body.Close()
  127. b, err = io.ReadAll(resp.Body)
  128. if err != nil {
  129. return Port{}, err
  130. }
  131. var port Port
  132. err = json.Unmarshal(b, &port)
  133. if err != nil {
  134. return port, err
  135. }
  136. return port, nil
  137. }