2016-09-26 18:48:55 +00:00
package service
2016-08-28 03:59:17 +00:00
import (
2017-03-15 15:55:30 +00:00
"context"
2016-08-28 03:59:17 +00:00
"encoding/json"
2021-11-22 14:13:26 +00:00
"errors"
2023-04-19 21:43:15 +00:00
"fmt"
2017-05-09 00:43:48 +00:00
"io"
2016-08-28 03:59:17 +00:00
"net/http"
2018-11-21 01:19:24 +00:00
"net/url"
2016-09-04 05:13:42 +00:00
"strconv"
2021-02-18 20:52:43 +00:00
"strings"
2016-08-28 03:59:17 +00:00
2021-11-22 14:13:26 +00:00
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
2021-06-26 04:46:51 +00:00
"github.com/fleetdm/fleet/v4/server/fleet"
2021-08-24 20:24:52 +00:00
"github.com/fleetdm/fleet/v4/server/ptr"
2022-07-01 19:52:55 +00:00
kithttp "github.com/go-kit/kit/transport/http"
2021-02-16 23:25:34 +00:00
"github.com/gorilla/mux"
2016-08-28 03:59:17 +00:00
)
2022-03-15 19:14:42 +00:00
// errBadRoute is used for mux errors
var errBadRoute = errors . New ( "bad route" )
2016-08-28 03:59:17 +00:00
func encodeResponse ( ctx context . Context , w http . ResponseWriter , response interface { } ) error {
2017-05-17 15:58:40 +00:00
// The has to happen first, if an error happens we'll redirect to an error
// page and the error will be logged
if page , ok := response . ( htmlPage ) ; ok {
w . Header ( ) . Set ( "Content-Type" , "text/html; charset=UTF-8" )
2022-10-12 13:19:21 +00:00
writeBrowserSecurityHeaders ( w )
2022-07-01 19:52:55 +00:00
if coder , ok := page . error ( ) . ( kithttp . StatusCoder ) ; ok {
w . WriteHeader ( coder . StatusCode ( ) )
}
2017-05-17 15:58:40 +00:00
_ , err := io . WriteString ( w , page . html ( ) )
return err
}
2016-08-28 03:59:17 +00:00
if e , ok := response . ( errorer ) ; ok && e . error ( ) != nil {
encodeError ( ctx , e . error ( ) , w )
return nil
}
2016-09-15 14:52:17 +00:00
2022-03-15 19:14:42 +00:00
if render , ok := response . ( renderHijacker ) ; ok {
render . hijackRender ( ctx , w )
return nil
}
2016-09-15 14:52:17 +00:00
if e , ok := response . ( statuser ) ; ok {
2022-03-15 19:14:42 +00:00
w . WriteHeader ( e . Status ( ) )
if e . Status ( ) == http . StatusNoContent {
2016-09-15 14:52:17 +00:00
return nil
}
}
2016-09-09 12:34:53 +00:00
enc := json . NewEncoder ( w )
enc . SetIndent ( "" , " " )
return enc . Encode ( response )
2016-08-28 03:59:17 +00:00
}
2016-09-15 14:52:17 +00:00
// statuser allows response types to implement a custom
// http success status - default is 200 OK
type statuser interface {
2022-03-15 19:14:42 +00:00
Status ( ) int
2016-09-15 14:52:17 +00:00
}
2017-05-09 00:43:48 +00:00
// loads a html page
type htmlPage interface {
html ( ) string
error ( ) error
}
2022-03-15 19:14:42 +00:00
// renderHijacker can be implemented by response values to take control of
// their own rendering.
type renderHijacker interface {
hijackRender ( ctx context . Context , w http . ResponseWriter )
}
2021-12-14 21:34:11 +00:00
func uintFromRequest ( r * http . Request , name string ) ( uint64 , error ) {
2016-09-04 05:13:42 +00:00
vars := mux . Vars ( r )
2021-12-14 21:34:11 +00:00
s , ok := vars [ name ]
2016-09-04 05:13:42 +00:00
if ! ok {
return 0 , errBadRoute
}
2021-12-14 21:34:11 +00:00
u , err := strconv . ParseUint ( s , 10 , 64 )
2016-09-04 05:13:42 +00:00
if err != nil {
2021-12-14 21:34:11 +00:00
return 0 , ctxerr . Wrap ( r . Context ( ) , err , "uintFromRequest" )
2016-09-04 05:13:42 +00:00
}
2021-12-14 21:34:11 +00:00
return u , nil
2016-09-04 05:13:42 +00:00
}
2021-12-14 21:34:11 +00:00
func intFromRequest ( r * http . Request , name string ) ( int64 , error ) {
2018-05-04 18:05:55 +00:00
vars := mux . Vars ( r )
2021-12-14 21:34:11 +00:00
s , ok := vars [ name ]
if ! ok {
return 0 , errBadRoute
}
u , err := strconv . ParseInt ( s , 10 , 64 )
if err != nil {
return 0 , ctxerr . Wrap ( r . Context ( ) , err , "intFromRequest" )
}
return u , nil
}
func stringFromRequest ( r * http . Request , name string ) ( string , error ) {
vars := mux . Vars ( r )
s , ok := vars [ name ]
2018-05-04 18:05:55 +00:00
if ! ok {
return "" , errBadRoute
}
2021-12-14 21:34:11 +00:00
unescaped , err := url . PathUnescape ( s )
2018-11-21 01:19:24 +00:00
if err != nil {
2021-12-14 21:34:11 +00:00
return "" , ctxerr . Wrap ( r . Context ( ) , err , "unescape value in path" )
2018-11-21 01:19:24 +00:00
}
return unescaped , nil
2018-05-04 18:05:55 +00:00
}
2016-10-13 18:21:47 +00:00
// default number of items to include per page
const defaultPerPage = 20
// listOptionsFromRequest parses the list options from the request parameters
2021-06-06 22:07:29 +00:00
func listOptionsFromRequest ( r * http . Request ) ( fleet . ListOptions , error ) {
2016-10-13 18:21:47 +00:00
var err error
pageString := r . URL . Query ( ) . Get ( "page" )
perPageString := r . URL . Query ( ) . Get ( "per_page" )
2016-10-17 14:01:14 +00:00
orderKey := r . URL . Query ( ) . Get ( "order_key" )
orderDirectionString := r . URL . Query ( ) . Get ( "order_direction" )
2021-11-29 18:06:00 +00:00
afterString := r . URL . Query ( ) . Get ( "after" )
2016-10-13 18:21:47 +00:00
2021-08-24 17:35:03 +00:00
var page int
2016-10-13 18:21:47 +00:00
if pageString != "" {
page , err = strconv . Atoi ( pageString )
if err != nil {
2023-05-17 20:41:30 +00:00
return fleet . ListOptions { } , ctxerr . Wrap ( r . Context ( ) , badRequest ( "non-int page value" ) )
2016-10-13 18:21:47 +00:00
}
if page < 0 {
2023-05-17 20:41:30 +00:00
return fleet . ListOptions { } , ctxerr . Wrap ( r . Context ( ) , badRequest ( "negative page value" ) )
2016-10-13 18:21:47 +00:00
}
}
// We default to 0 for per_page so that not specifying any paging
// information gets all results
2021-08-24 17:35:03 +00:00
var perPage int
2016-10-13 18:21:47 +00:00
if perPageString != "" {
perPage , err = strconv . Atoi ( perPageString )
if err != nil {
2023-05-17 20:41:30 +00:00
return fleet . ListOptions { } , ctxerr . Wrap ( r . Context ( ) , badRequest ( "non-int per_page value" ) )
2016-10-13 18:21:47 +00:00
}
if perPage <= 0 {
2023-05-17 20:41:30 +00:00
return fleet . ListOptions { } , ctxerr . Wrap ( r . Context ( ) , badRequest ( "invalid per_page value" ) )
2016-10-13 18:21:47 +00:00
}
}
if perPage == 0 && pageString != "" {
// We explicitly set a non-zero default if a page is specified
// (because the client probably intended for paging, and
// leaving the 0 would turn that off)
perPage = defaultPerPage
}
2016-10-17 14:01:14 +00:00
if orderKey == "" && orderDirectionString != "" {
2023-05-17 20:41:30 +00:00
return fleet . ListOptions { } , ctxerr . Wrap ( r . Context ( ) , badRequest ( "order_key must be specified with order_direction" ) )
2016-10-17 14:01:14 +00:00
}
2023-11-09 19:18:29 +00:00
if orderKey == "" && afterString != "" {
return fleet . ListOptions { } , ctxerr . Wrap ( r . Context ( ) , badRequest ( "order_key must be specified with after" ) )
}
2021-06-06 22:07:29 +00:00
var orderDirection fleet . OrderDirection
2016-10-17 14:01:14 +00:00
switch orderDirectionString {
case "desc" :
2021-06-06 22:07:29 +00:00
orderDirection = fleet . OrderDescending
2016-10-17 14:01:14 +00:00
case "asc" :
2021-06-06 22:07:29 +00:00
orderDirection = fleet . OrderAscending
2016-10-17 14:01:14 +00:00
case "" :
2021-06-06 22:07:29 +00:00
orderDirection = fleet . OrderAscending
2016-10-17 14:01:14 +00:00
default :
2021-06-06 22:07:29 +00:00
return fleet . ListOptions { } ,
2023-05-17 20:41:30 +00:00
ctxerr . Wrap ( r . Context ( ) , badRequest ( "unknown order_direction: " + orderDirectionString ) )
2016-10-17 14:01:14 +00:00
}
2021-03-18 00:24:34 +00:00
query := r . URL . Query ( ) . Get ( "query" )
2021-06-06 22:07:29 +00:00
return fleet . ListOptions {
2016-10-17 14:01:14 +00:00
Page : uint ( page ) ,
PerPage : uint ( perPage ) ,
OrderKey : orderKey ,
OrderDirection : orderDirection ,
2021-03-18 00:24:34 +00:00
MatchQuery : query ,
2021-11-29 18:06:00 +00:00
After : afterString ,
2016-10-17 14:01:14 +00:00
} , nil
2016-10-13 18:21:47 +00:00
}
2021-06-06 22:07:29 +00:00
func hostListOptionsFromRequest ( r * http . Request ) ( fleet . HostListOptions , error ) {
2021-02-18 20:52:43 +00:00
opt , err := listOptionsFromRequest ( r )
if err != nil {
2021-06-06 22:07:29 +00:00
return fleet . HostListOptions { } , err
2021-02-18 20:52:43 +00:00
}
2021-06-06 22:07:29 +00:00
hopt := fleet . HostListOptions { ListOptions : opt }
2021-02-18 20:52:43 +00:00
status := r . URL . Query ( ) . Get ( "status" )
2021-06-06 22:07:29 +00:00
switch fleet . HostStatus ( status ) {
2022-10-10 11:45:39 +00:00
case fleet . StatusNew , fleet . StatusOnline , fleet . StatusOffline , fleet . StatusMIA , fleet . StatusMissing :
2021-06-06 22:07:29 +00:00
hopt . StatusFilter = fleet . HostStatus ( status )
2021-02-18 20:52:43 +00:00
case "" :
// No error when unset
default :
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid status: %s" , status ) ) )
2021-02-18 20:52:43 +00:00
}
additionalInfoFiltersString := r . URL . Query ( ) . Get ( "additional_info_filters" )
if additionalInfoFiltersString != "" {
hopt . AdditionalFilters = strings . Split ( additionalInfoFiltersString , "," )
}
2021-10-12 14:38:12 +00:00
teamID := r . URL . Query ( ) . Get ( "team_id" )
if teamID != "" {
2023-12-06 19:59:00 +00:00
id , err := strconv . ParseUint ( teamID , 10 , 32 )
2021-08-11 14:40:56 +00:00
if err != nil {
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid team_id: %s" , teamID ) ) )
2021-08-11 14:40:56 +00:00
}
tid := uint ( id )
hopt . TeamFilter = & tid
}
2021-10-12 14:38:12 +00:00
policyID := r . URL . Query ( ) . Get ( "policy_id" )
if policyID != "" {
2023-12-06 19:59:00 +00:00
id , err := strconv . ParseUint ( policyID , 10 , 32 )
2021-08-24 20:24:52 +00:00
if err != nil {
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid policy_id: %s" , policyID ) ) )
2021-08-24 20:24:52 +00:00
}
pid := uint ( id )
hopt . PolicyIDFilter = & pid
}
2021-10-12 14:38:12 +00:00
policyResponse := r . URL . Query ( ) . Get ( "policy_response" )
if policyResponse != "" {
2023-10-27 20:13:20 +00:00
if hopt . PolicyIDFilter == nil {
return hopt , ctxerr . Wrap (
r . Context ( ) , badRequest (
"Missing policy_id (it must be present when policy_response is specified)" ,
) ,
)
}
2021-08-24 20:24:52 +00:00
var v * bool
2021-10-12 14:38:12 +00:00
switch policyResponse {
2021-08-24 20:24:52 +00:00
case "passing" :
v = ptr . Bool ( true )
case "failing" :
v = ptr . Bool ( false )
2023-10-27 20:13:20 +00:00
default :
return hopt , ctxerr . Wrap (
r . Context ( ) ,
badRequest (
fmt . Sprintf (
"Invalid policy_response: %v (Valid options are 'passing' or 'failing')" ,
policyResponse ,
) ,
) ,
)
2021-08-24 20:24:52 +00:00
}
hopt . PolicyResponseFilter = v
}
2021-10-12 14:38:12 +00:00
softwareID := r . URL . Query ( ) . Get ( "software_id" )
if softwareID != "" {
2023-12-06 19:59:00 +00:00
id , err := strconv . ParseUint ( softwareID , 10 , 64 )
2021-10-12 14:38:12 +00:00
if err != nil {
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid software_id: %s" , softwareID ) ) )
2021-10-12 14:38:12 +00:00
}
sid := uint ( id )
hopt . SoftwareIDFilter = & sid
}
2023-12-06 19:59:00 +00:00
softwareVersionID := r . URL . Query ( ) . Get ( "software_version_id" )
if softwareVersionID != "" {
id , err := strconv . ParseUint ( softwareVersionID , 10 , 64 )
if err != nil {
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid software_version_id: %s" , softwareVersionID ) ) )
}
sid := uint ( id )
hopt . SoftwareVersionIDFilter = & sid
}
softwareTitleID := r . URL . Query ( ) . Get ( "software_title_id" )
if softwareTitleID != "" {
id , err := strconv . ParseUint ( softwareTitleID , 10 , 32 )
if err != nil {
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid software_title_id: %s" , softwareTitleID ) ) )
}
sid := uint ( id )
hopt . SoftwareTitleIDFilter = & sid
}
2022-08-22 19:34:00 +00:00
osID := r . URL . Query ( ) . Get ( "os_id" )
if osID != "" {
2023-12-06 19:59:00 +00:00
id , err := strconv . ParseUint ( osID , 10 , 32 )
2022-08-12 19:23:25 +00:00
if err != nil {
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid os_id: %s" , osID ) ) )
2022-08-12 19:23:25 +00:00
}
2022-08-22 19:34:00 +00:00
sid := uint ( id )
hopt . OSIDFilter = & sid
}
2024-01-31 17:14:24 +00:00
osVersionID := r . URL . Query ( ) . Get ( "os_version_id" )
if osVersionID != "" {
id , err := strconv . ParseUint ( osVersionID , 10 , 32 )
if err != nil {
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid os_version_id: %s" , osVersionID ) ) )
}
sid := uint ( id )
hopt . OSVersionIDFilter = & sid
}
2022-08-22 19:34:00 +00:00
osName := r . URL . Query ( ) . Get ( "os_name" )
if osName != "" {
hopt . OSNameFilter = & osName
}
osVersion := r . URL . Query ( ) . Get ( "os_version" )
if osVersion != "" {
hopt . OSVersionFilter = & osVersion
2022-08-12 19:23:25 +00:00
}
2024-02-15 20:27:18 +00:00
cve := r . URL . Query ( ) . Get ( "vulnerability" )
if cve != "" {
hopt . VulnerabilityFilter = & cve
}
2023-10-27 20:13:20 +00:00
if hopt . OSNameFilter != nil && hopt . OSVersionFilter == nil {
return hopt , ctxerr . Wrap (
r . Context ( ) , badRequest (
"Invalid os_version (os_version must be specified with os_name)" ,
) ,
)
}
if hopt . OSNameFilter == nil && hopt . OSVersionFilter != nil {
return hopt , ctxerr . Wrap (
r . Context ( ) , badRequest (
"Invalid os_name (os_name must be specified with os_version)" ,
) ,
)
}
2021-11-29 21:04:33 +00:00
disableFailingPolicies := r . URL . Query ( ) . Get ( "disable_failing_policies" )
if disableFailingPolicies != "" {
boolVal , err := strconv . ParseBool ( disableFailingPolicies )
if err != nil {
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap (
r . Context ( ) , badRequest (
fmt . Sprintf (
"Invalid disable_failing_policies: %s" ,
disableFailingPolicies ,
) ,
) ,
)
2021-11-29 21:04:33 +00:00
}
hopt . DisableFailingPolicies = boolVal
}
2022-05-02 21:34:14 +00:00
deviceMapping := r . URL . Query ( ) . Get ( "device_mapping" )
if deviceMapping != "" {
boolVal , err := strconv . ParseBool ( deviceMapping )
if err != nil {
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid device_mapping: %s" , deviceMapping ) ) )
2022-05-02 21:34:14 +00:00
}
hopt . DeviceMapping = boolVal
}
2022-08-10 19:15:01 +00:00
mdmID := r . URL . Query ( ) . Get ( "mdm_id" )
if mdmID != "" {
2023-12-06 19:59:00 +00:00
id , err := strconv . ParseUint ( mdmID , 10 , 32 )
2022-08-10 19:15:01 +00:00
if err != nil {
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid mdm_id: %s" , mdmID ) ) )
2022-08-10 19:15:01 +00:00
}
mid := uint ( id )
hopt . MDMIDFilter = & mid
}
2023-03-29 12:30:49 +00:00
if mdmName := r . URL . Query ( ) . Get ( "mdm_name" ) ; mdmName != "" {
hopt . MDMNameFilter = & mdmName
}
2022-08-10 19:15:01 +00:00
enrollmentStatus := r . URL . Query ( ) . Get ( "mdm_enrollment_status" )
switch fleet . MDMEnrollStatus ( enrollmentStatus ) {
2023-03-29 12:30:49 +00:00
case fleet . MDMEnrollStatusManual , fleet . MDMEnrollStatusAutomatic ,
fleet . MDMEnrollStatusPending , fleet . MDMEnrollStatusUnenrolled , fleet . MDMEnrollStatusEnrolled :
2022-08-10 19:15:01 +00:00
hopt . MDMEnrollmentStatusFilter = fleet . MDMEnrollStatus ( enrollmentStatus )
case "" :
// No error when unset
default :
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap (
r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid mdm_enrollment_status: %s" , enrollmentStatus ) ) ,
)
2022-08-29 18:40:16 +00:00
}
2022-08-10 19:15:01 +00:00
2023-03-04 00:19:46 +00:00
macOSSettingsStatus := r . URL . Query ( ) . Get ( "macos_settings" )
2023-10-06 22:04:33 +00:00
switch fleet . OSSettingsStatus ( macOSSettingsStatus ) {
case fleet . OSSettingsFailed , fleet . OSSettingsPending , fleet . OSSettingsVerifying , fleet . OSSettingsVerified :
hopt . MacOSSettingsFilter = fleet . OSSettingsStatus ( macOSSettingsStatus )
2023-03-04 00:19:46 +00:00
case "" :
// No error when unset
default :
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap (
r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid macos_settings: %s" , macOSSettingsStatus ) ) ,
)
2023-03-04 00:19:46 +00:00
}
2023-04-05 16:09:23 +00:00
macOSSettingsDiskEncryptionStatus := r . URL . Query ( ) . Get ( "macos_settings_disk_encryption" )
2023-04-24 21:27:15 +00:00
switch fleet . DiskEncryptionStatus ( macOSSettingsDiskEncryptionStatus ) {
2023-04-05 16:09:23 +00:00
case
2023-04-24 21:27:15 +00:00
fleet . DiskEncryptionVerifying ,
2023-06-05 17:05:28 +00:00
fleet . DiskEncryptionVerified ,
2023-04-24 21:27:15 +00:00
fleet . DiskEncryptionActionRequired ,
fleet . DiskEncryptionEnforcing ,
fleet . DiskEncryptionFailed ,
fleet . DiskEncryptionRemovingEnforcement :
hopt . MacOSSettingsDiskEncryptionFilter = fleet . DiskEncryptionStatus ( macOSSettingsDiskEncryptionStatus )
2023-04-05 16:09:23 +00:00
case "" :
// No error when unset
default :
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap (
r . Context ( ) ,
badRequest ( fmt . Sprintf ( "Invalid macos_settings_disk_encryption: %s" , macOSSettingsDiskEncryptionStatus ) ) ,
)
2023-04-05 16:09:23 +00:00
}
2023-10-06 22:04:33 +00:00
osSettingsStatus := r . URL . Query ( ) . Get ( "os_settings" )
switch fleet . OSSettingsStatus ( osSettingsStatus ) {
case fleet . OSSettingsFailed , fleet . OSSettingsPending , fleet . OSSettingsVerifying , fleet . OSSettingsVerified :
hopt . OSSettingsFilter = fleet . OSSettingsStatus ( osSettingsStatus )
case "" :
// No error when unset
default :
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap (
r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid os_settings: %s" , osSettingsStatus ) ) ,
)
2023-10-06 22:04:33 +00:00
}
osSettingsDiskEncryptionStatus := r . URL . Query ( ) . Get ( "os_settings_disk_encryption" )
switch fleet . DiskEncryptionStatus ( osSettingsDiskEncryptionStatus ) {
case
fleet . DiskEncryptionVerifying ,
fleet . DiskEncryptionVerified ,
fleet . DiskEncryptionActionRequired ,
fleet . DiskEncryptionEnforcing ,
fleet . DiskEncryptionFailed ,
fleet . DiskEncryptionRemovingEnforcement :
hopt . OSSettingsDiskEncryptionFilter = fleet . DiskEncryptionStatus ( osSettingsDiskEncryptionStatus )
case "" :
// No error when unset
default :
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap (
r . Context ( ) ,
badRequest ( fmt . Sprintf ( "Invalid os_settings_disk_encryption: %s" , macOSSettingsDiskEncryptionStatus ) ) ,
)
2023-10-06 22:04:33 +00:00
}
2023-04-22 15:23:38 +00:00
mdmBootstrapPackageStatus := r . URL . Query ( ) . Get ( "bootstrap_package" )
switch fleet . MDMBootstrapPackageStatus ( mdmBootstrapPackageStatus ) {
case fleet . MDMBootstrapPackageFailed , fleet . MDMBootstrapPackagePending , fleet . MDMBootstrapPackageInstalled :
bpf := fleet . MDMBootstrapPackageStatus ( mdmBootstrapPackageStatus )
hopt . MDMBootstrapPackageFilter = & bpf
case "" :
// No error when unset
default :
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap (
r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid bootstrap_package: %s" , mdmBootstrapPackageStatus ) ) ,
)
2023-04-22 15:23:38 +00:00
}
2022-08-29 18:40:16 +00:00
munkiIssueID := r . URL . Query ( ) . Get ( "munki_issue_id" )
if munkiIssueID != "" {
2023-12-06 19:59:00 +00:00
id , err := strconv . ParseUint ( munkiIssueID , 10 , 32 )
2022-08-29 18:40:16 +00:00
if err != nil {
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid munki_issue_id: %s" , munkiIssueID ) ) )
2022-08-29 18:40:16 +00:00
}
mid := uint ( id )
hopt . MunkiIssueIDFilter = & mid
2022-08-10 19:15:01 +00:00
}
2022-09-21 19:16:31 +00:00
lowDiskSpace := r . URL . Query ( ) . Get ( "low_disk_space" )
if lowDiskSpace != "" {
v , err := strconv . Atoi ( lowDiskSpace )
if err != nil {
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid low_disk_space: %s" , lowDiskSpace ) ) )
2022-09-21 19:16:31 +00:00
}
if v < 1 || v > 100 {
2023-10-27 20:13:20 +00:00
return hopt , ctxerr . Wrap (
r . Context ( ) , badRequest (
fmt . Sprintf (
"Invalid low_disk_space, must be between 1 and 100: %s" , lowDiskSpace ,
) ,
) ,
)
2022-09-21 19:16:31 +00:00
}
hopt . LowDiskSpaceFilter = & v
}
2023-12-14 21:18:30 +00:00
populateSoftware := r . URL . Query ( ) . Get ( "populate_software" )
if populateSoftware != "" {
ps , err := strconv . ParseBool ( populateSoftware )
if err != nil {
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid populate_software: %s" , populateSoftware ) ) )
}
hopt . PopulateSoftware = ps
}
2024-03-01 17:20:21 +00:00
populatePolicies := r . URL . Query ( ) . Get ( "populate_policies" )
if populatePolicies != "" {
pp , err := strconv . ParseBool ( populatePolicies )
if err != nil {
return hopt , ctxerr . Wrap (
r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid boolean parameter populate_policies: %s" , populateSoftware ) ) ,
)
}
hopt . PopulatePolicies = pp
}
2022-09-21 19:16:31 +00:00
2023-12-06 19:59:00 +00:00
// cannot combine software_id, software_version_id, and software_title_id
var softwareErrorLabel [ ] string
if hopt . SoftwareIDFilter != nil {
softwareErrorLabel = append ( softwareErrorLabel , "software_id" )
}
if hopt . SoftwareVersionIDFilter != nil {
softwareErrorLabel = append ( softwareErrorLabel , "software_version_id" )
}
if hopt . SoftwareTitleIDFilter != nil {
softwareErrorLabel = append ( softwareErrorLabel , "software_title_id" )
}
if len ( softwareErrorLabel ) > 1 {
return hopt , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid parameters. The combination of %s is not allowed." , strings . Join ( softwareErrorLabel , " and " ) ) ) )
}
2021-02-18 20:52:43 +00:00
return hopt , nil
}
2021-12-01 20:45:29 +00:00
func carveListOptionsFromRequest ( r * http . Request ) ( fleet . CarveListOptions , error ) {
opt , err := listOptionsFromRequest ( r )
if err != nil {
return fleet . CarveListOptions { } , err
}
2023-10-27 20:13:20 +00:00
carveOpts := fleet . CarveListOptions { ListOptions : opt }
2021-12-01 20:45:29 +00:00
expired := r . URL . Query ( ) . Get ( "expired" )
2023-10-27 20:13:20 +00:00
if expired == "" {
carveOpts . Expired = false
} else {
boolVal , err := strconv . ParseBool ( expired )
if err != nil {
return carveOpts , ctxerr . Wrap (
r . Context ( ) , badRequest (
fmt . Sprintf ( "Invalid expired: %s" , expired ) ,
) ,
)
}
carveOpts . Expired = boolVal
2021-12-01 20:45:29 +00:00
}
2023-10-27 20:13:20 +00:00
return carveOpts , nil
2021-12-01 20:45:29 +00:00
}
2021-06-06 22:07:29 +00:00
func userListOptionsFromRequest ( r * http . Request ) ( fleet . UserListOptions , error ) {
2021-04-22 03:54:09 +00:00
opt , err := listOptionsFromRequest ( r )
if err != nil {
2021-06-06 22:07:29 +00:00
return fleet . UserListOptions { } , err
2021-04-22 03:54:09 +00:00
}
2023-10-27 20:13:20 +00:00
userOpts := fleet . UserListOptions { ListOptions : opt }
2021-04-22 03:54:09 +00:00
if tid := r . URL . Query ( ) . Get ( "team_id" ) ; tid != "" {
teamID , err := strconv . ParseUint ( tid , 10 , 64 )
if err != nil {
2023-10-27 20:13:20 +00:00
return userOpts , ctxerr . Wrap ( r . Context ( ) , badRequest ( fmt . Sprintf ( "Invalid team_id: %s" , tid ) ) )
2021-04-22 03:54:09 +00:00
}
2023-10-27 20:13:20 +00:00
// GitHub CodeQL flags this as: Incorrect conversion between integer types. Previously waived: https://github.com/fleetdm/fleet/security/code-scanning/516
userOpts . TeamID = uint ( teamID )
2021-04-22 03:54:09 +00:00
}
2023-10-27 20:13:20 +00:00
return userOpts , nil
2021-04-22 03:54:09 +00:00
}
2018-05-08 01:54:29 +00:00
type getGenericSpecRequest struct {
2021-12-15 14:35:40 +00:00
Name string ` url:"name" `
2018-05-08 01:54:29 +00:00
}