From 7cae658211d7ae9bbfacf176f5d45ee3321a4b57 Mon Sep 17 00:00:00 2001 From: jensilo <k@jensheise.com> Date: Fri, 15 Dec 2023 15:49:16 +0100 Subject: [PATCH] fix visibility bug with templates and template sets --- src/app/eiffel/service.go | 10 ++++++++++ src/app/eiffel/web.go | 3 ++- src/app/template/template.go | 33 +++++++++++++++++++-------------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/app/eiffel/service.go b/src/app/eiffel/service.go index f739706..0164c37 100644 --- a/src/app/eiffel/service.go +++ b/src/app/eiffel/service.go @@ -55,6 +55,7 @@ func TemplateIntoBasicTemplate(t *template.Template, validator validation.V, rul // TemplateFormData struct. If the template or variant could not be found, an error is returned. // However, using the defaultFirstVariant flag, the first variant will be used if no variant was specified and no // error will be returned. TemplateFormFromRequest will also parse and validate the template. +// TemplateFormFromRequest will return an error if the user is not permitted to access the template. // // Returned errors from TemplateFormFromRequest are safe to display to the user. func TemplateFormFromRequest( @@ -76,6 +77,15 @@ func TemplateFormFromRequest( return TemplateFormData{}, ErrTemplateNotFound } + usr, err := user.CtxUser(ctx) + if err != nil { + return TemplateFormData{}, ErrTemplateNotFound + } + + if tmpl.CreatedBy != usr.ID { + return TemplateFormData{}, ErrTemplateNotFound + } + bt, err := TemplateIntoBasicTemplate(tmpl, validator, ruleParsers) if err != nil { return TemplateFormData{}, err diff --git a/src/app/eiffel/web.go b/src/app/eiffel/web.go index fba9462..e3e2a72 100644 --- a/src/app/eiffel/web.go +++ b/src/app/eiffel/web.go @@ -202,7 +202,8 @@ func searchTemplate(appCtx *hctx.AppCtx, webCtx *web.Ctx) http.Handler { ) } - templates, err := templateRepository.FindByQueryForType(io.Context(), query, BasicTemplateType) + ctx := io.Context() + templates, err := templateRepository.FindByQueryForTypeAndUser(ctx, query, BasicTemplateType, user.MustCtxUser(ctx)) if err != nil && !errors.Is(err, persistence.ErrNotFound) { return io.InlineError(web.ErrInternal, err) } diff --git a/src/app/template/template.go b/src/app/template/template.go index 8ea099b..4104720 100644 --- a/src/app/template/template.go +++ b/src/app/template/template.go @@ -6,6 +6,7 @@ import ( "errors" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" + "github.com/org-harmony/harmony/src/app/user" "github.com/org-harmony/harmony/src/core/persistence" "strings" "time" @@ -31,15 +32,17 @@ var ( // Each template belongs to a template set. Templates are versioned and the information about the template should always match the template's config JSON. // Actually, Type, Name and Version are redundant, but they are used for easier querying. type Template struct { - ID uuid.UUID - TemplateSet uuid.UUID - Type string - Name string - Version string - Config string - CreatedBy uuid.UUID - CreatedAt time.Time - UpdatedAt *time.Time + ID uuid.UUID + TemplateSet uuid.UUID + Type string + Name string + Version string + Config string + CreatedBy uuid.UUID + CreatedAt time.Time + UpdatedAt *time.Time + // TemplateSetElem is the template set that the template belongs to joined onto the template. + // Don't expect this to be filled unless the origin of the template object explicitly states that it is filled. TemplateSetElem *Set } @@ -110,11 +113,12 @@ type PGSetRepository struct { type Repository interface { persistence.Repository - // FindByQueryForType finds all templates by a query for a specified template type. + // FindByQueryForTypeAndUser finds all templates by a query for a specified template type and user. // The query will be searched for in the template's name, version and in the template set's name. // It will join the template.Set onto template.Template and read it into Set.TemplateSetElem. + // The search is limited to the user's templates as templates are private. // It returns persistence.ErrNotFound if no templates could be found and persistence.ErrReadRow for any other error. - FindByQueryForType(ctx context.Context, query string, templateType string) ([]*Template, error) + FindByQueryForTypeAndUser(ctx context.Context, query, templateType string, usr *user.User) ([]*Template, error) // FindByID finds a template by its id. // It returns persistence.ErrNotFound if the template could not be found and persistence.ErrReadRow for any other error. FindByID(ctx context.Context, id uuid.UUID) (*Template, error) @@ -227,18 +231,19 @@ func (r *PGSetRepository) RepositoryName() string { return SetRepositoryName } -// FindByQueryForType finds all templates by a query for a specified template type. +// FindByQueryForTypeAndUser finds all templates by a query for a specified template type and user. // It returns persistence.ErrNotFound if no templates could be found and persistence.ErrReadRow for any other error. -func (r *PGRepository) FindByQueryForType(ctx context.Context, query string, templateType string) ([]*Template, error) { +func (r *PGRepository) FindByQueryForTypeAndUser(ctx context.Context, query, templateType string, usr *user.User) ([]*Template, error) { rows, err := r.db.Query( ctx, `SELECT templates.id, templates.template_set, templates.type, templates.name, templates.version, templates.config, templates.created_by, templates.created_at, templates.updated_at, template_sets.name, template_sets.version, template_sets.description, template_sets.created_by, template_sets.created_at, template_sets.updated_at FROM templates LEFT JOIN template_sets ON templates.template_set = template_sets.id -WHERE templates.name ILIKE $1 OR templates.version ILIKE $1 OR template_sets.name ILIKE $1 AND templates.type = $2`, +WHERE (templates.name ILIKE $1 OR templates.version ILIKE $1 OR template_sets.name ILIKE $1) AND templates.type = $2 AND templates.created_by = $3`, "%"+query+"%", templateType, + usr.ID, ) if err != nil { return nil, persistence.PGReadErr(err) -- GitLab