Device create was left off the ITAM surfaces because enrollment returns a one-shot token. Add createDevice so automations can issue PENDING devices with the enrollment payload. Signed-off-by: Ludovic Vielle <ludovic@probo.com>
314 lines
9.5 KiB
Go
314 lines
9.5 KiB
Go
package console_v1
|
|
|
|
// This file will be automatically regenerated based on the schema, any resolver
|
|
// implementations
|
|
// will be copied through when generating and any unknown code will be moved to the end.
|
|
// Code generated by github.com/99designs/gqlgen version v0.17.94
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/vikstrous/dataloadgen"
|
|
"go.gearno.de/kit/log"
|
|
"go.probo.inc/probo/pkg/coredata"
|
|
"go.probo.inc/probo/pkg/iam"
|
|
"go.probo.inc/probo/pkg/itam"
|
|
"go.probo.inc/probo/pkg/page"
|
|
"go.probo.inc/probo/pkg/server/api/authn"
|
|
"go.probo.inc/probo/pkg/server/api/authz"
|
|
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
|
|
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
|
|
"go.probo.inc/probo/pkg/server/api/console/v1/types"
|
|
"go.probo.inc/probo/pkg/server/gqlutils"
|
|
)
|
|
|
|
// Owner is the resolver for the owner field.
|
|
func (r *deviceResolver) Owner(ctx context.Context, obj *types.Device) (*types.Profile, error) {
|
|
if obj.Owner == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
if _, err := r.authorize(ctx, obj.Owner.ID, iam.ActionMembershipProfileGet); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
loaders := dataloader.FromContext(ctx)
|
|
|
|
owner, err := loaders.Profile.Load(ctx, obj.Owner.ID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot get device owner profile", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewProfile(owner), nil
|
|
}
|
|
|
|
// LatestPostures is the resolver for the Device.latestPostures field.
|
|
func (r *deviceResolver) LatestPostures(ctx context.Context, obj *types.Device) ([]*types.DevicePosture, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, itam.ActionDevicePostureList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
postures, err := r.itam.GetLatestPostures(ctx, scope, obj.ID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot load latest device postures", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDevicePostures(postures), nil
|
|
}
|
|
|
|
// PostureReports is the resolver for the postureReports field.
|
|
func (r *deviceResolver) PostureReports(ctx context.Context, obj *types.Device, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DevicePostureReportOrderBy) (*types.DevicePostureReportConnection, error) {
|
|
scope, err := r.authorize(ctx, obj.ID, itam.ActionDevicePostureList)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pageOrderBy := page.OrderBy[coredata.DevicePostureReportOrderField]{
|
|
Field: coredata.DevicePostureReportOrderFieldCreatedAt,
|
|
Direction: page.OrderDirectionDesc,
|
|
}
|
|
if orderBy != nil {
|
|
pageOrderBy = page.OrderBy[coredata.DevicePostureReportOrderField]{
|
|
Field: orderBy.Field,
|
|
Direction: orderBy.Direction,
|
|
}
|
|
}
|
|
|
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
|
|
|
p, err := r.itam.ListPostureReports(ctx, scope, obj.ID, cursor)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot list device posture reports", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return types.NewDevicePostureReportConnection(p, r, obj.ID), nil
|
|
}
|
|
|
|
// TotalCount is the resolver for the DeviceConnection.totalCount field.
|
|
func (r *deviceConnectionResolver) TotalCount(ctx context.Context, obj *types.DeviceConnection) (int, error) {
|
|
scope, err := r.authorize(ctx, obj.ParentID, itam.ActionDeviceList)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch obj.Resolver.(type) {
|
|
case *organizationResolver:
|
|
count, err := r.itam.CountForOrganizationID(ctx, scope, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count devices", log.Error(err))
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
// TotalCount is the resolver for the totalCount field.
|
|
func (r *devicePostureReportConnectionResolver) TotalCount(ctx context.Context, obj *types.DevicePostureReportConnection) (int, error) {
|
|
scope, err := r.authorize(ctx, obj.ParentID, itam.ActionDevicePostureList)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
count, err := r.itam.CountPostureReports(ctx, scope, obj.ParentID)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot count device posture reports", log.Error(err))
|
|
|
|
return 0, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// EnrollDevice is the resolver for the enrollDevice field.
|
|
// SkipAssumptionCheck: self-enrollment from /enroll runs before the viewer
|
|
// assumes the target organization.
|
|
func (r *mutationResolver) EnrollDevice(ctx context.Context, input types.EnrollDeviceInput) (*types.CreateDevicePayload, error) {
|
|
identity := authn.IdentityFromContext(ctx)
|
|
|
|
scope, err := r.authorize(
|
|
ctx,
|
|
input.OrganizationID,
|
|
itam.ActionDeviceEnroll,
|
|
authz.WithSkipAssumptionCheck(),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result, err := r.itam.EnrollDevice(
|
|
ctx, scope,
|
|
itam.EnrollDeviceRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
IdentityID: identity.ID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot enroll device", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
urls, err := itam.BuildEnrollmentURLs(r.baseURL, result.EnrollmentToken)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot build enrollment URLs", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateDevicePayload{
|
|
Device: types.NewDevice(result.Device),
|
|
EnrollmentToken: result.EnrollmentToken,
|
|
ServerURL: urls.ServerURL,
|
|
EnrollmentURL: urls.EnrollmentURL,
|
|
}, nil
|
|
}
|
|
|
|
// CreateDevice is the resolver for the createDevice field.
|
|
func (r *mutationResolver) CreateDevice(ctx context.Context, input types.CreateDeviceInput) (*types.CreateDevicePayload, error) {
|
|
scope, err := r.authorize(ctx, input.OrganizationID, itam.ActionDeviceCreate)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result, err := r.itam.CreateDevice(
|
|
ctx, scope,
|
|
itam.CreateDeviceRequest{
|
|
OrganizationID: input.OrganizationID,
|
|
OwnerID: input.OwnerID,
|
|
},
|
|
)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if errors.Is(err, itam.ErrInvalidOwnerProfile) {
|
|
return nil, gqlutils.Invalid(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot create device", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
urls, err := itam.BuildEnrollmentURLs(r.baseURL, result.EnrollmentToken)
|
|
if err != nil {
|
|
r.logger.ErrorCtx(ctx, "cannot build enrollment URLs", log.Error(err))
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.CreateDevicePayload{
|
|
Device: types.NewDevice(result.Device),
|
|
EnrollmentToken: result.EnrollmentToken,
|
|
ServerURL: urls.ServerURL,
|
|
EnrollmentURL: urls.EnrollmentURL,
|
|
}, nil
|
|
}
|
|
|
|
// RevokeDevice is the resolver for the revokeDevice field.
|
|
func (r *mutationResolver) RevokeDevice(ctx context.Context, input types.RevokeDeviceInput) (*types.RevokeDevicePayload, error) {
|
|
scope, err := r.authorize(ctx, input.DeviceID, itam.ActionDeviceRevoke)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d, err := r.itam.RevokeDevice(ctx, scope, input.DeviceID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot revoke device", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.RevokeDevicePayload{Device: types.NewDevice(d)}, nil
|
|
}
|
|
|
|
// DeleteDevice is the resolver for the deleteDevice field.
|
|
func (r *mutationResolver) DeleteDevice(ctx context.Context, input types.DeleteDeviceInput) (*types.DeleteDevicePayload, error) {
|
|
scope, err := r.authorize(ctx, input.DeviceID, itam.ActionDeviceDelete)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d, err := r.itam.DeleteDevice(ctx, scope, input.DeviceID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if errors.Is(err, itam.ErrDeviceNotDeletable) {
|
|
return nil, gqlutils.Conflict(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot delete device", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.DeleteDevicePayload{DeletedDeviceID: d.ID}, nil
|
|
}
|
|
|
|
// SetDeviceOwner is the resolver for the setDeviceOwner field.
|
|
func (r *mutationResolver) SetDeviceOwner(ctx context.Context, input types.SetDeviceOwnerInput) (*types.SetDeviceOwnerPayload, error) {
|
|
scope, err := r.authorize(ctx, input.DeviceID, itam.ActionDeviceAssignOwner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d, err := r.itam.SetDeviceOwner(ctx, scope, input.DeviceID, input.OwnerID)
|
|
if err != nil {
|
|
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
return nil, gqlutils.NotFound(ctx, err)
|
|
}
|
|
|
|
if errors.Is(err, itam.ErrInvalidOwnerProfile) {
|
|
return nil, gqlutils.Invalid(ctx, err)
|
|
}
|
|
|
|
r.logger.ErrorCtx(ctx, "cannot set device owner", log.Error(err))
|
|
|
|
return nil, gqlutils.Internal(ctx)
|
|
}
|
|
|
|
return &types.SetDeviceOwnerPayload{Device: types.NewDevice(d)}, nil
|
|
}
|
|
|
|
// Device returns schema.DeviceResolver implementation.
|
|
func (r *Resolver) Device() schema.DeviceResolver { return &deviceResolver{r} }
|
|
|
|
// DeviceConnection returns schema.DeviceConnectionResolver implementation.
|
|
func (r *Resolver) DeviceConnection() schema.DeviceConnectionResolver {
|
|
return &deviceConnectionResolver{r}
|
|
}
|
|
|
|
// DevicePostureReportConnection returns schema.DevicePostureReportConnectionResolver implementation.
|
|
func (r *Resolver) DevicePostureReportConnection() schema.DevicePostureReportConnectionResolver {
|
|
return &devicePostureReportConnectionResolver{r}
|
|
}
|
|
|
|
type (
|
|
deviceResolver struct{ *Resolver }
|
|
deviceConnectionResolver struct{ *Resolver }
|
|
devicePostureReportConnectionResolver struct{ *Resolver }
|
|
)
|