eintopf.info@v0.13.16/service/revent/authorizer.go (about) 1 // Copyright (C) 2022 The Eintopf authors 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <https://www.gnu.org/licenses/>. 15 16 package revent 17 18 import ( 19 "context" 20 "fmt" 21 "time" 22 23 "eintopf.info/internal/crud" 24 "eintopf.info/service/auth" 25 "eintopf.info/service/event" 26 ) 27 28 // authorizer wraps a Storer. It checks the authorization before propagating 29 // the call to the wrapped storer. 30 type authorizer struct { 31 service Service 32 } 33 34 // NewAuthorizer returns a new role manager limiting access to the provided 35 // store. 36 func NewAuthorizer(service Service) Service { 37 return &authorizer{service} 38 } 39 40 // Create can be called by all users. 41 func (r *authorizer) Create(ctx context.Context, newRepeatingEvent *NewRepeatingEvent) (*RepeatingEvent, error) { 42 _, err := auth.UserIDFromContext(ctx) 43 if err != nil { 44 return nil, auth.ErrUnauthorized 45 } 46 return r.service.Create(ctx, newRepeatingEvent) 47 } 48 49 // Update can be called by an admin user or the repeatingEvent author. 50 func (r *authorizer) Update(ctx context.Context, repeatingEvent *RepeatingEvent) (*RepeatingEvent, error) { 51 if err := r.adminOrOwned(ctx, repeatingEvent.ID); err != nil { 52 return nil, err 53 } 54 oldRepeatingEvent, err := r.service.FindByID(ctx, repeatingEvent.ID) 55 if err != nil { 56 return nil, err 57 } 58 if oldRepeatingEvent == nil { 59 return nil, fmt.Errorf("cant find repeatingEvent with id: %s", repeatingEvent.ID) 60 } 61 if oldRepeatingEvent.Deactivated != repeatingEvent.Deactivated { 62 role, err := auth.RoleFromContext(ctx) 63 if err != nil { 64 return nil, auth.ErrUnauthorized 65 } 66 if role == auth.RoleNormal { 67 return nil, auth.ErrUnauthorized 68 } 69 } 70 return r.service.Update(ctx, repeatingEvent) 71 } 72 73 // Delete can be called by an admin user or the repeatingEvent author. 74 func (r *authorizer) Delete(ctx context.Context, id string) error { 75 if err := r.adminOrOwned(ctx, id); err != nil { 76 return err 77 } 78 return r.service.Delete(ctx, id) 79 } 80 81 // FindByID can be called by everyone. 82 func (r *authorizer) FindByID(ctx context.Context, id string) (*RepeatingEvent, error) { 83 return r.service.FindByID(ctx, id) 84 } 85 86 // Find can be called by everyone. 87 func (r *authorizer) Find(ctx context.Context, params *crud.FindParams[FindFilters]) ([]*RepeatingEvent, int, error) { 88 return r.service.Find(ctx, params) 89 } 90 91 func (a *authorizer) GenerateEvents(ctx context.Context, id string, start, end time.Time) ([]*event.Event, error) { 92 if err := a.adminOrOwned(ctx, id); err != nil { 93 return nil, err 94 } 95 return a.service.GenerateEvents(ctx, id, start, end) 96 } 97 98 func (r *authorizer) adminOrOwned(ctx context.Context, repeatingEventID string) error { 99 role, err := auth.RoleFromContext(ctx) 100 if err != nil { 101 return auth.ErrUnauthorized 102 } 103 if role == auth.RoleAdmin || role == auth.RoleInternal { 104 return nil 105 } 106 107 repeatingEvent, err := r.FindByID(ctx, repeatingEventID) 108 if err != nil { 109 return err 110 } 111 userID, err := auth.UserIDFromContext(ctx) 112 if err != nil { 113 return auth.ErrUnauthorized 114 } 115 if !repeatingEvent.IsOwned(userID) { 116 return auth.ErrUnauthorized 117 } 118 119 return nil 120 }