cmd/syncthing: Don't fail early on api setup error (fixes 7558) (#7591)

* cmd/syncthing: Don't fail early on api setup error (fixes 7558)

* switch to factory pattern

* refactor config command to show help on nothing

* wip

* wip

* already abort in before
This commit is contained in:
Simon Frei
2021-04-25 20:48:17 +01:00
committed by GitHub
parent 54e27f551d
commit ef4b8a2cf8
6 changed files with 185 additions and 103 deletions
+66 -11
View File
@@ -17,33 +17,88 @@ import (
"strings"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/locations"
"github.com/syncthing/syncthing/lib/protocol"
)
type APIClient struct {
type APIClient interface {
Get(url string) (*http.Response, error)
Post(url, body string) (*http.Response, error)
}
type apiClient struct {
http.Client
cfg config.GUIConfiguration
apikey string
}
func getClient(cfg config.GUIConfiguration) *APIClient {
type apiClientFactory struct {
cfg config.GUIConfiguration
}
func (f *apiClientFactory) getClient() (APIClient, error) {
// Now if the API key and address is not provided (we are not connecting to a remote instance),
// try to rip it out of the config.
if f.cfg.RawAddress == "" && f.cfg.APIKey == "" {
var err error
f.cfg, err = loadGUIConfig()
if err != nil {
return nil, err
}
} else if f.cfg.Address() == "" || f.cfg.APIKey == "" {
return nil, errors.New("Both --gui-address and --gui-apikey should be specified")
}
httpClient := http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(cfg.Network(), cfg.Address())
return net.Dial(f.cfg.Network(), f.cfg.Address())
},
},
}
return &APIClient{
return &apiClient{
Client: httpClient,
cfg: cfg,
apikey: cfg.APIKey,
}
cfg: f.cfg,
apikey: f.cfg.APIKey,
}, nil
}
func (c *APIClient) Endpoint() string {
func loadGUIConfig() (config.GUIConfiguration, error) {
// Load the certs and get the ID
cert, err := tls.LoadX509KeyPair(
locations.Get(locations.CertFile),
locations.Get(locations.KeyFile),
)
if err != nil {
return config.GUIConfiguration{}, fmt.Errorf("reading device ID: %w", err)
}
myID := protocol.NewDeviceID(cert.Certificate[0])
// Load the config
cfg, _, err := config.Load(locations.Get(locations.ConfigFile), myID, events.NoopLogger)
if err != nil {
return config.GUIConfiguration{}, fmt.Errorf("loading config: %w", err)
}
guiCfg := cfg.GUI()
if guiCfg.Address() == "" {
return config.GUIConfiguration{}, errors.New("Could not find GUI Address")
}
if guiCfg.APIKey == "" {
return config.GUIConfiguration{}, errors.New("Could not find GUI API key")
}
return guiCfg, nil
}
func (c *apiClient) Endpoint() string {
if c.cfg.Network() == "unix" {
return "http://unix/"
}
@@ -54,7 +109,7 @@ func (c *APIClient) Endpoint() string {
return url
}
func (c *APIClient) Do(req *http.Request) (*http.Response, error) {
func (c *apiClient) Do(req *http.Request) (*http.Response, error) {
req.Header.Set("X-API-Key", c.apikey)
resp, err := c.Client.Do(req)
if err != nil {
@@ -63,7 +118,7 @@ func (c *APIClient) Do(req *http.Request) (*http.Response, error) {
return resp, checkResponse(resp)
}
func (c *APIClient) Get(url string) (*http.Response, error) {
func (c *apiClient) Get(url string) (*http.Response, error) {
request, err := http.NewRequest("GET", c.Endpoint()+"rest/"+url, nil)
if err != nil {
return nil, err
@@ -71,7 +126,7 @@ func (c *APIClient) Get(url string) (*http.Response, error) {
return c.Do(request)
}
func (c *APIClient) Post(url, body string) (*http.Response, error) {
func (c *apiClient) Post(url, body string) (*http.Response, error) {
request, err := http.NewRequest("POST", c.Endpoint()+"rest/"+url, bytes.NewBufferString(body))
if err != nil {
return nil, err