Files
sendico/api/server/internal/server/permissionsimp/changepolicies.go
Stephan D 49b86efecb
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
fx build fix
2025-11-08 00:30:29 +01:00

95 lines
3.2 KiB
Go

package permissionsimp
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/tech/sendico/pkg/api/http/response"
"github.com/tech/sendico/pkg/merrors"
"github.com/tech/sendico/pkg/model"
"github.com/tech/sendico/pkg/mservice"
"github.com/tech/sendico/server/interface/api/srequest"
"github.com/tech/sendico/server/interface/api/sresponse"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.uber.org/zap"
)
func (a *PermissionsAPI) changePolicies(r *http.Request, account *model.Account, _ *sresponse.TokenData) http.HandlerFunc {
var req srequest.ChangePolicies
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
a.logger.Warn("Failed to decode role policies change request", zap.Error(err))
return response.BadPayload(a.logger, mservice.Roles, err)
}
if req.Add != nil && req.Remove != nil {
for _, addItem := range *req.Add {
for _, removeItem := range *req.Remove {
if addItem == removeItem {
a.logger.Debug("Duplicate policies found, rejecting policies update request", zap.Any("add", &addItem), zap.Any("remove", &removeItem))
return response.BadRequest(a.logger, a.Name(), "invalid_policies_change_request", "duplicate policies found in 'add' and 'remove' fields")
}
}
}
}
if _, err := a.tf.CreateTransaction().Execute(r.Context(), func(ctx context.Context) (any, error) {
return a.changePoliciesImp(ctx, account, &req)
}); err != nil {
a.logger.Debug("Rolling policies changes back", zap.Error(err))
return response.Auto(a.logger, a.Name(), err)
}
return response.Success(a.logger)
}
func (a *PermissionsAPI) changePoliciesImp(
ctx context.Context,
account *model.Account,
req *srequest.ChangePolicies,
) (any, error) {
// helper that runs through each change-item, enforces the right action,
// and then calls apply(item) if enforcement passes.
handle := func(items *[]model.RolePolicy, action model.Action, opName string, apply func(context.Context, *model.RolePolicy) error) error {
for _, it := range *items {
// 1) permission check
ok, err := a.enforcer.Enforce(ctx, a.policiesPermissionRef, account.ID, it.OrganizationRef, primitive.NilObjectID, action)
if err != nil {
a.logger.Warn(fmt.Sprintf("failed to enforce permission while %s policy", opName), zap.Error(err), zap.Any(opName, &it))
return err
}
if !ok {
a.logger.Debug(fmt.Sprintf("policy %s denied", opName))
return merrors.AccessDenied(mservice.Policies, string(action), primitive.NilObjectID)
}
// 2) perform the add/remove
if err := apply(ctx, &it); err != nil {
a.logger.Warn(fmt.Sprintf("failed to %s role policy", opName), zap.Error(err), zap.Any("policy", &it))
return err
}
}
return nil
}
// REMOVE
if req.Remove != nil {
if err := handle(req.Remove, model.ActionDelete, "remove", func(ctx context.Context, it *model.RolePolicy) error {
return a.auth.Permission().RevokeFromRole(ctx, it)
}); err != nil {
return nil, err
}
}
// ADD
if req.Add != nil {
if err := handle(req.Add, model.ActionCreate, "add", func(ctx context.Context, it *model.RolePolicy) error {
return a.auth.Permission().GrantToRole(ctx, it)
}); err != nil {
return nil, err
}
}
return nil, nil
}