portainer/portainer

View on GitHub
api/http/handler/hostmanagement/openamt/amtdevices.go

Summary

Maintainability
A
2 hrs
Test Coverage
package openamt

import (
    "errors"
    "net/http"

    portainer "github.com/portainer/portainer/api"
    httperror "github.com/portainer/portainer/pkg/libhttp/error"
    "github.com/portainer/portainer/pkg/libhttp/request"
    "github.com/portainer/portainer/pkg/libhttp/response"

    "github.com/rs/zerolog/log"
)

// @id OpenAMTDevices
// @summary Fetch OpenAMT managed devices information for endpoint
// @description Fetch OpenAMT managed devices information for endpoint
// @description **Access policy**: administrator
// @tags intel
// @security jwt
// @produce json
// @param id path int true "Environment(Endpoint) identifier"
// @success 200 "Success"
// @failure 400 "Invalid request"
// @failure 403 "Permission denied to access settings"
// @failure 500 "Server error"
// @router /open_amt/{id}/devices [get]
func (handler *Handler) openAMTDevices(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
    endpointID, err := request.RetrieveNumericRouteVariableValue(r, "id")
    if err != nil {
        return httperror.BadRequest("Invalid environment identifier route variable", err)
    }

    endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID))
    if handler.DataStore.IsErrObjectNotFound(err) {
        return httperror.NotFound("Unable to find an endpoint with the specified identifier inside the database", err)
    } else if err != nil {
        return httperror.InternalServerError("Unable to find an endpoint with the specified identifier inside the database", err)
    }

    if endpoint.AMTDeviceGUID == "" {
        return response.JSON(w, []portainer.OpenAMTDeviceInformation{})
    }

    settings, err := handler.DataStore.Settings().Settings()
    if err != nil {
        return httperror.InternalServerError("Unable to retrieve settings from the database", err)
    }

    device, err := handler.OpenAMTService.DeviceInformation(settings.OpenAMTConfiguration, endpoint.AMTDeviceGUID)
    if err != nil {
        return httperror.InternalServerError("Unable to retrieve device information", err)
    }

    devices := []portainer.OpenAMTDeviceInformation{
        *device,
    }

    return response.JSON(w, devices)
}

type deviceActionPayload struct {
    Action string
}

func (payload *deviceActionPayload) Validate(r *http.Request) error {
    if payload.Action == "" {
        return errors.New("device action must be provided")
    }

    return nil
}

// @id DeviceAction
// @summary Execute out of band action on an AMT managed device
// @description Execute out of band action on an AMT managed device
// @description **Access policy**: administrator
// @tags intel
// @security jwt
// @accept json
// @produce json
// @param id path int true "Environment identifier"
// @param deviceId path int true "Device identifier"
// @param body body deviceActionPayload true "Device Action"
// @success 204 "Success"
// @failure 400 "Invalid request"
// @failure 403 "Permission denied to access settings"
// @failure 500 "Server error"
// @router /open_amt/{id}/devices/{deviceId}/action [post]
func (handler *Handler) deviceAction(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
    deviceID, err := request.RetrieveRouteVariableValue(r, "deviceId")
    if err != nil {
        return httperror.BadRequest("Invalid device identifier route variable", err)
    }

    var payload deviceActionPayload
    err = request.DecodeAndValidateJSONPayload(r, &payload)
    if err != nil {
        log.Error().Err(err).Msg("invalid request payload")

        return httperror.BadRequest("Invalid request payload", err)
    }

    settings, err := handler.DataStore.Settings().Settings()
    if err != nil {
        return httperror.InternalServerError("Unable to retrieve settings from the database", err)
    }

    err = handler.OpenAMTService.ExecuteDeviceAction(settings.OpenAMTConfiguration, deviceID, payload.Action)
    if err != nil {
        log.Error().Err(err).Msg("error executing device action")

        return httperror.BadRequest("Error executing device action", err)
    }

    return response.Empty(w)
}

type deviceFeaturesPayload struct {
    Features portainer.OpenAMTDeviceEnabledFeatures
}

func (payload *deviceFeaturesPayload) Validate(r *http.Request) error {
    if payload.Features.UserConsent == "" {
        return errors.New("device user consent status must be provided")
    }

    return nil
}

type AuthorizationResponse struct {
    Server string
    Token  string
}

// @id DeviceFeatures
// @summary Enable features on an AMT managed device
// @description Enable features on an AMT managed device
// @description **Access policy**: administrator
// @tags intel
// @security jwt
// @accept json
// @produce json
// @param id path int true "Environment identifier"
// @param deviceId path int true "Device identifier"
// @param body body deviceFeaturesPayload true "Device Features"
// @success 204 "Success"
// @failure 400 "Invalid request"
// @failure 403 "Permission denied to access settings"
// @failure 500 "Server error"
// @router /open_amt/{id}/devices_features/{deviceId} [post]
func (handler *Handler) deviceFeatures(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
    deviceID, err := request.RetrieveRouteVariableValue(r, "deviceId")
    if err != nil {
        return httperror.BadRequest("Invalid device identifier route variable", err)
    }

    var payload deviceFeaturesPayload
    err = request.DecodeAndValidateJSONPayload(r, &payload)
    if err != nil {
        log.Error().Err(err).Msg("invalid request payload")

        return httperror.BadRequest("Invalid request payload", err)
    }

    settings, err := handler.DataStore.Settings().Settings()
    if err != nil {
        return httperror.InternalServerError("Unable to retrieve settings from the database", err)
    }

    _, err = handler.OpenAMTService.DeviceInformation(settings.OpenAMTConfiguration, deviceID)
    if err != nil {
        return httperror.InternalServerError("Unable to retrieve device information", err)
    }

    token, err := handler.OpenAMTService.EnableDeviceFeatures(settings.OpenAMTConfiguration, deviceID, payload.Features)
    if err != nil {
        log.Error().Err(err).Msg("error executing device action")

        return httperror.BadRequest("Error executing device action", err)
    }

    authorizationResponse := AuthorizationResponse{
        Server: settings.OpenAMTConfiguration.MPSServer,
        Token:  token,
    }

    return response.JSON(w, authorizationResponse)
}