Files
go-unifi/unifi/api_paths.go
Mateusz Filipowicz 278a72fbb9 feat: add support for uploading Hotspot Captive Portal files (like background image, logo) (#42)
* feat: add support for uploading Hotspot Captive Portal files (like background image, logo)

* feat: add UploadPortalFileFromReader
2025-03-03 02:03:10 +01:00

110 lines
2.4 KiB
Go

package unifi
import (
"errors"
"fmt"
"io"
"net/http"
)
const (
apiPath = "/api"
apiV2Path = "/v2/api"
apiPathNew = "/proxy/network/api"
apiV2PathNew = "/proxy/network/v2/api"
loginPath = "/api/login"
loginPathNew = "/api/auth/login"
statusPath = "/status"
statusPathNew = "/proxy/network/status"
uploadPath = "/upload"
uploadPathNew = "/proxy/network/upload"
logoutPath = "/api/logout"
defaultUserAgent = "go-unifi/0.0.1"
ApiKeyHeader = "X-Api-Key"
CsrfHeader = "X-Csrf-Token"
UserAgentHeader = "User-Agent"
AcceptHeader = "Accept"
ContentTypeHeader = "Content-Type"
)
// APIPaths defines the URL paths used by the client.
type APIPaths struct {
ApiPath string
ApiV2Path string
LoginPath string
StatusPath string
LogoutPath string
UploadPath string
}
var (
OldStyleAPI = APIPaths{
ApiPath: apiPath,
ApiV2Path: apiV2Path,
LoginPath: loginPath,
StatusPath: statusPath,
LogoutPath: logoutPath,
UploadPath: uploadPath,
}
NewStyleAPI = APIPaths{
ApiPath: apiPathNew,
ApiV2Path: apiV2PathNew,
LoginPath: loginPathNew,
StatusPath: statusPathNew,
LogoutPath: logoutPath,
UploadPath: uploadPathNew,
}
)
// determineApiStyle checks the base URL to decide which API style to use and sets the apiPaths accordingly.
func (c *client) determineApiStyle() error {
c.Debug("Determining API style")
ctx, cancel := c.newRequestContext()
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.baseURL.String(), nil)
if err != nil {
return err
}
client := &http.Client{
CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
return http.ErrUseLastResponse
},
Transport: c.http.Transport,
}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
// Discard response body to avoid leaks
_, _ = io.Copy(io.Discard, resp.Body)
switch resp.StatusCode {
case http.StatusOK:
c.Debug("Using new style API")
c.apiPaths = &NewStyleAPI
case http.StatusFound:
c.Debug("Using old style API")
c.apiPaths = &OldStyleAPI
default:
return fmt.Errorf("expected 200 or 302 status code, but got: %d", resp.StatusCode)
}
if c.apiPaths == &OldStyleAPI && c.credentials.IsAPIKey() {
return errors.New("unable to use API key authentication with old style API. Switch to user/pass authentication or update controller to latest version")
}
return nil
}