endpoints.go 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /*
  2. Copyright © The ESO Authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package secretmanager
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "net/http"
  18. )
  19. // EndpointsURI is the URI for getting the actual Cloud.ru API endpoints.
  20. const EndpointsURI = "https://api.cloud.ru/endpoints"
  21. // EndpointsResponse is a response from the Cloud.ru API.
  22. type EndpointsResponse struct {
  23. // Endpoints contains the list of actual API addresses of Cloud.ru products.
  24. Endpoints []Endpoint `json:"endpoints"`
  25. }
  26. // Endpoint is a product API address.
  27. type Endpoint struct {
  28. ID string `json:"id"`
  29. Address string `json:"address"`
  30. }
  31. // GetEndpoints returns the actual Cloud.ru API endpoints.
  32. func GetEndpoints(url string) (*EndpointsResponse, error) {
  33. // Validate that the URL is the expected Cloud.ru endpoints URL to prevent SSRF
  34. if url != EndpointsURI {
  35. return nil, fmt.Errorf("invalid endpoints URL: expected %s, got %s", EndpointsURI, url)
  36. }
  37. req, err := http.NewRequest(http.MethodGet, url, http.NoBody) //nolint:gosec // URL is validated against EndpointsURI above
  38. if err != nil {
  39. return nil, fmt.Errorf("construct HTTP request for cloud.ru endpoints: %w", err)
  40. }
  41. resp, err := http.DefaultClient.Do(req) //nolint:gosec // URL is validated against EndpointsURI above
  42. if err != nil {
  43. return nil, fmt.Errorf("get cloud.ru endpoints: %w", err)
  44. }
  45. defer func() {
  46. _ = resp.Body.Close()
  47. }()
  48. if resp.StatusCode != http.StatusOK {
  49. return nil, fmt.Errorf("get cloud.ru endpoints: unexpected status code %d", resp.StatusCode)
  50. }
  51. var endpoints EndpointsResponse
  52. if err = json.NewDecoder(resp.Body).Decode(&endpoints); err != nil {
  53. return nil, fmt.Errorf("decode cloud.ru endpoints: %w", err)
  54. }
  55. return &endpoints, nil
  56. }
  57. // Get returns the API address of the product by its ID.
  58. // If the product is not found, the function returns nil.
  59. func (er *EndpointsResponse) Get(id string) *Endpoint {
  60. for i := range er.Endpoints {
  61. if er.Endpoints[i].ID == id {
  62. return &er.Endpoints[i]
  63. }
  64. }
  65. return nil
  66. }