From 45d1ba25c099c42a565fe8fc8fb1ab0a19cab006 Mon Sep 17 00:00:00 2001 From: David Christofas Date: Mon, 13 Feb 2023 13:22:52 +0100 Subject: [PATCH] add logo reset endpoint when resetting the logo we are falling back to the embedded logo asset --- ocis-pkg/assetsfs/assetsfs.go | 4 ++ services/web/pkg/service/v0/branding.go | 69 +++++++++++++++++++++++ services/web/pkg/service/v0/instrument.go | 5 ++ services/web/pkg/service/v0/logging.go | 5 ++ services/web/pkg/service/v0/service.go | 2 + services/web/pkg/service/v0/tracing.go | 5 ++ 6 files changed, 90 insertions(+) diff --git a/ocis-pkg/assetsfs/assetsfs.go b/ocis-pkg/assetsfs/assetsfs.go index 311f904662..826acff4ab 100644 --- a/ocis-pkg/assetsfs/assetsfs.go +++ b/ocis-pkg/assetsfs/assetsfs.go @@ -28,6 +28,10 @@ func (f *FileSystem) Open(original string) (http.File, error) { return f.fs.Open(original) } +func (f *FileSystem) OpenEmbedded(name string) (http.File, error) { + return f.fs.Open(name) +} + // Create creates a new file in the assetPath func (f *FileSystem) Create(name string) (*os.File, error) { fullPath := f.jailPath(name) diff --git a/services/web/pkg/service/v0/branding.go b/services/web/pkg/service/v0/branding.go index 0b34e3e32b..afc8592df8 100644 --- a/services/web/pkg/service/v0/branding.go +++ b/services/web/pkg/service/v0/branding.go @@ -76,6 +76,46 @@ func (p Web) UploadLogo(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } +// ResetLogo implements the endpoint to reset the instance logo. +// The config will be changed back to use the embedded logo asset. +func (p Web) ResetLogo(w http.ResponseWriter, r *http.Request) { + user := revactx.ContextMustGetUser(r.Context()) + rsp, err := p.gatewayClient.CheckPermission(r.Context(), &permissionsapi.CheckPermissionRequest{ + Permission: "change-logo", + SubjectRef: &permissionsapi.SubjectReference{ + Spec: &permissionsapi.SubjectReference_UserId{ + UserId: user.Id, + }, + }, + }) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + if rsp.Status.Code != rpc.Code_CODE_OK { + w.WriteHeader(http.StatusForbidden) + return + } + + f, err := p.fs.OpenEmbedded(_themesConfigPath) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + defer f.Close() + + originalPath, err := p.getLogoPath(f) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + if err := p.updateLogoThemeConfig(originalPath); err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } +} + func (p Web) storeAsset(name string, asset io.Reader) error { dst, err := p.fs.Create(name) if err != nil { @@ -87,6 +127,35 @@ func (p Web) storeAsset(name string, asset io.Reader) error { return err } +func (p Web) getLogoPath(r io.Reader) (string, error) { + // This decoding of the themes.json file is not optimal. If we need to decode it for other + // usecases as well we should consider decoding to a struct. + var m map[string]interface{} + _ = json.NewDecoder(r).Decode(&m) + + webCfg, ok := m["web"].(map[string]interface{}) + if !ok { + return "", errInvalidThemeConfig + } + + defaultCfg, ok := webCfg["default"].(map[string]interface{}) + if !ok { + return "", errInvalidThemeConfig + } + + logoCfg, ok := defaultCfg["logo"].(map[string]interface{}) + if !ok { + return "", errInvalidThemeConfig + } + + logoPath, ok := logoCfg["login"].(string) + if !ok { + return "", errInvalidThemeConfig + } + + return logoPath, nil +} + func (p Web) updateLogoThemeConfig(logoPath string) error { f, err := p.fs.Open(_themesConfigPath) if err == nil { diff --git a/services/web/pkg/service/v0/instrument.go b/services/web/pkg/service/v0/instrument.go index 72c64082ce..e01a3b1dc1 100644 --- a/services/web/pkg/service/v0/instrument.go +++ b/services/web/pkg/service/v0/instrument.go @@ -33,3 +33,8 @@ func (i instrument) Config(w http.ResponseWriter, r *http.Request) { func (i instrument) UploadLogo(w http.ResponseWriter, r *http.Request) { i.next.UploadLogo(w, r) } + +// ResetLogo implements the Service interface. +func (i instrument) ResetLogo(w http.ResponseWriter, r *http.Request) { + i.next.ResetLogo(w, r) +} diff --git a/services/web/pkg/service/v0/logging.go b/services/web/pkg/service/v0/logging.go index 09ab4145e0..dbdb3abb91 100644 --- a/services/web/pkg/service/v0/logging.go +++ b/services/web/pkg/service/v0/logging.go @@ -33,3 +33,8 @@ func (l logging) Config(w http.ResponseWriter, r *http.Request) { func (l logging) UploadLogo(w http.ResponseWriter, r *http.Request) { l.next.UploadLogo(w, r) } + +// ResetLogo implements the Service interface. +func (l logging) ResetLogo(w http.ResponseWriter, r *http.Request) { + l.next.ResetLogo(w, r) +} diff --git a/services/web/pkg/service/v0/service.go b/services/web/pkg/service/v0/service.go index 3f816a3e51..2699f975f2 100644 --- a/services/web/pkg/service/v0/service.go +++ b/services/web/pkg/service/v0/service.go @@ -31,6 +31,7 @@ type Service interface { ServeHTTP(http.ResponseWriter, *http.Request) Config(http.ResponseWriter, *http.Request) UploadLogo(http.ResponseWriter, *http.Request) + ResetLogo(http.ResponseWriter, *http.Request) } // NewService returns a service implementation for Service. @@ -56,6 +57,7 @@ func NewService(opts ...Option) Service { account.JWTSecret(options.Config.TokenManager.JWTSecret), )) r.Post("/", svc.UploadLogo) + r.Delete("/", svc.ResetLogo) }) r.Mount("/", svc.Static(options.Config.HTTP.CacheTTL)) }) diff --git a/services/web/pkg/service/v0/tracing.go b/services/web/pkg/service/v0/tracing.go index 2889715bdc..413257e9cd 100644 --- a/services/web/pkg/service/v0/tracing.go +++ b/services/web/pkg/service/v0/tracing.go @@ -29,3 +29,8 @@ func (t tracing) Config(w http.ResponseWriter, r *http.Request) { func (t tracing) UploadLogo(w http.ResponseWriter, r *http.Request) { t.next.UploadLogo(w, r) } + +// ResetLogo implements the Service interface. +func (t tracing) ResetLogo(w http.ResponseWriter, r *http.Request) { + t.next.ResetLogo(w, r) +}