114 lines
3.0 KiB
Go
114 lines
3.0 KiB
Go
package permissions
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"go.infratographer.com/x/gidx"
|
|
"golang.org/x/exp/slices"
|
|
)
|
|
|
|
// ResourceRoleCreate is the role create request.
|
|
type ResourceRoleCreate struct {
|
|
Actions []string `json:"actions"`
|
|
}
|
|
|
|
// ResourceRoleCreateResponse is the role creation response.
|
|
type ResourceRoleCreateResponse struct {
|
|
ID string `json:"id"`
|
|
}
|
|
|
|
// ResourceRoleDeleteResponse is the role deletion response.
|
|
type ResourceRoleDeleteResponse struct {
|
|
Success bool `json:"success"`
|
|
}
|
|
|
|
// ResourceRoles is a listg of resource roles.
|
|
type ResourceRoles []ResourceRole
|
|
|
|
// ResourceRole contains the role id and its actions.
|
|
type ResourceRole struct {
|
|
ID gidx.PrefixedID `json:"id"`
|
|
Actions []string `json:"actions"`
|
|
}
|
|
|
|
// CreateRole creates a role on the given resource id with the provided actions.
|
|
func (c *client) CreateRole(ctx context.Context, resourceID gidx.PrefixedID, actions []string) (gidx.PrefixedID, error) {
|
|
path := fmt.Sprintf("/api/v1/resources/%s/roles", resourceID.String())
|
|
|
|
body, err := encodeJSON(ResourceRoleCreate{
|
|
Actions: actions,
|
|
})
|
|
if err != nil {
|
|
return gidx.NullPrefixedID, err
|
|
}
|
|
|
|
var response ResourceRoleCreateResponse
|
|
|
|
if _, err = c.DoRequest(ctx, http.MethodPost, path, body, &response); err != nil { // nolint:bodyclose // closed by Do on json decode.
|
|
return gidx.NullPrefixedID, err
|
|
}
|
|
|
|
roleID, err := gidx.Parse(response.ID)
|
|
if err != nil {
|
|
return gidx.NullPrefixedID, err
|
|
}
|
|
|
|
return roleID, nil
|
|
}
|
|
|
|
// DeleteRole deletes the provided role.
|
|
func (c *client) DeleteRole(ctx context.Context, roleID gidx.PrefixedID) error {
|
|
path := fmt.Sprintf("/api/v1/roles/%s", roleID.String())
|
|
|
|
var response ResourceRoleDeleteResponse
|
|
|
|
if _, err := c.DoRequest(ctx, http.MethodDelete, path, nil, &response); err != nil { // nolint:bodyclose // closed by Do on json decode.
|
|
return err
|
|
}
|
|
|
|
if !response.Success {
|
|
return ErrUnexpectedRoleDeleteFailed
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ListResourceRoles fetches all roles assigned to the provided resource.
|
|
func (c *client) ListResourceRoles(ctx context.Context, resourceID gidx.PrefixedID) (ResourceRoles, error) {
|
|
path := fmt.Sprintf("/api/v1/resources/%s/roles", resourceID.String())
|
|
|
|
var response struct {
|
|
Data ResourceRoles `json:"data"`
|
|
}
|
|
|
|
if _, err := c.DoRequest(ctx, http.MethodGet, path, nil, &response); err != nil { // nolint:bodyclose // closed by Do on json decode.
|
|
return nil, err
|
|
}
|
|
|
|
return response.Data, nil
|
|
}
|
|
|
|
// FindResourceRoleByActions fetches roles assigned to the provided resource and finds the first role where the actions match the provided actions.
|
|
func (c *client) FindResourceRoleByActions(ctx context.Context, resourceID gidx.PrefixedID, actions []string) (ResourceRole, error) {
|
|
roles, err := c.ListResourceRoles(ctx, resourceID)
|
|
if err != nil {
|
|
return ResourceRole{}, err
|
|
}
|
|
|
|
slices.Sort(actions)
|
|
|
|
for _, role := range roles {
|
|
roleActions := role.Actions
|
|
|
|
slices.Sort(roleActions)
|
|
|
|
if slices.Equal(actions, roleActions) {
|
|
return role, nil
|
|
}
|
|
}
|
|
|
|
return ResourceRole{}, ErrRoleNotFound
|
|
}
|