2016-09-26 18:48:55 +00:00
|
|
|
package service
|
2016-09-04 05:13:42 +00:00
|
|
|
|
|
|
|
import (
|
2017-03-15 15:55:30 +00:00
|
|
|
"context"
|
2021-08-02 22:06:27 +00:00
|
|
|
|
2021-07-13 19:54:22 +00:00
|
|
|
"github.com/fleetdm/fleet/v4/server/authz"
|
2021-08-02 22:06:27 +00:00
|
|
|
"github.com/fleetdm/fleet/v4/server/contexts/logging"
|
2021-06-26 04:46:51 +00:00
|
|
|
"github.com/fleetdm/fleet/v4/server/contexts/viewer"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/ptr"
|
2018-01-03 19:18:05 +00:00
|
|
|
"github.com/pkg/errors"
|
2016-09-04 05:13:42 +00:00
|
|
|
)
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
func queryFromSpec(spec *fleet.QuerySpec) *fleet.Query {
|
|
|
|
return &fleet.Query{
|
2018-01-03 19:18:05 +00:00
|
|
|
Name: spec.Name,
|
|
|
|
Description: spec.Description,
|
|
|
|
Query: spec.Query,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
func specFromQuery(query *fleet.Query) *fleet.QuerySpec {
|
|
|
|
return &fleet.QuerySpec{
|
2018-01-03 19:18:05 +00:00
|
|
|
Name: query.Name,
|
|
|
|
Description: query.Description,
|
|
|
|
Query: query.Query,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
func (svc Service) ApplyQuerySpecs(ctx context.Context, specs []*fleet.QuerySpec) error {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Query{}, fleet.ActionWrite); err != nil {
|
2021-06-03 23:24:15 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-01-03 19:18:05 +00:00
|
|
|
vc, ok := viewer.FromContext(ctx)
|
|
|
|
if !ok {
|
|
|
|
return errors.New("user must be authenticated to apply queries")
|
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
queries := []*fleet.Query{}
|
2018-01-03 19:18:05 +00:00
|
|
|
for _, spec := range specs {
|
|
|
|
queries = append(queries, queryFromSpec(spec))
|
|
|
|
}
|
|
|
|
|
2020-12-15 02:13:34 +00:00
|
|
|
for _, query := range queries {
|
|
|
|
if err := query.ValidateSQL(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
err := svc.ds.ApplyQueries(ctx, vc.UserID(), queries)
|
2021-07-13 19:54:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "applying queries")
|
|
|
|
}
|
|
|
|
|
|
|
|
return svc.ds.NewActivity(
|
2021-09-14 12:11:07 +00:00
|
|
|
ctx,
|
2021-07-13 19:54:22 +00:00
|
|
|
authz.UserFromContext(ctx),
|
|
|
|
fleet.ActivityTypeAppliedSpecSavedQuery,
|
|
|
|
&map[string]interface{}{"specs": specs},
|
|
|
|
)
|
2018-01-03 19:18:05 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
func (svc Service) GetQuerySpecs(ctx context.Context) ([]*fleet.QuerySpec, error) {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Query{}, fleet.ActionRead); err != nil {
|
2021-06-03 23:24:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
queries, err := svc.ds.ListQueries(ctx, fleet.ListOptions{})
|
2018-01-03 19:18:05 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "getting queries")
|
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
specs := []*fleet.QuerySpec{}
|
2018-01-03 19:18:05 +00:00
|
|
|
for _, query := range queries {
|
|
|
|
specs = append(specs, specFromQuery(query))
|
|
|
|
}
|
|
|
|
return specs, nil
|
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
func (svc Service) GetQuerySpec(ctx context.Context, name string) (*fleet.QuerySpec, error) {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Query{}, fleet.ActionRead); err != nil {
|
2021-06-03 23:24:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
query, err := svc.ds.QueryByName(ctx, name)
|
2018-05-08 01:54:29 +00:00
|
|
|
if err != nil {
|
2018-05-09 23:54:42 +00:00
|
|
|
return nil, err
|
2018-05-08 01:54:29 +00:00
|
|
|
}
|
|
|
|
return specFromQuery(query), nil
|
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
func (svc Service) ListQueries(ctx context.Context, opt fleet.ListOptions) ([]*fleet.Query, error) {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Query{}, fleet.ActionRead); err != nil {
|
2021-06-03 23:24:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
return svc.ds.ListQueries(ctx, opt)
|
2016-09-04 05:13:42 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
func (svc *Service) GetQuery(ctx context.Context, id uint) (*fleet.Query, error) {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Query{}, fleet.ActionRead); err != nil {
|
2021-06-03 23:24:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
return svc.ds.Query(ctx, id)
|
2016-09-04 05:13:42 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
func (svc *Service) NewQuery(ctx context.Context, p fleet.QueryPayload) (*fleet.Query, error) {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Query{}, fleet.ActionWrite); err != nil {
|
2021-06-03 23:24:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
query := &fleet.Query{Saved: true}
|
2016-09-04 05:13:42 +00:00
|
|
|
|
|
|
|
if p.Name != nil {
|
|
|
|
query.Name = *p.Name
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:05:02 +00:00
|
|
|
if p.Description != nil {
|
|
|
|
query.Description = *p.Description
|
|
|
|
}
|
|
|
|
|
2016-09-04 05:13:42 +00:00
|
|
|
if p.Query != nil {
|
|
|
|
query.Query = *p.Query
|
|
|
|
}
|
|
|
|
|
2021-08-02 22:06:27 +00:00
|
|
|
logging.WithExtras(ctx, "name", query.Name, "sql", query.Query)
|
|
|
|
|
2021-05-20 17:28:55 +00:00
|
|
|
if p.ObserverCanRun != nil {
|
|
|
|
query.ObserverCanRun = *p.ObserverCanRun
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:22:31 +00:00
|
|
|
vc, ok := viewer.FromContext(ctx)
|
|
|
|
if ok {
|
2021-05-27 03:45:06 +00:00
|
|
|
query.AuthorID = ptr.Uint(vc.UserID())
|
2017-01-06 01:48:56 +00:00
|
|
|
query.AuthorName = vc.FullName()
|
2016-12-07 20:22:31 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 02:13:34 +00:00
|
|
|
if err := query.ValidateSQL(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
query, err := svc.ds.NewQuery(ctx, query)
|
2016-09-04 05:13:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-01-06 01:48:56 +00:00
|
|
|
|
2021-07-13 19:54:22 +00:00
|
|
|
if err := svc.ds.NewActivity(
|
2021-09-14 12:11:07 +00:00
|
|
|
ctx,
|
2021-07-13 19:54:22 +00:00
|
|
|
authz.UserFromContext(ctx),
|
|
|
|
fleet.ActivityTypeCreatedSavedQuery,
|
|
|
|
&map[string]interface{}{"query_id": query.ID, "query_name": query.Name},
|
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-10-31 22:00:04 +00:00
|
|
|
return query, nil
|
2016-09-04 05:13:42 +00:00
|
|
|
}
|
|
|
|
|
2021-06-06 22:07:29 +00:00
|
|
|
func (svc *Service) ModifyQuery(ctx context.Context, id uint, p fleet.QueryPayload) (*fleet.Query, error) {
|
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Query{}, fleet.ActionWrite); err != nil {
|
2021-06-03 23:24:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
query, err := svc.ds.Query(ctx, id)
|
2016-09-04 05:13:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if p.Name != nil {
|
|
|
|
query.Name = *p.Name
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:05:02 +00:00
|
|
|
if p.Description != nil {
|
|
|
|
query.Description = *p.Description
|
|
|
|
}
|
|
|
|
|
2016-09-04 05:13:42 +00:00
|
|
|
if p.Query != nil {
|
|
|
|
query.Query = *p.Query
|
|
|
|
}
|
|
|
|
|
2021-08-02 22:06:27 +00:00
|
|
|
logging.WithExtras(ctx, "name", query.Name, "sql", query.Query)
|
|
|
|
|
2021-05-20 17:28:55 +00:00
|
|
|
if p.ObserverCanRun != nil {
|
|
|
|
query.ObserverCanRun = *p.ObserverCanRun
|
|
|
|
}
|
|
|
|
|
2020-12-15 02:13:34 +00:00
|
|
|
if err := query.ValidateSQL(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
if err := svc.ds.SaveQuery(ctx, query); err != nil {
|
2016-09-04 05:13:42 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-07-13 19:54:22 +00:00
|
|
|
if err := svc.ds.NewActivity(
|
2021-09-14 12:11:07 +00:00
|
|
|
ctx,
|
2021-07-13 19:54:22 +00:00
|
|
|
authz.UserFromContext(ctx),
|
|
|
|
fleet.ActivityTypeEditedSavedQuery,
|
|
|
|
&map[string]interface{}{"query_id": query.ID, "query_name": query.Name},
|
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-09-04 05:13:42 +00:00
|
|
|
return query, nil
|
|
|
|
}
|
|
|
|
|
2021-06-01 00:07:51 +00:00
|
|
|
func (svc *Service) DeleteQuery(ctx context.Context, name string) error {
|
2021-06-06 22:07:29 +00:00
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Query{}, fleet.ActionWrite); err != nil {
|
2021-06-03 23:24:15 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
if err := svc.ds.DeleteQuery(ctx, name); err != nil {
|
2021-07-13 19:54:22 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return svc.ds.NewActivity(
|
2021-09-14 12:11:07 +00:00
|
|
|
ctx,
|
2021-07-13 19:54:22 +00:00
|
|
|
authz.UserFromContext(ctx),
|
|
|
|
fleet.ActivityTypeDeletedSavedQuery,
|
|
|
|
&map[string]interface{}{"query_name": name},
|
|
|
|
)
|
2016-09-04 05:13:42 +00:00
|
|
|
}
|
2016-12-09 17:12:45 +00:00
|
|
|
|
2021-06-01 00:07:51 +00:00
|
|
|
func (svc *Service) DeleteQueryByID(ctx context.Context, id uint) error {
|
2021-06-06 22:07:29 +00:00
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Query{}, fleet.ActionWrite); err != nil {
|
2021-06-03 23:24:15 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
query, err := svc.ds.Query(ctx, id)
|
2018-06-15 14:13:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "lookup query by ID")
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
if err := svc.ds.DeleteQuery(ctx, query.Name); err != nil {
|
2021-07-13 19:54:22 +00:00
|
|
|
return errors.Wrap(err, "delete query")
|
|
|
|
}
|
|
|
|
|
|
|
|
return svc.ds.NewActivity(
|
2021-09-14 12:11:07 +00:00
|
|
|
ctx,
|
2021-07-13 19:54:22 +00:00
|
|
|
authz.UserFromContext(ctx),
|
|
|
|
fleet.ActivityTypeDeletedSavedQuery,
|
|
|
|
&map[string]interface{}{"query_name": query.Name},
|
|
|
|
)
|
2018-06-15 14:13:11 +00:00
|
|
|
}
|
|
|
|
|
2021-06-01 00:07:51 +00:00
|
|
|
func (svc *Service) DeleteQueries(ctx context.Context, ids []uint) (uint, error) {
|
2021-06-06 22:07:29 +00:00
|
|
|
if err := svc.authz.Authorize(ctx, &fleet.Query{}, fleet.ActionWrite); err != nil {
|
2021-06-03 23:24:15 +00:00
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2021-09-14 12:11:07 +00:00
|
|
|
n, err := svc.ds.DeleteQueries(ctx, ids)
|
2021-07-13 19:54:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = svc.ds.NewActivity(
|
2021-09-14 12:11:07 +00:00
|
|
|
ctx,
|
2021-07-13 19:54:22 +00:00
|
|
|
authz.UserFromContext(ctx),
|
|
|
|
fleet.ActivityTypeDeletedMultipleSavedQuery,
|
|
|
|
&map[string]interface{}{"query_ids": ids},
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return n, nil
|
2016-12-09 17:12:45 +00:00
|
|
|
}
|