From d364aca6465f1f2e1f0d34fdee6b44bf6199e656 Mon Sep 17 00:00:00 2001 From: Erwan Guyader Date: Wed, 27 Nov 2024 10:53:03 +0100 Subject: [PATCH] fix: Remove duplicated manager url config We used to store the manager url in the context config in the `manager_url` attribute. We're now storing it as part of the `clouderies` config so we can remove the old attribute and its use. However, some clients still make use of the old context attribute so we're adding it back in the context API response for backwards compatibility. --- model/instance/instance_test.go | 4 +-- model/instance/manager.go | 35 ++++++++++++++------- pkg/config/config/config_test.go | 7 ++++- pkg/config/config/testdata/full_config.yaml | 5 ++- tests/testutils/test_utils.go | 20 ++++++++++++ web/auth/confirm.go | 8 ++--- web/settings/context.go | 22 +++++++++++-- 7 files changed, 77 insertions(+), 24 deletions(-) diff --git a/model/instance/instance_test.go b/model/instance/instance_test.go index af18fde7b5d..d2c8837c56c 100644 --- a/model/instance/instance_test.go +++ b/model/instance/instance_test.go @@ -61,7 +61,6 @@ func TestInstance(t *testing.T) { cfg.Contexts = map[string]interface{}{ "context": map[string]interface{}{ - "manager_url": "http://manager.example.org", "logos": map[string]interface{}{ "coachco2": map[string]interface{}{ "light": []interface{}{ @@ -173,8 +172,7 @@ func TestInstance(t *testing.T) { } ] } - }, - "manager_url": "http://manager.example.org" + } }` assert.Equal(t, expected, string(bytes)) }) diff --git a/model/instance/manager.go b/model/instance/manager.go index ebfe579baac..61bdc61054f 100644 --- a/model/instance/manager.go +++ b/model/instance/manager.go @@ -19,22 +19,24 @@ const ( ManagerPremiumURL // ManagerBlockedURL is the kind for a redirection of a blocked instance. ManagerBlockedURL + // ManagerBaseURL is the kind for building other manager URLs + ManagerBaseURL ) // ManagerURL returns an external string for the given ManagerURL kind. It is // used for redirecting the user to a manager URL. func (i *Instance) ManagerURL(k ManagerURLKind) (string, error) { - if i.UUID == "" { + c := clouderyConfig(i) + if c == nil { return "", nil } - config, ok := i.SettingsContext() - if !ok { + if i.UUID == "" { return "", nil } - base, ok := config["manager_url"].(string) - if !ok { + base := c.API.URL + if base == "" { return "", nil } @@ -51,6 +53,8 @@ func (i *Instance) ManagerURL(k ManagerURLKind) (string, error) { path = fmt.Sprintf("/cozy/instances/%s/tos", url.PathEscape(i.UUID)) case ManagerBlockedURL: path = fmt.Sprintf("/cozy/instances/%s/blocked", url.PathEscape(i.UUID)) + case ManagerBaseURL: + path = "" default: panic("unknown ManagerURLKind") } @@ -61,6 +65,20 @@ func (i *Instance) ManagerURL(k ManagerURLKind) (string, error) { // APIManagerClient returns a client to talk to the manager via its API. func APIManagerClient(inst *Instance) *manager.APIClient { + c := clouderyConfig(inst) + if c == nil { + return nil + } + + api := c.API + if api.URL == "" || api.Token == "" { + return nil + } + + return manager.NewAPIClient(api.URL, api.Token) +} + +func clouderyConfig(inst *Instance) *config.ClouderyConfig { clouderies := config.GetConfig().Clouderies if clouderies == nil { return nil @@ -75,10 +93,5 @@ func APIManagerClient(inst *Instance) *manager.APIClient { return nil } - api := cloudery.API - if api.URL == "" || api.Token == "" { - return nil - } - - return manager.NewAPIClient(api.URL, api.Token) + return &cloudery } diff --git a/pkg/config/config/config_test.go b/pkg/config/config/config_test.go index de8c219a796..c3af112285b 100644 --- a/pkg/config/config/config_test.go +++ b/pkg/config/config/config_test.go @@ -116,7 +116,6 @@ func TestConfigUnmarshal(t *testing.T) { // Contexts assert.EqualValues(t, map[string]interface{}{ "my-context": map[string]interface{}{ - "manager_url": "https://manager-url", "onboarded_redirection": "home/intro", "default_redirection": "home/", "help_link": "https://cozy.io/fr/support", @@ -216,6 +215,12 @@ func TestConfigUnmarshal(t *testing.T) { Token: "some-token", }, }, + "my-context": { + API: ClouderyAPI{ + URL: "https://manager-url", + Token: "manager-token", + }, + }, }, cfg.Clouderies) // CSPs diff --git a/pkg/config/config/testdata/full_config.yaml b/pkg/config/config/testdata/full_config.yaml index d827a587f0c..ab753424ab6 100644 --- a/pkg/config/config/testdata/full_config.yaml +++ b/pkg/config/config/testdata/full_config.yaml @@ -109,6 +109,10 @@ clouderies: api: url: https://some-url token: some-token + my-context: + api: + url: https://manager-url + token: manager-token password_reset_interval: 1h @@ -163,7 +167,6 @@ log: contexts: my-context: - manager_url: https://manager-url onboarded_redirection: home/intro default_redirection: home/ help_link: https://cozy.io/fr/support diff --git a/tests/testutils/test_utils.go b/tests/testutils/test_utils.go index 34ca8db5f98..e792f445a7c 100644 --- a/tests/testutils/test_utils.go +++ b/tests/testutils/test_utils.go @@ -488,6 +488,13 @@ func WithManager(t *testing.T, inst *instance.Instance, managerConfig ManagerCon cfg := config.GetConfig() originalCfg, _ := json.Marshal(cfg) + if cfg.Clouderies == nil { + cfg.Clouderies = map[string]config.ClouderyConfig{} + } + cloudery, contextName := getCloudery(inst, cfg) + cloudery.API = config.ClouderyAPI{URL: managerConfig.URL, Token: ""} + cfg.Clouderies[contextName] = cloudery + if cfg.Contexts == nil { cfg.Contexts = map[string]interface{}{} } @@ -511,6 +518,19 @@ func WithManager(t *testing.T, inst *instance.Instance, managerConfig ManagerCon return shouldRemoveUUID } +// getCloudery returns the most relevant cloudery config depending on the +// instance context name or creates a new one if none exist. +// It also returns the name of the context associated with the config. +func getCloudery(inst *instance.Instance, cfg *config.Config) (config.ClouderyConfig, string) { + if cloudery, ok := cfg.Clouderies[inst.ContextName]; ok { + return cloudery, inst.ContextName + } + if cloudery, ok := cfg.Clouderies[config.DefaultInstanceContext]; ok { + return cloudery, config.DefaultInstanceContext + } + return config.ClouderyConfig{}, config.DefaultInstanceContext +} + // getContext returns the most relevant context config depending on the // instance context name or creates a new one if none exist. // It also returns the name of the context associated with the config. diff --git a/web/auth/confirm.go b/web/auth/confirm.go index 0a2c64ffe4a..895db8479da 100644 --- a/web/auth/confirm.go +++ b/web/auth/confirm.go @@ -149,12 +149,8 @@ func checkRedirectToAuthorized(c echo.Context) (*url.URL, error) { } func checkRedirectToManager(inst *instance.Instance, redirect *url.URL) bool { - config, ok := inst.SettingsContext() - if !ok { - return false - } - managerURL, ok := config["manager_url"].(string) - if !ok { + managerURL, err := inst.ManagerURL(instance.ManagerBaseURL) + if err != nil { return false } manager, err := url.Parse(managerURL) diff --git a/web/settings/context.go b/web/settings/context.go index fc036e06d3b..2af737d9f6c 100644 --- a/web/settings/context.go +++ b/web/settings/context.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" + "github.com/cozy/cozy-stack/model/instance" "github.com/cozy/cozy-stack/model/instance/lifecycle" "github.com/cozy/cozy-stack/pkg/consts" "github.com/cozy/cozy-stack/pkg/couchdb" @@ -78,6 +79,23 @@ func (h *HTTPHandler) context(c echo.Context) error { } i := middlewares.GetInstance(c) - doc := &apiContext{i.GetContextWithSponsorships()} - return jsonapi.Data(c, http.StatusOK, doc, nil) + context := &apiContext{i.GetContextWithSponsorships()} + + managerURL, err := i.ManagerURL(instance.ManagerBaseURL) + if err != nil { + return err + } + if managerURL != "" { + // XXX: The manager URL used to be stored in the config in + // `context..manager_url`. It's now stored in + // `clouderies..api.url` and can be retrieved via a call + // to `instance.ManagerURL()`. + // + // However, some external apps and clients (e.g. `cozy-client`) still + // expect to find the `manager_url` attribute in the context document + // so we add it back for backwards compatibility. + context.doc["manager_url"] = managerURL + } + + return jsonapi.Data(c, http.StatusOK, context, nil) }