fix: label policy (#1828)

* fix: font color

* fix: assets from iam when policy is default

* fix: remove multiple files

* fix mock storage

* doc: add asset api

* build assets docs

* fix operator test

* docs

* fix remove assets from org label policy and not default

* fix remove label policy assets and feature downgrade correctly

* fix storage mock

* Update docs/docs/apis/apis.md

Co-authored-by: fabi <fabienne.gerschwiler@gmail.com>
Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
Livio Amstutz 2021-06-08 09:48:44 +02:00 committed by GitHub
parent 0ed722395e
commit 81974b977d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 641 additions and 162 deletions

View File

@ -140,7 +140,8 @@ COPY internal/errors internal/errors
RUN build/zitadel/generate-grpc.sh \ RUN build/zitadel/generate-grpc.sh \
&& go generate openapi/statik/generate.go \ && go generate openapi/statik/generate.go \
&& go run internal/api/assets/generator/asset_generator.go -directory=internal/api/assets/generator/ && mkdir -p docs/apis/assets/ \
&& go run internal/api/assets/generator/asset_generator.go -directory=internal/api/assets/generator/ -assets=docs/apis/assets/assets.md
####################### #######################
@ -166,6 +167,7 @@ COPY --from=go-stub /go/src/github.com/caos/zitadel/openapi/statik/statik.go ope
COPY --from=go-stub /go/src/github.com/caos/zitadel/internal/protoc/protoc-gen-authoption/templates.gen.go internal/protoc/protoc-gen-authoption/templates.gen.go COPY --from=go-stub /go/src/github.com/caos/zitadel/internal/protoc/protoc-gen-authoption/templates.gen.go internal/protoc/protoc-gen-authoption/templates.gen.go
COPY --from=go-stub /go/src/github.com/caos/zitadel/internal/protoc/protoc-gen-authoption/authoption/options.pb.go internal/protoc/protoc-gen-authoption/authoption/options.pb.go COPY --from=go-stub /go/src/github.com/caos/zitadel/internal/protoc/protoc-gen-authoption/authoption/options.pb.go internal/protoc/protoc-gen-authoption/authoption/options.pb.go
COPY --from=go-stub /go/src/github.com/caos/zitadel/docs/apis/proto docs/docs/apis/proto COPY --from=go-stub /go/src/github.com/caos/zitadel/docs/apis/proto docs/docs/apis/proto
COPY --from=go-stub /go/src/github.com/caos/zitadel/docs/apis/assets docs/docs/apis/assets
COPY --from=go-stub /go/src/github.com/caos/zitadel/internal/api/assets/authz.go ./internal/api/assets/authz.go COPY --from=go-stub /go/src/github.com/caos/zitadel/internal/api/assets/authz.go ./internal/api/assets/authz.go
COPY --from=go-stub /go/src/github.com/caos/zitadel/internal/api/assets/router.go ./internal/api/assets/router.go COPY --from=go-stub /go/src/github.com/caos/zitadel/internal/api/assets/router.go ./internal/api/assets/router.go

View File

@ -20,6 +20,7 @@ AssetStorage:
SSL: $ZITADEL_ASSET_STORAGE_SSL SSL: $ZITADEL_ASSET_STORAGE_SSL
Location: $ZITADEL_ASSET_STORAGE_LOCATION Location: $ZITADEL_ASSET_STORAGE_LOCATION
BucketPrefix: $ZITADEL_ASSET_STORAGE_BUCKET_PREFIX BucketPrefix: $ZITADEL_ASSET_STORAGE_BUCKET_PREFIX
MultiDelete: $ZITADEL_ASSET_STORAGE_MULTI_DELETE
Metrics: Metrics:
Type: 'otel' Type: 'otel'

View File

@ -1,3 +0,0 @@
---
title: Administration
---

View File

@ -50,3 +50,13 @@ This API is intended to configure and manage the IAM itself.
| GRPC | [https://api.zitadel.ch/caos.zitadel.admin.api.v1.AdminService/](https://api.zitadel.ch/caos.zitadel.admin.api.v1.AdminService) | | GRPC | [https://api.zitadel.ch/caos.zitadel.admin.api.v1.AdminService/](https://api.zitadel.ch/caos.zitadel.admin.api.v1.AdminService) |
[Latest API Version](https://github.com/caos/zitadel/blob/main/proto/zitadel/admin.proto) [Latest API Version](https://github.com/caos/zitadel/blob/main/proto/zitadel/admin.proto)
## Assets API
The Assets API allows you to up- and download all kinds of assets. This can be files such as logos, fonts or user avatar.
| Service | URI |
|:--------|:--------------------------------------------------------------------------------------------------------------------------------|
| REST | [https://api.zitadel.ch/assets/v1/](https://api.zitadel.ch/assets/v1/) |

259
docs/docs/apis/assets/assets.md Executable file
View File

@ -0,0 +1,259 @@
---
title: zitadel/assets
---
## AssetsService
### UploadDefaultLabelPolicyFont()
> UploadDefaultLabelPolicyFont()
POST: /iam/policy/label/font
### GetDefaultLabelPolicyFont()
> GetDefaultLabelPolicyFont()
GET: /iam/policy/label/font
### GetPreviewDefaultLabelPolicyFont()
> GetPreviewDefaultLabelPolicyFont()
GET: /iam/policy/label/font/_preview
### UploadDefaultLabelPolicyIcon()
> UploadDefaultLabelPolicyIcon()
POST: /iam/policy/label/icon
### UploadDefaultLabelPolicyIcon()
> UploadDefaultLabelPolicyIconDark()
POST: /iam/policy/label/icon/dark
### GetDefaultLabelPolicyIcon()
> GetDefaultLabelPolicyIcon()
GET: /iam/policy/label/icon
### GetDefaultLabelPolicyIcon()
> GetDefaultLabelPolicyIconDark()
GET: /iam/policy/label/icon/dark
### GetPreviewDefaultLabelPolicyIcon()
> GetPreviewDefaultLabelPolicyIcon()
GET: /iam/policy/label/icon/_preview
### GetPreviewDefaultLabelPolicyIcon()
> GetPreviewDefaultLabelPolicyIconDark()
GET: /iam/policy/label/icon/dark/_preview
### UploadDefaultLabelPolicyLogo()
> UploadDefaultLabelPolicyLogo()
POST: /iam/policy/label/logo
### UploadDefaultLabelPolicyLogo()
> UploadDefaultLabelPolicyLogoDark()
POST: /iam/policy/label/logo/dark
### GetDefaultLabelPolicyLogo()
> GetDefaultLabelPolicyLogo()
GET: /iam/policy/label/logo
### GetDefaultLabelPolicyLogo()
> GetDefaultLabelPolicyLogoDark()
GET: /iam/policy/label/logo/dark
### GetPreviewDefaultLabelPolicyLogo()
> GetPreviewDefaultLabelPolicyLogo()
GET: /iam/policy/label/logo/_preview
### GetPreviewDefaultLabelPolicyLogo()
> GetPreviewDefaultLabelPolicyLogoDark()
GET: /iam/policy/label/logo/dark/_preview
### UploadOrgLabelPolicyFont()
> UploadOrgLabelPolicyFont()
POST: /org/policy/label/font
### GetOrgLabelPolicyFont()
> GetOrgLabelPolicyFont()
GET: /org/policy/label/font
### GetPreviewOrgLabelPolicyFont()
> GetPreviewOrgLabelPolicyFont()
GET: /org/policy/label/font/_preview
### UploadOrgLabelPolicyIcon()
> UploadOrgLabelPolicyIcon()
POST: /org/policy/label/icon
### UploadOrgLabelPolicyIcon()
> UploadOrgLabelPolicyIconDark()
POST: /org/policy/label/icon/dark
### GetOrgLabelPolicyIcon()
> GetOrgLabelPolicyIcon()
GET: /org/policy/label/icon
### GetOrgLabelPolicyIcon()
> GetOrgLabelPolicyIconDark()
GET: /org/policy/label/icon/dark
### GetPreviewOrgLabelPolicyIcon()
> GetPreviewOrgLabelPolicyIcon()
GET: /org/policy/label/icon/_preview
### GetPreviewOrgLabelPolicyIcon()
> GetPreviewOrgLabelPolicyIconDark()
GET: /org/policy/label/icon/dark/_preview
### UploadOrgLabelPolicyLogo()
> UploadOrgLabelPolicyLogo()
POST: /org/policy/label/logo
### UploadOrgLabelPolicyLogo()
> UploadOrgLabelPolicyLogoDark()
POST: /org/policy/label/logo/dark
### GetOrgLabelPolicyLogo()
> GetOrgLabelPolicyLogo()
GET: /org/policy/label/logo
### GetOrgLabelPolicyLogo()
> GetOrgLabelPolicyLogoDark()
GET: /org/policy/label/logo/dark
### GetPreviewOrgLabelPolicyLogo()
> GetPreviewOrgLabelPolicyLogo()
GET: /org/policy/label/logo/_preview
### GetPreviewOrgLabelPolicyLogo()
> GetPreviewOrgLabelPolicyLogoDark()
GET: /org/policy/label/logo/dark/_preview
### UploadMyUserAvatar()
> UploadMyUserAvatar()
POST: /users/me/avatar
### GetMyUserAvatar()
> GetMyUserAvatar()
GET: /users/me/avatar

View File

@ -1,3 +0,0 @@
---
title: Authentication
---

View File

@ -8,10 +8,11 @@ title: Introduction
--- ---
ZITADEL provides three API's for different use cases. These API's are built with GRPC and then generate a REST service. ZITADEL provides four API's for different use cases. Three API's are built with GRPC and then generate a REST service.
Each service's proto definition is located in the source control on GitHub. Each service's proto definition is located in the source control on GitHub.
As we generate the REST services and Swagger file out of the proto definition we recommend that you rely on the proto file. As we generate the REST services and Swagger file out of the proto definition we recommend that you rely on the proto file.
We annotate the corresponding REST methods on each possible call as well as the AuthN and AuthZ requirements. We annotate the corresponding REST methods on each possible call as well as the AuthN and AuthZ requirements.
The last API (assets) is only a REST API because we use multipart form data.
See below for an example with the call **GetMyUser**. See below for an example with the call **GetMyUser**.

View File

@ -1,3 +0,0 @@
---
title: Management
---

View File

@ -109,6 +109,14 @@ module.exports = {
'apis/proto/options', 'apis/proto/options',
], ],
}, },
{
type: 'category',
label: 'Assets API Definition',
collapsed: false,
items: [
'apis/assets/assets',
],
},
{ {
type: 'category', type: 'category',
label: 'OpenID Connect & OAuth', label: 'OpenID Connect & OAuth',

1
go.mod
View File

@ -69,6 +69,7 @@ require (
go.opentelemetry.io/otel/exporters/stdout v0.13.0 go.opentelemetry.io/otel/exporters/stdout v0.13.0
go.opentelemetry.io/otel/sdk v0.13.0 go.opentelemetry.io/otel/sdk v0.13.0
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/text v0.3.6 golang.org/x/text v0.3.6
golang.org/x/tools v0.1.0 golang.org/x/tools v0.1.0
google.golang.org/api v0.34.0 google.golang.org/api v0.34.0

2
go.sum
View File

@ -1118,6 +1118,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@ -174,6 +174,12 @@ func (m *Styling) writeFile(policy *iam_model.LabelPolicyView) (io.Reader, int64
cssContent += fmt.Sprintf("--zitadel-color-warn-%v: %s;", i, color) cssContent += fmt.Sprintf("--zitadel-color-warn-%v: %s;", i, color)
} }
} }
if policy.FontColor != "" {
palette := m.generateColorPaletteRGBA255(policy.FontColor)
for i, color := range palette {
cssContent += fmt.Sprintf("--zitadel-color-text-%v: %s;", i, color)
}
}
var fontname string var fontname string
if policy.FontURL != "" { if policy.FontURL != "" {
split := strings.Split(policy.FontURL, "/") split := strings.Split(policy.FontURL, "/")
@ -206,7 +212,7 @@ func (m *Styling) writeFile(policy *iam_model.LabelPolicyView) (io.Reader, int64
if policy.FontColorDark != "" { if policy.FontColorDark != "" {
palette := m.generateColorPaletteRGBA255(policy.FontColorDark) palette := m.generateColorPaletteRGBA255(policy.FontColorDark)
for i, color := range palette { for i, color := range palette {
cssContent += fmt.Sprintf("--zitadel-color-font-%v: %s;", i, color) cssContent += fmt.Sprintf("--zitadel-color-text-%v: %s;", i, color)
} }
} }
cssContent += fmt.Sprint("}") cssContent += fmt.Sprint("}")

View File

@ -123,7 +123,7 @@ func UploadHandleFunc(s AssetsService, uploader Uploader) func(http.ResponseWrit
contentType := handler.Header.Get("content-type") contentType := handler.Header.Get("content-type")
size := handler.Size size := handler.Size
if !uploader.ContentTypeAllowed(contentType) { if !uploader.ContentTypeAllowed(contentType) {
s.ErrorHandler()(w, r, caos_errs.ThrowInvalidArgument(nil, "UPLOAD-Dbvfs", "invalid content-type")) s.ErrorHandler()(w, r, caos_errs.ThrowInvalidArgumentf(nil, "UPLOAD-Dbvfs", "invalid content-type: %s", contentType))
return return
} }
if size > uploader.MaxFileSize() { if size > uploader.MaxFileSize() {

View File

@ -13,6 +13,7 @@ import (
var ( var (
directory = flag.String("directory", "./", "working directory: asset.yaml must be in this directory, files will be generated into parent directory") directory = flag.String("directory", "./", "working directory: asset.yaml must be in this directory, files will be generated into parent directory")
assets = flag.String("assets", "../../../../docs/docs/apis/assets/assets.md", "path where the assets.md will be generated")
) )
func main() { func main() {
@ -22,7 +23,9 @@ func main() {
logging.Log("ASSETS-Gn31f").OnError(err).Fatal("cannot open authz file") logging.Log("ASSETS-Gn31f").OnError(err).Fatal("cannot open authz file")
router, err := os.OpenFile(*directory+"../router.go", os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0755) router, err := os.OpenFile(*directory+"../router.go", os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0755)
logging.Log("ASSETS-ABen3").OnError(err).Fatal("cannot open router file") logging.Log("ASSETS-ABen3").OnError(err).Fatal("cannot open router file")
GenerateAssetHandler(configFile, authz, router) docs, err := os.OpenFile(*assets, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0755)
logging.Log("ASSETS-Dfvsd").OnError(err).Fatal("cannot open docs file")
GenerateAssetHandler(configFile, authz, router, docs)
} }
type Method struct { type Method struct {
@ -94,7 +97,7 @@ type Service struct {
Methods map[string]Method Methods map[string]Method
} }
func GenerateAssetHandler(configFilePath string, output io.Writer, output2 io.Writer) { func GenerateAssetHandler(configFilePath string, authz, router, docs io.Writer) {
conf := new(struct { conf := new(struct {
Services Services Services Services
}) })
@ -104,6 +107,8 @@ func GenerateAssetHandler(configFilePath string, output io.Writer, output2 io.Wr
logging.Log("ASSETS-BGbbg").OnError(err).Fatal("cannot parse authz template") logging.Log("ASSETS-BGbbg").OnError(err).Fatal("cannot parse authz template")
tmplRouter, err := template.New("").Parse(routerTmpl) tmplRouter, err := template.New("").Parse(routerTmpl)
logging.Log("ASSETS-gh4rq").OnError(err).Fatal("cannot parse router template") logging.Log("ASSETS-gh4rq").OnError(err).Fatal("cannot parse router template")
tmplDocs, err := template.New("").Parse(docsTmpl)
logging.Log("ASSETS-FGdgs").OnError(err).Fatal("cannot parse docs template")
data := &struct { data := &struct {
GoPkgName string GoPkgName string
Name string Name string
@ -115,10 +120,12 @@ func GenerateAssetHandler(configFilePath string, output io.Writer, output2 io.Wr
Prefix: "/assets/v1", Prefix: "/assets/v1",
Services: conf.Services, Services: conf.Services,
} }
err = tmplAuthz.Execute(output, data) err = tmplAuthz.Execute(authz, data)
logging.Log("ASSETS-BHngj").OnError(err).Fatal("cannot generate authz") logging.Log("ASSETS-BHngj").OnError(err).Fatal("cannot generate authz")
err = tmplRouter.Execute(output2, data) err = tmplRouter.Execute(router, data)
logging.Log("ASSETS-Bfd41").OnError(err).Fatal("cannot generate router") logging.Log("ASSETS-Bfd41").OnError(err).Fatal("cannot generate router")
err = tmplDocs.Execute(docs, data)
logging.Log("ASSETS-Bfd41").OnError(err).Fatal("cannot generate docs")
} }
const authzTmpl = `package {{.GoPkgName}} const authzTmpl = `package {{.GoPkgName}}
@ -198,3 +205,30 @@ func RegisterRoutes(router *mux.Router, s {{.Name}}) {
{{ end }} {{ end }}
} }
` `
const docsTmpl = `---
title: zitadel/admin.proto
---
## {{.Name}}
{{ range $service := .Services}}
{{ range $methodName, $method := .Methods}}
{{ range $handler := .Handlers}}
### {{$handler.Name}}{{$methodName}}()
> {{$handler.Name}}{{$methodName}}()
{{$handler.Method}}: {{$service.Prefix}}{{$method.Path}}{{$handler.PathSuffix}}
{{ if $method.HasDarkMode }}
### {{$handler.Name}}{{$methodName}}()
> {{$handler.Name}}{{$methodName}}Dark()
{{$handler.Method}}: {{$service.Prefix}}{{$method.Path}}/dark{{$handler.PathSuffix}}
{{ end }}
{{ end }}
{{ end }}
{{ end }}
`

View File

@ -136,10 +136,7 @@ func (l *labelPolicyLogoDownloader) ObjectName(ctx context.Context, path string)
} }
func (l *labelPolicyLogoDownloader) BucketName(ctx context.Context, id string) string { func (l *labelPolicyLogoDownloader) BucketName(ctx context.Context, id string) string {
if l.defaultPolicy { return getLabelPolicyBucketName(ctx, l.defaultPolicy, l.preview, l.org)
return domain.IAMID
}
return authz.GetCtxData(ctx).OrgID
} }
func (h *Handler) UploadDefaultLabelPolicyIcon() Uploader { func (h *Handler) UploadDefaultLabelPolicyIcon() Uploader {
@ -267,10 +264,7 @@ func (l *labelPolicyIconDownloader) ObjectName(ctx context.Context, path string)
} }
func (l *labelPolicyIconDownloader) BucketName(ctx context.Context, id string) string { func (l *labelPolicyIconDownloader) BucketName(ctx context.Context, id string) string {
if l.defaultPolicy { return getLabelPolicyBucketName(ctx, l.defaultPolicy, l.preview, l.org)
return domain.IAMID
}
return authz.GetCtxData(ctx).OrgID
} }
func (h *Handler) UploadDefaultLabelPolicyFont() Uploader { func (h *Handler) UploadDefaultLabelPolicyFont() Uploader {
@ -357,10 +351,7 @@ func (l *labelPolicyFontDownloader) ObjectName(ctx context.Context, path string)
} }
func (l *labelPolicyFontDownloader) BucketName(ctx context.Context, id string) string { func (l *labelPolicyFontDownloader) BucketName(ctx context.Context, id string) string {
if l.defaultPolicy { return getLabelPolicyBucketName(ctx, l.defaultPolicy, l.preview, l.org)
return domain.IAMID
}
return authz.GetCtxData(ctx).OrgID
} }
func getLabelPolicy(ctx context.Context, defaultPolicy, preview bool, orgRepo repository.OrgRepository) (*model.LabelPolicyView, error) { func getLabelPolicy(ctx context.Context, defaultPolicy, preview bool, orgRepo repository.OrgRepository) (*model.LabelPolicyView, error) {
@ -375,3 +366,17 @@ func getLabelPolicy(ctx context.Context, defaultPolicy, preview bool, orgRepo re
} }
return orgRepo.GetLabelPolicy(ctx) return orgRepo.GetLabelPolicy(ctx)
} }
func getLabelPolicyBucketName(ctx context.Context, defaultPolicy, preview bool, org repository.OrgRepository) string {
if defaultPolicy {
return domain.IAMID
}
policy, err := getLabelPolicy(ctx, defaultPolicy, preview, org)
if err != nil {
return ""
}
if policy.Default {
return domain.IAMID
}
return authz.GetCtxData(ctx).OrgID
}

View File

@ -86,7 +86,7 @@ func (s *Server) ResetLabelPolicyToDefault(ctx context.Context, req *mgmt_pb.Res
} }
func (s *Server) RemoveCustomLabelPolicyLogo(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyLogoRequest) (*mgmt_pb.RemoveCustomLabelPolicyLogoResponse, error) { func (s *Server) RemoveCustomLabelPolicyLogo(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyLogoRequest) (*mgmt_pb.RemoveCustomLabelPolicyLogoResponse, error) {
policy, err := s.command.RemoveLogoDefaultLabelPolicy(ctx) policy, err := s.command.RemoveLogoLabelPolicy(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -100,7 +100,7 @@ func (s *Server) RemoveCustomLabelPolicyLogo(ctx context.Context, req *mgmt_pb.R
} }
func (s *Server) RemoveCustomLabelPolicyLogoDark(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyLogoDarkRequest) (*mgmt_pb.RemoveCustomLabelPolicyLogoDarkResponse, error) { func (s *Server) RemoveCustomLabelPolicyLogoDark(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyLogoDarkRequest) (*mgmt_pb.RemoveCustomLabelPolicyLogoDarkResponse, error) {
policy, err := s.command.RemoveLogoDarkDefaultLabelPolicy(ctx) policy, err := s.command.RemoveLogoDarkLabelPolicy(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -114,7 +114,7 @@ func (s *Server) RemoveCustomLabelPolicyLogoDark(ctx context.Context, req *mgmt_
} }
func (s *Server) RemoveCustomLabelPolicyIcon(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyIconRequest) (*mgmt_pb.RemoveCustomLabelPolicyIconResponse, error) { func (s *Server) RemoveCustomLabelPolicyIcon(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyIconRequest) (*mgmt_pb.RemoveCustomLabelPolicyIconResponse, error) {
policy, err := s.command.RemoveIconDefaultLabelPolicy(ctx) policy, err := s.command.RemoveIconLabelPolicy(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -128,7 +128,7 @@ func (s *Server) RemoveCustomLabelPolicyIcon(ctx context.Context, req *mgmt_pb.R
} }
func (s *Server) RemoveCustomLabelPolicyIconDark(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyIconDarkRequest) (*mgmt_pb.RemoveCustomLabelPolicyIconDarkResponse, error) { func (s *Server) RemoveCustomLabelPolicyIconDark(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyIconDarkRequest) (*mgmt_pb.RemoveCustomLabelPolicyIconDarkResponse, error) {
policy, err := s.command.RemoveIconDarkDefaultLabelPolicy(ctx) policy, err := s.command.RemoveIconDarkLabelPolicy(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -142,7 +142,7 @@ func (s *Server) RemoveCustomLabelPolicyIconDark(ctx context.Context, req *mgmt_
} }
func (s *Server) RemoveCustomLabelPolicyFont(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyFontRequest) (*mgmt_pb.RemoveCustomLabelPolicyFontResponse, error) { func (s *Server) RemoveCustomLabelPolicyFont(ctx context.Context, req *mgmt_pb.RemoveCustomLabelPolicyFontRequest) (*mgmt_pb.RemoveCustomLabelPolicyFontResponse, error) {
policy, err := s.command.RemoveFontDefaultLabelPolicy(ctx) policy, err := s.command.RemoveFontLabelPolicy(ctx, authz.GetCtxData(ctx).OrgID)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -98,6 +98,8 @@ func (m *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case model.LabelPolicyRemoved:
return m.view.DeleteLabelPolicy(event.AggregateID, event)
default: default:
return m.view.ProcessedLabelPolicySequence(event) return m.view.ProcessedLabelPolicySequence(event)
} }

View File

@ -279,12 +279,15 @@ func (c *Commands) setAllowedLabelPolicy(ctx context.Context, orgID string, feat
} }
events = append(events, assetsEvent) events = append(events, assetsEvent)
} }
changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, OrgAggregateFromWriteModel(&existingPolicy.WriteModel), changedEvent, hasChangedEvent := existingPolicy.NewChangedEvent(ctx, OrgAggregateFromWriteModel(&existingPolicy.WriteModel),
policy.PrimaryColor, policy.BackgroundColor, policy.WarnColor, policy.FontColor, policy.PrimaryColor, policy.BackgroundColor, policy.WarnColor, policy.FontColor,
policy.PrimaryColorDark, policy.BackgroundColorDark, policy.WarnColorDark, policy.FontColorDark, policy.PrimaryColorDark, policy.BackgroundColorDark, policy.WarnColorDark, policy.FontColorDark,
policy.HideLoginNameSuffix, policy.ErrorMsgPopup, policy.HideLoginNameSuffix) policy.HideLoginNameSuffix, policy.ErrorMsgPopup, policy.HideLoginNameSuffix)
if hasChanged { if hasChangedEvent {
events = append(events, changedEvent) events = append(events, changedEvent)
} }
if len(events) > 0 {
events = append(events, org.NewLabelPolicyActivatedEvent(ctx, OrgAggregateFromWriteModel(&existingPolicy.WriteModel)))
}
return events, nil return events, nil
} }

View File

@ -958,7 +958,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
), ),
), ),
iamDomain: "iam-domain", iamDomain: "iam-domain",
static: mock.NewMockStorage(gomock.NewController(t)).ExpectRemoveObjectNoError(), static: mock.NewMockStorage(gomock.NewController(t)).ExpectRemoveObjectsNoError(),
}, },
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),

View File

@ -324,10 +324,6 @@ func (c *Commands) RemoveIconDarkLabelPolicy(ctx context.Context, orgID string)
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved { if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "ORG-3NFos", "Errors.Org.LabelPolicy.NotFound") return nil, caos_errs.ThrowNotFound(nil, "ORG-3NFos", "Errors.Org.LabelPolicy.NotFound")
} }
err = c.RemoveAsset(ctx, orgID, existingPolicy.IconDarkKey)
if err != nil {
return nil, err
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel) orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyIconDarkRemovedEvent(ctx, orgAgg, existingPolicy.IconDarkKey)) pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyIconDarkRemovedEvent(ctx, orgAgg, existingPolicy.IconDarkKey))
if err != nil { if err != nil {
@ -379,10 +375,6 @@ func (c *Commands) RemoveFontLabelPolicy(ctx context.Context, orgID string) (*do
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved { if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "ORG-4n9SD", "Errors.Org.LabelPolicy.NotFound") return nil, caos_errs.ThrowNotFound(nil, "ORG-4n9SD", "Errors.Org.LabelPolicy.NotFound")
} }
err = c.RemoveAsset(ctx, orgID, existingPolicy.FontKey)
if err != nil {
return nil, err
}
orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel) orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LabelPolicyWriteModel.WriteModel)
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyFontRemovedEvent(ctx, orgAgg, existingPolicy.FontKey)) pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewLabelPolicyFontRemovedEvent(ctx, orgAgg, existingPolicy.FontKey))
if err != nil { if err != nil {
@ -423,7 +415,8 @@ func (c *Commands) removeLabelPolicy(ctx context.Context, existingPolicy *OrgLab
if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved { if existingPolicy.State == domain.PolicyStateUnspecified || existingPolicy.State == domain.PolicyStateRemoved {
return nil, caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LabelPolicy.NotFound") return nil, caos_errs.ThrowNotFound(nil, "Org-3M9df", "Errors.Org.LabelPolicy.NotFound")
} }
err = c.RemoveAsset(ctx, existingPolicy.AggregateID, domain.LabelPolicyPrefix)
err = c.RemoveAssetsFolder(ctx, existingPolicy.AggregateID, domain.LabelPolicyPrefix+"/", true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -439,7 +432,7 @@ func (c *Commands) removeLabelPolicyIfExists(ctx context.Context, orgID string)
if existingPolicy.State != domain.PolicyStateActive { if existingPolicy.State != domain.PolicyStateActive {
return nil, nil return nil, nil
} }
err = c.RemoveAsset(ctx, orgID, domain.LabelPolicyPrefix) err = c.RemoveAssetsFolder(ctx, orgID, domain.LabelPolicyPrefix+"/", true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -448,7 +441,7 @@ func (c *Commands) removeLabelPolicyIfExists(ctx context.Context, orgID string)
} }
func (c *Commands) removeLabelPolicyAssets(ctx context.Context, existingPolicy *OrgLabelPolicyWriteModel) (*org.LabelPolicyAssetsRemovedEvent, error) { func (c *Commands) removeLabelPolicyAssets(ctx context.Context, existingPolicy *OrgLabelPolicyWriteModel) (*org.LabelPolicyAssetsRemovedEvent, error) {
err := c.RemoveAsset(ctx, existingPolicy.AggregateID, domain.LabelPolicyPrefix) err := c.RemoveAssetsFolder(ctx, existingPolicy.AggregateID, domain.LabelPolicyPrefix+"/", true)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -575,7 +575,7 @@ func TestCommandSide_RemoveLabelPolicy(t *testing.T) {
}, },
), ),
), ),
static: mock.NewMockStorage(gomock.NewController(t)).ExpectRemoveObjectNoError(), static: mock.NewMockStorage(gomock.NewController(t)).ExpectRemoveObjectsNoError(),
}, },
args: args{ args: args{
ctx: context.Background(), ctx: context.Background(),
@ -1559,7 +1559,6 @@ func TestCommandSide_RemoveIconDarkLabelPolicy(t *testing.T) {
{ {
name: "icon dark added, ok", name: "icon dark added, ok",
fields: fields{ fields: fields{
storage: mock.NewMockStorage(gomock.NewController(t)).ExpectRemoveObjectNoError(),
eventstore: eventstoreExpect( eventstore: eventstoreExpect(
t, t,
expectFilter( expectFilter(
@ -1813,7 +1812,6 @@ func TestCommandSide_RemoveFontLabelPolicy(t *testing.T) {
{ {
name: "font added, ok", name: "font added, ok",
fields: fields{ fields: fields{
storage: mock.NewMockStorage(gomock.NewController(t)).ExpectRemoveObjectNoError(),
eventstore: eventstoreExpect( eventstore: eventstoreExpect(
t, t,
expectFilter( expectFilter(

View File

@ -25,3 +25,7 @@ func (c *Commands) UploadAsset(ctx context.Context, bucketName, objectName, cont
func (c *Commands) RemoveAsset(ctx context.Context, bucketName, storeKey string) error { func (c *Commands) RemoveAsset(ctx context.Context, bucketName, storeKey string) error {
return c.static.RemoveObject(ctx, bucketName, storeKey) return c.static.RemoveObject(ctx, bucketName, storeKey)
} }
func (c *Commands) RemoveAssetsFolder(ctx context.Context, bucketName, path string, recursive bool) error {
return c.static.RemoveObjects(ctx, bucketName, path, recursive)
}

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore/v1" "github.com/caos/zitadel/internal/eventstore/v1"
es_models "github.com/caos/zitadel/internal/eventstore/v1/models" es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
@ -100,6 +101,8 @@ func (m *LabelPolicy) processLabelPolicy(event *es_models.Event) (err error) {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case model.LabelPolicyRemoved:
return m.view.DeleteLabelPolicy(event.AggregateID, event)
case iam_es_model.LabelPolicyActivated, model.LabelPolicyActivated: case iam_es_model.LabelPolicyActivated, model.LabelPolicyActivated:
policy, err = m.view.LabelPolicyByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview)) policy, err = m.view.LabelPolicyByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview))
if err != nil { if err != nil {
@ -135,15 +138,21 @@ func (p *LabelPolicy) CleanUpBucket(policy *iam_model.LabelPolicyView) {
return return
} }
for _, object := range objects { for _, object := range objects {
if !deleteableObject(object, policy) { if !deletableObject(object, policy) {
continue continue
} }
p.static.RemoveObject(ctx, policy.AggregateID, object.Key) err = p.static.RemoveObject(ctx, policy.AggregateID, object.Key)
logging.LogWithFields("SPOOL-ASd3g", "aggregate", policy.AggregateID, "key", object.Key).OnError(err).Warn("could not delete asset")
} }
} }
func deleteableObject(object *domain.AssetInfo, policy *iam_model.LabelPolicyView) bool { func deletableObject(object *domain.AssetInfo, policy *iam_model.LabelPolicyView) bool {
if object.Key == policy.LogoURL || object.Key == policy.LogoDarkURL || object.Key == policy.IconURL || object.Key == policy.IconDarkURL || object.Key == policy.FontURL { if object.Key == policy.LogoURL ||
object.Key == policy.LogoDarkURL ||
object.Key == policy.IconURL ||
object.Key == policy.IconDarkURL ||
object.Key == policy.FontURL ||
object.Key == domain.LabelPolicyPrefix+"/css/" {
return false return false
} }
return true return true

View File

@ -6,39 +6,40 @@ package mock
import ( import (
context "context" context "context"
domain "github.com/caos/zitadel/internal/domain"
static "github.com/caos/zitadel/internal/static"
gomock "github.com/golang/mock/gomock"
io "io" io "io"
url "net/url" url "net/url"
reflect "reflect" reflect "reflect"
time "time" time "time"
domain "github.com/caos/zitadel/internal/domain"
static "github.com/caos/zitadel/internal/static"
gomock "github.com/golang/mock/gomock"
) )
// MockStorage is a mock of Storage interface // MockStorage is a mock of Storage interface.
type MockStorage struct { type MockStorage struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockStorageMockRecorder recorder *MockStorageMockRecorder
} }
// MockStorageMockRecorder is the mock recorder for MockStorage // MockStorageMockRecorder is the mock recorder for MockStorage.
type MockStorageMockRecorder struct { type MockStorageMockRecorder struct {
mock *MockStorage mock *MockStorage
} }
// NewMockStorage creates a new mock instance // NewMockStorage creates a new mock instance.
func NewMockStorage(ctrl *gomock.Controller) *MockStorage { func NewMockStorage(ctrl *gomock.Controller) *MockStorage {
mock := &MockStorage{ctrl: ctrl} mock := &MockStorage{ctrl: ctrl}
mock.recorder = &MockStorageMockRecorder{mock} mock.recorder = &MockStorageMockRecorder{mock}
return mock return mock
} }
// EXPECT returns an object that allows the caller to indicate expected use // EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockStorage) EXPECT() *MockStorageMockRecorder { func (m *MockStorage) EXPECT() *MockStorageMockRecorder {
return m.recorder return m.recorder
} }
// CreateBucket mocks base method // CreateBucket mocks base method.
func (m *MockStorage) CreateBucket(ctx context.Context, name, location string) error { func (m *MockStorage) CreateBucket(ctx context.Context, name, location string) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateBucket", ctx, name, location) ret := m.ctrl.Call(m, "CreateBucket", ctx, name, location)
@ -46,72 +47,13 @@ func (m *MockStorage) CreateBucket(ctx context.Context, name, location string) e
return ret0 return ret0
} }
// CreateBucket indicates an expected call of CreateBucket // CreateBucket indicates an expected call of CreateBucket.
func (mr *MockStorageMockRecorder) CreateBucket(ctx, name, location interface{}) *gomock.Call { func (mr *MockStorageMockRecorder) CreateBucket(ctx, name, location interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBucket", reflect.TypeOf((*MockStorage)(nil).CreateBucket), ctx, name, location) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBucket", reflect.TypeOf((*MockStorage)(nil).CreateBucket), ctx, name, location)
} }
// RemoveBucket mocks base method // GetObject mocks base method.
func (m *MockStorage) RemoveBucket(ctx context.Context, name string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RemoveBucket", ctx, name)
ret0, _ := ret[0].(error)
return ret0
}
// RemoveBucket indicates an expected call of RemoveBucket
func (mr *MockStorageMockRecorder) RemoveBucket(ctx, name interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveBucket", reflect.TypeOf((*MockStorage)(nil).RemoveBucket), ctx, name)
}
// ListBuckets mocks base method
func (m *MockStorage) ListBuckets(ctx context.Context) ([]*domain.BucketInfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListBuckets", ctx)
ret0, _ := ret[0].([]*domain.BucketInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ListBuckets indicates an expected call of ListBuckets
func (mr *MockStorageMockRecorder) ListBuckets(ctx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBuckets", reflect.TypeOf((*MockStorage)(nil).ListBuckets), ctx)
}
// PutObject mocks base method
func (m *MockStorage) PutObject(ctx context.Context, bucketName, objectName, contentType string, object io.Reader, objectSize int64, createBucketIfNotExisting bool) (*domain.AssetInfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PutObject", ctx, bucketName, objectName, contentType, object, objectSize, createBucketIfNotExisting)
ret0, _ := ret[0].(*domain.AssetInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PutObject indicates an expected call of PutObject
func (mr *MockStorageMockRecorder) PutObject(ctx, bucketName, objectName, contentType, object, objectSize, createBucketIfNotExisting interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutObject", reflect.TypeOf((*MockStorage)(nil).PutObject), ctx, bucketName, objectName, contentType, object, objectSize, createBucketIfNotExisting)
}
// GetObjectInfo mocks base method
func (m *MockStorage) GetObjectInfo(ctx context.Context, bucketName, objectName string) (*domain.AssetInfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetObjectInfo", ctx, bucketName, objectName)
ret0, _ := ret[0].(*domain.AssetInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetObjectInfo indicates an expected call of GetObjectInfo
func (mr *MockStorageMockRecorder) GetObjectInfo(ctx, bucketName, objectName interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectInfo", reflect.TypeOf((*MockStorage)(nil).GetObjectInfo), ctx, bucketName, objectName)
}
// GetObject mocks base method
func (m *MockStorage) GetObject(ctx context.Context, bucketName, objectName string) (io.Reader, func() (*domain.AssetInfo, error), error) { func (m *MockStorage) GetObject(ctx context.Context, bucketName, objectName string) (io.Reader, func() (*domain.AssetInfo, error), error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetObject", ctx, bucketName, objectName) ret := m.ctrl.Call(m, "GetObject", ctx, bucketName, objectName)
@ -121,28 +63,28 @@ func (m *MockStorage) GetObject(ctx context.Context, bucketName, objectName stri
return ret0, ret1, ret2 return ret0, ret1, ret2
} }
// GetObject indicates an expected call of GetObject // GetObject indicates an expected call of GetObject.
func (mr *MockStorageMockRecorder) GetObject(ctx, bucketName, objectName interface{}) *gomock.Call { func (mr *MockStorageMockRecorder) GetObject(ctx, bucketName, objectName interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObject", reflect.TypeOf((*MockStorage)(nil).GetObject), ctx, bucketName, objectName) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObject", reflect.TypeOf((*MockStorage)(nil).GetObject), ctx, bucketName, objectName)
} }
// ListObjectInfos mocks base method // GetObjectInfo mocks base method.
func (m *MockStorage) ListObjectInfos(ctx context.Context, bucketName, prefix string, recursive bool) ([]*domain.AssetInfo, error) { func (m *MockStorage) GetObjectInfo(ctx context.Context, bucketName, objectName string) (*domain.AssetInfo, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListObjectInfos", ctx, bucketName, prefix, recursive) ret := m.ctrl.Call(m, "GetObjectInfo", ctx, bucketName, objectName)
ret0, _ := ret[0].([]*domain.AssetInfo) ret0, _ := ret[0].(*domain.AssetInfo)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// ListObjectInfos indicates an expected call of ListObjectInfos // GetObjectInfo indicates an expected call of GetObjectInfo.
func (mr *MockStorageMockRecorder) ListObjectInfos(ctx, bucketName, prefix, recursive interface{}) *gomock.Call { func (mr *MockStorageMockRecorder) GetObjectInfo(ctx, bucketName, objectName interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectInfos", reflect.TypeOf((*MockStorage)(nil).ListObjectInfos), ctx, bucketName, prefix, recursive) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectInfo", reflect.TypeOf((*MockStorage)(nil).GetObjectInfo), ctx, bucketName, objectName)
} }
// GetObjectPresignedURL mocks base method // GetObjectPresignedURL mocks base method.
func (m *MockStorage) GetObjectPresignedURL(ctx context.Context, bucketName, objectName string, expiration time.Duration) (*url.URL, error) { func (m *MockStorage) GetObjectPresignedURL(ctx context.Context, bucketName, objectName string, expiration time.Duration) (*url.URL, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetObjectPresignedURL", ctx, bucketName, objectName, expiration) ret := m.ctrl.Call(m, "GetObjectPresignedURL", ctx, bucketName, objectName, expiration)
@ -151,13 +93,72 @@ func (m *MockStorage) GetObjectPresignedURL(ctx context.Context, bucketName, obj
return ret0, ret1 return ret0, ret1
} }
// GetObjectPresignedURL indicates an expected call of GetObjectPresignedURL // GetObjectPresignedURL indicates an expected call of GetObjectPresignedURL.
func (mr *MockStorageMockRecorder) GetObjectPresignedURL(ctx, bucketName, objectName, expiration interface{}) *gomock.Call { func (mr *MockStorageMockRecorder) GetObjectPresignedURL(ctx, bucketName, objectName, expiration interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectPresignedURL", reflect.TypeOf((*MockStorage)(nil).GetObjectPresignedURL), ctx, bucketName, objectName, expiration) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetObjectPresignedURL", reflect.TypeOf((*MockStorage)(nil).GetObjectPresignedURL), ctx, bucketName, objectName, expiration)
} }
// RemoveObject mocks base method // ListBuckets mocks base method.
func (m *MockStorage) ListBuckets(ctx context.Context) ([]*domain.BucketInfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListBuckets", ctx)
ret0, _ := ret[0].([]*domain.BucketInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ListBuckets indicates an expected call of ListBuckets.
func (mr *MockStorageMockRecorder) ListBuckets(ctx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBuckets", reflect.TypeOf((*MockStorage)(nil).ListBuckets), ctx)
}
// ListObjectInfos mocks base method.
func (m *MockStorage) ListObjectInfos(ctx context.Context, bucketName, prefix string, recursive bool) ([]*domain.AssetInfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListObjectInfos", ctx, bucketName, prefix, recursive)
ret0, _ := ret[0].([]*domain.AssetInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ListObjectInfos indicates an expected call of ListObjectInfos.
func (mr *MockStorageMockRecorder) ListObjectInfos(ctx, bucketName, prefix, recursive interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectInfos", reflect.TypeOf((*MockStorage)(nil).ListObjectInfos), ctx, bucketName, prefix, recursive)
}
// PutObject mocks base method.
func (m *MockStorage) PutObject(ctx context.Context, bucketName, objectName, contentType string, object io.Reader, objectSize int64, createBucketIfNotExisting bool) (*domain.AssetInfo, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PutObject", ctx, bucketName, objectName, contentType, object, objectSize, createBucketIfNotExisting)
ret0, _ := ret[0].(*domain.AssetInfo)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PutObject indicates an expected call of PutObject.
func (mr *MockStorageMockRecorder) PutObject(ctx, bucketName, objectName, contentType, object, objectSize, createBucketIfNotExisting interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutObject", reflect.TypeOf((*MockStorage)(nil).PutObject), ctx, bucketName, objectName, contentType, object, objectSize, createBucketIfNotExisting)
}
// RemoveBucket mocks base method.
func (m *MockStorage) RemoveBucket(ctx context.Context, name string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RemoveBucket", ctx, name)
ret0, _ := ret[0].(error)
return ret0
}
// RemoveBucket indicates an expected call of RemoveBucket.
func (mr *MockStorageMockRecorder) RemoveBucket(ctx, name interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveBucket", reflect.TypeOf((*MockStorage)(nil).RemoveBucket), ctx, name)
}
// RemoveObject mocks base method.
func (m *MockStorage) RemoveObject(ctx context.Context, bucketName, objectName string) error { func (m *MockStorage) RemoveObject(ctx context.Context, bucketName, objectName string) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RemoveObject", ctx, bucketName, objectName) ret := m.ctrl.Call(m, "RemoveObject", ctx, bucketName, objectName)
@ -165,36 +166,50 @@ func (m *MockStorage) RemoveObject(ctx context.Context, bucketName, objectName s
return ret0 return ret0
} }
// RemoveObject indicates an expected call of RemoveObject // RemoveObject indicates an expected call of RemoveObject.
func (mr *MockStorageMockRecorder) RemoveObject(ctx, bucketName, objectName interface{}) *gomock.Call { func (mr *MockStorageMockRecorder) RemoveObject(ctx, bucketName, objectName interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveObject", reflect.TypeOf((*MockStorage)(nil).RemoveObject), ctx, bucketName, objectName) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveObject", reflect.TypeOf((*MockStorage)(nil).RemoveObject), ctx, bucketName, objectName)
} }
// MockConfig is a mock of Config interface // RemoveObjects mocks base method.
func (m *MockStorage) RemoveObjects(ctx context.Context, bucketName, path string, recursive bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RemoveObjects", ctx, bucketName, path, recursive)
ret0, _ := ret[0].(error)
return ret0
}
// RemoveObjects indicates an expected call of RemoveObjects.
func (mr *MockStorageMockRecorder) RemoveObjects(ctx, bucketName, path, recursive interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveObjects", reflect.TypeOf((*MockStorage)(nil).RemoveObjects), ctx, bucketName, path, recursive)
}
// MockConfig is a mock of Config interface.
type MockConfig struct { type MockConfig struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockConfigMockRecorder recorder *MockConfigMockRecorder
} }
// MockConfigMockRecorder is the mock recorder for MockConfig // MockConfigMockRecorder is the mock recorder for MockConfig.
type MockConfigMockRecorder struct { type MockConfigMockRecorder struct {
mock *MockConfig mock *MockConfig
} }
// NewMockConfig creates a new mock instance // NewMockConfig creates a new mock instance.
func NewMockConfig(ctrl *gomock.Controller) *MockConfig { func NewMockConfig(ctrl *gomock.Controller) *MockConfig {
mock := &MockConfig{ctrl: ctrl} mock := &MockConfig{ctrl: ctrl}
mock.recorder = &MockConfigMockRecorder{mock} mock.recorder = &MockConfigMockRecorder{mock}
return mock return mock
} }
// EXPECT returns an object that allows the caller to indicate expected use // EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockConfig) EXPECT() *MockConfigMockRecorder { func (m *MockConfig) EXPECT() *MockConfigMockRecorder {
return m.recorder return m.recorder
} }
// NewStorage mocks base method // NewStorage mocks base method.
func (m *MockConfig) NewStorage() (static.Storage, error) { func (m *MockConfig) NewStorage() (static.Storage, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NewStorage") ret := m.ctrl.Call(m, "NewStorage")
@ -203,7 +218,7 @@ func (m *MockConfig) NewStorage() (static.Storage, error) {
return ret0, ret1 return ret0, ret1
} }
// NewStorage indicates an expected call of NewStorage // NewStorage indicates an expected call of NewStorage.
func (mr *MockConfigMockRecorder) NewStorage() *gomock.Call { func (mr *MockConfigMockRecorder) NewStorage() *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewStorage", reflect.TypeOf((*MockConfig)(nil).NewStorage)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewStorage", reflect.TypeOf((*MockConfig)(nil).NewStorage))

View File

@ -33,6 +33,13 @@ func (m *MockStorage) ExpectRemoveObjectNoError() *MockStorage {
return m return m
} }
func (m *MockStorage) ExpectRemoveObjectsNoError() *MockStorage {
m.EXPECT().
RemoveObjects(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
Return(nil)
return m
}
func (m *MockStorage) ExpectRemoveObjectError() *MockStorage { func (m *MockStorage) ExpectRemoveObjectError() *MockStorage {
m.EXPECT(). m.EXPECT().
RemoveObject(gomock.Any(), gomock.Any(), gomock.Any()). RemoveObject(gomock.Any(), gomock.Any(), gomock.Any()).

View File

@ -15,6 +15,7 @@ type Config struct {
SSL bool SSL bool
Location string Location string
BucketPrefix string BucketPrefix string
MultiDelete bool
} }
func (c *Config) NewStorage() (static.Storage, error) { func (c *Config) NewStorage() (static.Storage, error) {
@ -30,5 +31,6 @@ func (c *Config) NewStorage() (static.Storage, error) {
Client: minioClient, Client: minioClient,
Location: c.Location, Location: c.Location,
BucketPrefix: c.BucketPrefix, BucketPrefix: c.BucketPrefix,
MultiDelete: c.MultiDelete,
}, nil }, nil
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/caos/logging" "github.com/caos/logging"
"github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7"
"golang.org/x/sync/errgroup"
"github.com/caos/zitadel/internal/domain" "github.com/caos/zitadel/internal/domain"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
@ -19,6 +20,7 @@ type Minio struct {
Client *minio.Client Client *minio.Client
Location string Location string
BucketPrefix string BucketPrefix string
MultiDelete bool
} }
func (m *Minio) CreateBucket(ctx context.Context, name, location string) error { func (m *Minio) CreateBucket(ctx context.Context, name, location string) error {
@ -128,15 +130,11 @@ func (m *Minio) GetObjectPresignedURL(ctx context.Context, bucketName, objectNam
func (m *Minio) ListObjectInfos(ctx context.Context, bucketName, prefix string, recursive bool) ([]*domain.AssetInfo, error) { func (m *Minio) ListObjectInfos(ctx context.Context, bucketName, prefix string, recursive bool) ([]*domain.AssetInfo, error) {
bucketName = m.prefixBucketName(bucketName) bucketName = m.prefixBucketName(bucketName)
ctx, cancel := context.WithCancel(ctx)
defer cancel()
objectCh := m.Client.ListObjects(ctx, bucketName, minio.ListObjectsOptions{
Prefix: prefix,
Recursive: recursive,
})
assetInfos := make([]*domain.AssetInfo, 0) assetInfos := make([]*domain.AssetInfo, 0)
for object := range objectCh {
objects, cancel := m.listObjects(ctx, bucketName, prefix, recursive)
defer cancel()
for object := range objects {
if object.Err != nil { if object.Err != nil {
logging.LogWithFields("MINIO-wC8sd", "bucket-name", bucketName, "prefix", prefix).WithError(object.Err).Debug("unable to get object") logging.LogWithFields("MINIO-wC8sd", "bucket-name", bucketName, "prefix", prefix).WithError(object.Err).Debug("unable to get object")
return nil, caos_errs.ThrowInternal(object.Err, "MINIO-1m09S", "Errors.Assets.Object.ListFailed") return nil, caos_errs.ThrowInternal(object.Err, "MINIO-1m09S", "Errors.Assets.Object.ListFailed")
@ -155,6 +153,47 @@ func (m *Minio) RemoveObject(ctx context.Context, bucketName, objectName string)
return nil return nil
} }
func (m *Minio) RemoveObjects(ctx context.Context, bucketName, path string, recursive bool) error {
bucketName = m.prefixBucketName(bucketName)
objectsCh := make(chan minio.ObjectInfo)
g := new(errgroup.Group)
g.Go(func() error {
defer close(objectsCh)
objects, cancel := m.listObjects(ctx, bucketName, path, recursive)
for object := range objects {
if object.Err != nil {
cancel()
return caos_errs.ThrowInternal(object.Err, "MINIO-WQF32", "Errors.Assets.Object.ListFailed")
}
objectsCh <- object
}
return nil
})
if m.MultiDelete {
for objError := range m.Client.RemoveObjects(ctx, bucketName, objectsCh, minio.RemoveObjectsOptions{GovernanceBypass: true}) {
return caos_errs.ThrowInternal(objError.Err, "MINIO-Sfdgr", "Errors.Assets.Object.RemoveFailed")
}
return g.Wait()
}
for objectInfo := range objectsCh {
if err := m.Client.RemoveObject(ctx, bucketName, objectInfo.Key, minio.RemoveObjectOptions{GovernanceBypass: true}); err != nil {
return caos_errs.ThrowInternal(err, "MINIO-GVgew", "Errors.Assets.Object.RemoveFailed")
}
}
return g.Wait()
}
func (m *Minio) listObjects(ctx context.Context, bucketName, prefix string, recursive bool) (<-chan minio.ObjectInfo, context.CancelFunc) {
ctxCancel, cancel := context.WithCancel(ctx)
return m.Client.ListObjects(ctxCancel, bucketName, minio.ListObjectsOptions{
Prefix: prefix,
Recursive: recursive,
}), cancel
}
func (m *Minio) objectToAssetInfo(bucketName string, object minio.ObjectInfo) *domain.AssetInfo { func (m *Minio) objectToAssetInfo(bucketName string, object minio.ObjectInfo) *domain.AssetInfo {
return &domain.AssetInfo{ return &domain.AssetInfo{
Bucket: bucketName, Bucket: bucketName,

View File

@ -19,6 +19,7 @@ type Storage interface {
ListObjectInfos(ctx context.Context, bucketName, prefix string, recursive bool) ([]*domain.AssetInfo, error) ListObjectInfos(ctx context.Context, bucketName, prefix string, recursive bool) ([]*domain.AssetInfo, error)
GetObjectPresignedURL(ctx context.Context, bucketName, objectName string, expiration time.Duration) (*url.URL, error) GetObjectPresignedURL(ctx context.Context, bucketName, objectName string, expiration time.Duration) (*url.URL, error)
RemoveObject(ctx context.Context, bucketName, objectName string) error RemoveObject(ctx context.Context, bucketName, objectName string) error
RemoveObjects(ctx context.Context, bucketName, path string, recursive bool) error
} }
type Config interface { type Config interface {
NewStorage() (Storage, error) NewStorage() (Storage, error)

View File

@ -3,6 +3,7 @@
--zitadel-color-background: var(--zitadel-color-background-500); --zitadel-color-background: var(--zitadel-color-background-500);
--zitadel-color-secondary: var(--zitadel-color-secondary-500); --zitadel-color-secondary: var(--zitadel-color-secondary-500);
--zitadel-color-warn: var(--zitadel-color-warn-500); --zitadel-color-warn: var(--zitadel-color-warn-500);
--zitadel-color-text: var(--zitadel-color-text-500);
--zitadel-color-primary-50: #eaedfa; --zitadel-color-primary-50: #eaedfa;
--zitadel-color-primary-100: #ccd2f2; --zitadel-color-primary-100: #ccd2f2;
@ -42,7 +43,18 @@
--zitadel-font-family: 'Lato'; --zitadel-font-family: 'Lato';
--zitadel-color-background-500: var(--zitadel-color-grey-50); --zitadel-color-background-50: rgb(255, 255, 255);
--zitadel-color-background-100: rgb(255, 255, 255);
--zitadel-color-background-200: rgb(255, 255, 255);
--zitadel-color-background-300: rgb(255, 255, 255);
--zitadel-color-background-400: rgb(255, 255, 255);
--zitadel-color-background-500: rgb(250, 250, 250);
--zitadel-color-background-600: rgb(222, 222, 222);
--zitadel-color-background-700: rgb(195, 195, 194);
--zitadel-color-background-800: rgb(168, 168, 168);
--zitadel-color-background-900: rgb(142, 142, 142);
--zitadel-color-background-contrast: rgb(0, 0, 0);
--zitadel-color-footer-line: #e3e8ee; --zitadel-color-footer-line: #e3e8ee;
--zitadel-color-input-background: #fafafa50; --zitadel-color-input-background: #fafafa50;
@ -50,7 +62,17 @@
--zitadel-color-input-border-hover: #1a1b1b; --zitadel-color-input-border-hover: #1a1b1b;
--zitadel-color-input-placeholder: var(--zitadel-color-grey-600); --zitadel-color-input-placeholder: var(--zitadel-color-grey-600);
--zitadel-color-text: rgba(0, 0, 0, 0.87); --zitadel-color-font-50: rgb(0, 0, 0);
--zitadel-color-font-100: rgb(0, 0, 0);
--zitadel-color-font-200: rgb(0, 0, 0);
--zitadel-color-font-300: rgb(0, 0, 0);
--zitadel-color-font-400: rgb(0, 0, 0);
--zitadel-color-font-500: rgb(0, 0, 0);
--zitadel-color-font-600: rgb(0, 0, 0);
--zitadel-color-font-700: rgb(0, 0, 0);
--zitadel-color-font-800: rgb(0, 0, 0);
--zitadel-color-font-900: rgb(0, 0, 0);
--zitadel-color-font-contrast: rgb(255, 255, 255);
--zitadel-color-label: var(--zitadel-color-grey-600); --zitadel-color-label: var(--zitadel-color-grey-600);
@ -69,7 +91,6 @@
--zitadel-color-raised-button-background: var(--zitadel-color-white); --zitadel-color-raised-button-background: var(--zitadel-color-white);
--zitadel-color-white: #ffffff;
--zitadel-color-black: #000000; --zitadel-color-black: #000000;
--zitadel-color-grey-50: #fafafa; --zitadel-color-grey-50: #fafafa;
--zitadel-color-grey-100: #f5f5f5; --zitadel-color-grey-100: #f5f5f5;
@ -128,7 +149,18 @@
--zitadel-font-family: 'Lato'; --zitadel-font-family: 'Lato';
--zitadel-color-background-500: var(--zitadel-color-grey-900); --zitadel-color-background-50: rgb(60, 60, 60);
--zitadel-color-background-100: rgb(55, 55, 55);
--zitadel-color-background-200: rgb(49, 49, 49);
--zitadel-color-background-300: rgb(44, 44, 44);
--zitadel-color-background-400: rgb(36, 36, 36);
--zitadel-color-background-500: rgb(33, 33, 33);
--zitadel-color-background-600: rgb(30, 30, 30);
--zitadel-color-background-700: rgb(28, 28, 28);
--zitadel-color-background-800: rgb(25, 25, 25);
--zitadel-color-background-900: rgb(23, 23, 23);
--zitadel-color-background-contrast: rgb(255, 255, 255);
--zitadel-color-footer-line: #303131; --zitadel-color-footer-line: #303131;
--zitadel-color-input-background: rgba(0, 0, 0, 0.2); --zitadel-color-input-background: rgba(0, 0, 0, 0.2);
@ -136,7 +168,17 @@
--zitadel-color-input-border-hover: #aeafb1; --zitadel-color-input-border-hover: #aeafb1;
--zitadel-color-input-placeholder: var(--zitadel-color-grey-600); --zitadel-color-input-placeholder: var(--zitadel-color-grey-600);
--zitadel-color-text: var(--zitadel-color-white); --zitadel-color-text-50: rgb(255, 255, 255);
--zitadel-color-text-100: rgb(255, 255, 255);
--zitadel-color-text-200: rgb(255, 255, 255);
--zitadel-color-text-300: rgb(255, 255, 255);
--zitadel-color-text-400: rgb(255, 255, 255);
--zitadel-color-text-500: rgb(255, 255, 255);
--zitadel-color-text-600: rgb(221, 222, 223);
--zitadel-color-text-700: rgb(194, 195, 195);
--zitadel-color-text-800: rgb(167, 168, 169);
--zitadel-color-text-900: rgb(141, 142, 143);
--zitadel-color-text-contrast: rgb(0, 0, 0);
--zitadel-color-label: var(--zitadel-color-grey-600); --zitadel-color-label: var(--zitadel-color-grey-600);
--zitadel-color-account-selector-hover: rgba(255, 255, 255, 0.02); --zitadel-color-account-selector-hover: rgba(255, 255, 255, 0.02);
@ -162,4 +204,4 @@
--zitadel-color-google-text: #8b8d8d; --zitadel-color-google-text: #8b8d8d;
--zitadel-color-google-background: #ffffff; --zitadel-color-google-background: #ffffff;
} }

View File

@ -4,6 +4,7 @@
--zitadel-color-background: var(--zitadel-color-background-500); --zitadel-color-background: var(--zitadel-color-background-500);
--zitadel-color-secondary: var(--zitadel-color-secondary-500); --zitadel-color-secondary: var(--zitadel-color-secondary-500);
--zitadel-color-warn: var(--zitadel-color-warn-500); --zitadel-color-warn: var(--zitadel-color-warn-500);
--zitadel-color-text: var(--zitadel-color-text-500);
--zitadel-color-primary-50: #eaedfa; --zitadel-color-primary-50: #eaedfa;
--zitadel-color-primary-100: #ccd2f2; --zitadel-color-primary-100: #ccd2f2;
--zitadel-color-primary-200: #aab4ea; --zitadel-color-primary-200: #aab4ea;
@ -38,13 +39,33 @@
--zitadel-color-warn-800: #c62828; --zitadel-color-warn-800: #c62828;
--zitadel-color-warn-900: #b71c1c; --zitadel-color-warn-900: #b71c1c;
--zitadel-font-family: "Lato"; --zitadel-font-family: "Lato";
--zitadel-color-background-500: var(--zitadel-color-grey-50); --zitadel-color-background-50: rgb(255, 255, 255);
--zitadel-color-background-100: rgb(255, 255, 255);
--zitadel-color-background-200: rgb(255, 255, 255);
--zitadel-color-background-300: rgb(255, 255, 255);
--zitadel-color-background-400: rgb(255, 255, 255);
--zitadel-color-background-500: rgb(250, 250, 250);
--zitadel-color-background-600: rgb(222, 222, 222);
--zitadel-color-background-700: rgb(195, 195, 194);
--zitadel-color-background-800: rgb(168, 168, 168);
--zitadel-color-background-900: rgb(142, 142, 142);
--zitadel-color-background-contrast: rgb(0, 0, 0);
--zitadel-color-footer-line: #e3e8ee; --zitadel-color-footer-line: #e3e8ee;
--zitadel-color-input-background: #fafafa50; --zitadel-color-input-background: #fafafa50;
--zitadel-color-input-border: #00000040; --zitadel-color-input-border: #00000040;
--zitadel-color-input-border-hover: #1a1b1b; --zitadel-color-input-border-hover: #1a1b1b;
--zitadel-color-input-placeholder: var(--zitadel-color-grey-600); --zitadel-color-input-placeholder: var(--zitadel-color-grey-600);
--zitadel-color-text: rgba(0, 0, 0, 0.87); --zitadel-color-font-50: rgb(0, 0, 0);
--zitadel-color-font-100: rgb(0, 0, 0);
--zitadel-color-font-200: rgb(0, 0, 0);
--zitadel-color-font-300: rgb(0, 0, 0);
--zitadel-color-font-400: rgb(0, 0, 0);
--zitadel-color-font-500: rgb(0, 0, 0);
--zitadel-color-font-600: rgb(0, 0, 0);
--zitadel-color-font-700: rgb(0, 0, 0);
--zitadel-color-font-800: rgb(0, 0, 0);
--zitadel-color-font-900: rgb(0, 0, 0);
--zitadel-color-font-contrast: rgb(255, 255, 255);
--zitadel-color-label: var(--zitadel-color-grey-600); --zitadel-color-label: var(--zitadel-color-grey-600);
--zitadel-color-account-selector-hover: rgba(0, 0, 0, 0.02); --zitadel-color-account-selector-hover: rgba(0, 0, 0, 0.02);
--zitadel-color-account-selector-active: rgba(0, 0, 0, 0.05); --zitadel-color-account-selector-active: rgba(0, 0, 0, 0.05);
@ -56,7 +77,6 @@
--zitadel-color-button-selected-background: var(--zitadel-color-grey-900); --zitadel-color-button-selected-background: var(--zitadel-color-grey-900);
--zitadel-color-button-disabled-selected-background: var(--zitadel-color-grey-800); --zitadel-color-button-disabled-selected-background: var(--zitadel-color-grey-800);
--zitadel-color-raised-button-background: var(--zitadel-color-white); --zitadel-color-raised-button-background: var(--zitadel-color-white);
--zitadel-color-white: #ffffff;
--zitadel-color-black: #000000; --zitadel-color-black: #000000;
--zitadel-color-grey-50: #fafafa; --zitadel-color-grey-50: #fafafa;
--zitadel-color-grey-100: #f5f5f5; --zitadel-color-grey-100: #f5f5f5;
@ -108,13 +128,33 @@
--zitadel-color-warn-800: #c62828; --zitadel-color-warn-800: #c62828;
--zitadel-color-warn-900: #b71c1c; --zitadel-color-warn-900: #b71c1c;
--zitadel-font-family: "Lato"; --zitadel-font-family: "Lato";
--zitadel-color-background-500: var(--zitadel-color-grey-900); --zitadel-color-background-50: rgb(60, 60, 60);
--zitadel-color-background-100: rgb(55, 55, 55);
--zitadel-color-background-200: rgb(49, 49, 49);
--zitadel-color-background-300: rgb(44, 44, 44);
--zitadel-color-background-400: rgb(36, 36, 36);
--zitadel-color-background-500: rgb(33, 33, 33);
--zitadel-color-background-600: rgb(30, 30, 30);
--zitadel-color-background-700: rgb(28, 28, 28);
--zitadel-color-background-800: rgb(25, 25, 25);
--zitadel-color-background-900: rgb(23, 23, 23);
--zitadel-color-background-contrast: rgb(255, 255, 255);
--zitadel-color-footer-line: #303131; --zitadel-color-footer-line: #303131;
--zitadel-color-input-background: rgba(0, 0, 0, 0.2); --zitadel-color-input-background: rgba(0, 0, 0, 0.2);
--zitadel-color-input-border: #403e3e; --zitadel-color-input-border: #403e3e;
--zitadel-color-input-border-hover: #aeafb1; --zitadel-color-input-border-hover: #aeafb1;
--zitadel-color-input-placeholder: var(--zitadel-color-grey-600); --zitadel-color-input-placeholder: var(--zitadel-color-grey-600);
--zitadel-color-text: var(--zitadel-color-white); --zitadel-color-text-50: rgb(255, 255, 255);
--zitadel-color-text-100: rgb(255, 255, 255);
--zitadel-color-text-200: rgb(255, 255, 255);
--zitadel-color-text-300: rgb(255, 255, 255);
--zitadel-color-text-400: rgb(255, 255, 255);
--zitadel-color-text-500: rgb(255, 255, 255);
--zitadel-color-text-600: rgb(221, 222, 223);
--zitadel-color-text-700: rgb(194, 195, 195);
--zitadel-color-text-800: rgb(167, 168, 169);
--zitadel-color-text-900: rgb(141, 142, 143);
--zitadel-color-text-contrast: rgb(0, 0, 0);
--zitadel-color-label: var(--zitadel-color-grey-600); --zitadel-color-label: var(--zitadel-color-grey-600);
--zitadel-color-account-selector-hover: rgba(255, 255, 255, 0.02); --zitadel-color-account-selector-hover: rgba(255, 255, 255, 0.02);
--zitadel-color-account-selector-active: rgba(255, 255, 255, 0.05); --zitadel-color-account-selector-active: rgba(255, 255, 255, 0.05);

File diff suppressed because one or more lines are too long

View File

@ -41,6 +41,7 @@ type AssetStorage struct {
SSL bool `yaml:"ssl,omitempty"` SSL bool `yaml:"ssl,omitempty"`
Location string `yaml:"location,omitempty"` Location string `yaml:"location,omitempty"`
BucketPrefix string `yaml:"bucketPrefix,omitempty"` BucketPrefix string `yaml:"bucketPrefix,omitempty"`
MultiDelete bool `yaml:"multiDelete,omitempty"`
} }
type DNS struct { type DNS struct {

View File

@ -107,6 +107,7 @@ func literalsConfigMap(
literalsConfigMap["ZITADEL_ASSET_STORAGE_SSL"] = strconv.FormatBool(desired.AssetStorage.SSL) literalsConfigMap["ZITADEL_ASSET_STORAGE_SSL"] = strconv.FormatBool(desired.AssetStorage.SSL)
literalsConfigMap["ZITADEL_ASSET_STORAGE_LOCATION"] = desired.AssetStorage.Location literalsConfigMap["ZITADEL_ASSET_STORAGE_LOCATION"] = desired.AssetStorage.Location
literalsConfigMap["ZITADEL_ASSET_STORAGE_BUCKET_PREFIX"] = desired.AssetStorage.BucketPrefix literalsConfigMap["ZITADEL_ASSET_STORAGE_BUCKET_PREFIX"] = desired.AssetStorage.BucketPrefix
literalsConfigMap["ZITADEL_ASSET_STORAGE_MULTI_DELETE"] = strconv.FormatBool(desired.AssetStorage.MultiDelete)
} }
} }

View File

@ -294,6 +294,7 @@ func TestConfiguration_LiteralsConfigMap(t *testing.T) {
"ZITADEL_ASSET_STORAGE_SSL": "false", "ZITADEL_ASSET_STORAGE_SSL": "false",
"ZITADEL_ASSET_STORAGE_LOCATION": "", "ZITADEL_ASSET_STORAGE_LOCATION": "",
"ZITADEL_ASSET_STORAGE_BUCKET_PREFIX": "", "ZITADEL_ASSET_STORAGE_BUCKET_PREFIX": "",
"ZITADEL_ASSET_STORAGE_MULTI_DELETE": "false",
} }
literals := literalsConfigMap(desiredEmpty, users, certPath, secretPath, googleSA, zitadelKeyPath, queried) literals := literalsConfigMap(desiredEmpty, users, certPath, secretPath, googleSA, zitadelKeyPath, queried)
@ -378,6 +379,7 @@ func TestConfiguration_LiteralsConfigMapFull(t *testing.T) {
"ZITADEL_ASSET_STORAGE_SSL": "true", "ZITADEL_ASSET_STORAGE_SSL": "true",
"ZITADEL_ASSET_STORAGE_LOCATION": "location", "ZITADEL_ASSET_STORAGE_LOCATION": "location",
"ZITADEL_ASSET_STORAGE_BUCKET_PREFIX": "bucketprefix", "ZITADEL_ASSET_STORAGE_BUCKET_PREFIX": "bucketprefix",
"ZITADEL_ASSET_STORAGE_MULTI_DELETE": "false",
} }
literals := literalsConfigMap(desiredFull, users, certPath, secretPath, googleSA, zitadelKeyPath, queried) literals := literalsConfigMap(desiredFull, users, certPath, secretPath, googleSA, zitadelKeyPath, queried)