2018-05-04 16:53:21 +00:00
|
|
|
package service
|
|
|
|
|
|
2018-05-09 23:54:23 +00:00
|
|
|
import (
|
2022-02-28 12:34:44 +00:00
|
|
|
"database/sql"
|
2018-05-09 23:54:23 +00:00
|
|
|
"encoding/json"
|
2022-02-14 16:43:34 +00:00
|
|
|
"errors"
|
2023-04-03 18:25:49 +00:00
|
|
|
"fmt"
|
2018-05-09 23:54:23 +00:00
|
|
|
"io"
|
Add UUID to Fleet errors and clean up error msgs (#10411)
#8129
Apart from fixing the issue in #8129, this change also introduces UUIDs
to Fleet errors. To be able to match a returned error from the API to a
error in the Fleet logs. See
https://fleetdm.slack.com/archives/C019WG4GH0A/p1677780622769939 for
more context.
Samples with the changes in this PR:
```
curl -k -H "Authorization: Bearer $TEST_TOKEN" -H 'Content-Type:application/json' "https://localhost:8080/api/v1/fleet/sso" -d ''
{
"message": "Bad request",
"errors": [
{
"name": "base",
"reason": "Expected JSON Body"
}
],
"uuid": "a01f6e10-354c-4ff0-b96e-1f64adb500b0"
}
```
```
curl -k -H "Authorization: Bearer $TEST_TOKEN" -H 'Content-Type:application/json' "https://localhost:8080/api/v1/fleet/sso" -d 'asd'
{
"message": "Bad request",
"errors": [
{
"name": "base",
"reason": "json decoder error"
}
],
"uuid": "5f716a64-7550-464b-a1dd-e6a505a9f89d"
}
```
```
curl -k -X GET -H "Authorization: Bearer badtoken" "https://localhost:8080/api/latest/fleet/teams"
{
"message": "Authentication required",
"errors": [
{
"name": "base",
"reason": "Authentication required"
}
],
"uuid": "efe45bc0-f956-4bf9-ba4f-aa9020a9aaaf"
}
```
```
curl -k -X PATCH -H "Authorization: Bearer $TEST_TOKEN" "https://localhost:8080/api/latest/fleet/users/14" -d '{"name": "Manuel2", "password": "what", "new_password": "p4ssw0rd.12345"}'
{
"message": "Authorization header required",
"errors": [
{
"name": "base",
"reason": "Authorization header required"
}
],
"uuid": "57f78cd0-4559-464f-9df7-36c9ef7c89b3"
}
```
```
curl -k -X PATCH -H "Authorization: Bearer $TEST_TOKEN" "https://localhost:8080/api/latest/fleet/users/14" -d '{"name": "Manuel2", "password": "what", "new_password": "p4ssw0rd.12345"}'
{
"message": "Permission Denied",
"uuid": "7f0220ad-6de7-4faf-8b6c-8d7ff9d2ca06"
}
```
- [X] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [X] Documented any API changes (docs/Using-Fleet/REST-API.md or
docs/Contributing/API-for-contributors.md)
- ~[ ] Documented any permissions changes~
- ~[ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)~
- ~[ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for
new osquery data ingestion features.~
- [X] Added/updated tests
- [X] Manual QA for all new/changed functionality
- For Orbit and Fleet Desktop changes:
- [X] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- ~[ ] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).~
2023-03-13 16:44:06 +00:00
|
|
|
|
|
|
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
2018-05-09 23:54:23 +00:00
|
|
|
)
|
|
|
|
|
|
2022-02-14 16:43:34 +00:00
|
|
|
var (
|
|
|
|
|
ErrUnauthenticated = errors.New("unauthenticated, or invalid token")
|
2022-06-01 23:05:05 +00:00
|
|
|
ErrMissingLicense = errors.New("missing or invalid license")
|
2022-02-14 16:43:34 +00:00
|
|
|
)
|
|
|
|
|
|
2018-05-04 16:53:21 +00:00
|
|
|
type SetupAlreadyErr interface {
|
|
|
|
|
SetupAlready() bool
|
|
|
|
|
Error() string
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-08 02:07:00 +00:00
|
|
|
type setupAlreadyErr struct{}
|
2018-05-04 16:53:21 +00:00
|
|
|
|
|
|
|
|
func (e setupAlreadyErr) Error() string {
|
2021-01-28 15:57:32 +00:00
|
|
|
return "Fleet has already been setup"
|
2018-05-04 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e setupAlreadyErr) SetupAlready() bool {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type NotSetupErr interface {
|
|
|
|
|
NotSetup() bool
|
|
|
|
|
Error() string
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-08 02:07:00 +00:00
|
|
|
type notSetupErr struct{}
|
2018-05-04 16:53:21 +00:00
|
|
|
|
|
|
|
|
func (e notSetupErr) Error() string {
|
2021-01-28 15:57:32 +00:00
|
|
|
return "The Fleet instance is not set up yet"
|
2018-05-04 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e notSetupErr) NotSetup() bool {
|
|
|
|
|
return true
|
|
|
|
|
}
|
2018-05-08 02:07:00 +00:00
|
|
|
|
2023-04-03 18:25:49 +00:00
|
|
|
// TODO: we have a similar but different interface in the fleet package,
|
|
|
|
|
// fleet.NotFoundError - at the very least, the NotFound method should be the
|
|
|
|
|
// same in both (the other is currently IsNotFound), and ideally we'd just have
|
|
|
|
|
// one of those interfaces.
|
2018-05-08 02:07:00 +00:00
|
|
|
type NotFoundErr interface {
|
|
|
|
|
NotFound() bool
|
|
|
|
|
Error() string
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-06 15:56:54 +00:00
|
|
|
type notFoundErr struct {
|
|
|
|
|
msg string
|
Add UUID to Fleet errors and clean up error msgs (#10411)
#8129
Apart from fixing the issue in #8129, this change also introduces UUIDs
to Fleet errors. To be able to match a returned error from the API to a
error in the Fleet logs. See
https://fleetdm.slack.com/archives/C019WG4GH0A/p1677780622769939 for
more context.
Samples with the changes in this PR:
```
curl -k -H "Authorization: Bearer $TEST_TOKEN" -H 'Content-Type:application/json' "https://localhost:8080/api/v1/fleet/sso" -d ''
{
"message": "Bad request",
"errors": [
{
"name": "base",
"reason": "Expected JSON Body"
}
],
"uuid": "a01f6e10-354c-4ff0-b96e-1f64adb500b0"
}
```
```
curl -k -H "Authorization: Bearer $TEST_TOKEN" -H 'Content-Type:application/json' "https://localhost:8080/api/v1/fleet/sso" -d 'asd'
{
"message": "Bad request",
"errors": [
{
"name": "base",
"reason": "json decoder error"
}
],
"uuid": "5f716a64-7550-464b-a1dd-e6a505a9f89d"
}
```
```
curl -k -X GET -H "Authorization: Bearer badtoken" "https://localhost:8080/api/latest/fleet/teams"
{
"message": "Authentication required",
"errors": [
{
"name": "base",
"reason": "Authentication required"
}
],
"uuid": "efe45bc0-f956-4bf9-ba4f-aa9020a9aaaf"
}
```
```
curl -k -X PATCH -H "Authorization: Bearer $TEST_TOKEN" "https://localhost:8080/api/latest/fleet/users/14" -d '{"name": "Manuel2", "password": "what", "new_password": "p4ssw0rd.12345"}'
{
"message": "Authorization header required",
"errors": [
{
"name": "base",
"reason": "Authorization header required"
}
],
"uuid": "57f78cd0-4559-464f-9df7-36c9ef7c89b3"
}
```
```
curl -k -X PATCH -H "Authorization: Bearer $TEST_TOKEN" "https://localhost:8080/api/latest/fleet/users/14" -d '{"name": "Manuel2", "password": "what", "new_password": "p4ssw0rd.12345"}'
{
"message": "Permission Denied",
"uuid": "7f0220ad-6de7-4faf-8b6c-8d7ff9d2ca06"
}
```
- [X] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [X] Documented any API changes (docs/Using-Fleet/REST-API.md or
docs/Contributing/API-for-contributors.md)
- ~[ ] Documented any permissions changes~
- ~[ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)~
- ~[ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for
new osquery data ingestion features.~
- [X] Added/updated tests
- [X] Manual QA for all new/changed functionality
- For Orbit and Fleet Desktop changes:
- [X] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- ~[ ] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).~
2023-03-13 16:44:06 +00:00
|
|
|
|
|
|
|
|
fleet.ErrorWithUUID
|
2022-12-06 15:56:54 +00:00
|
|
|
}
|
2018-05-08 02:07:00 +00:00
|
|
|
|
|
|
|
|
func (e notFoundErr) Error() string {
|
2022-12-06 15:56:54 +00:00
|
|
|
if e.msg != "" {
|
|
|
|
|
return e.msg
|
|
|
|
|
}
|
2018-05-08 02:07:00 +00:00
|
|
|
return "The resource was not found"
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-24 17:35:03 +00:00
|
|
|
func (e notFoundErr) NotFound() bool {
|
2018-05-08 02:07:00 +00:00
|
|
|
return true
|
|
|
|
|
}
|
2018-05-09 23:54:23 +00:00
|
|
|
|
2022-02-28 12:34:44 +00:00
|
|
|
// Implement Is so that errors.Is(err, sql.ErrNoRows) returns true for an
|
|
|
|
|
// error of type *notFoundError, without having to wrap sql.ErrNoRows
|
|
|
|
|
// explicitly.
|
|
|
|
|
func (e notFoundErr) Is(other error) bool {
|
|
|
|
|
return other == sql.ErrNoRows
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-06 15:56:54 +00:00
|
|
|
type ConflictErr interface {
|
|
|
|
|
Conflict() bool
|
|
|
|
|
Error() string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type conflictErr struct {
|
|
|
|
|
msg string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e conflictErr) Error() string {
|
|
|
|
|
return e.msg
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e conflictErr) Conflict() bool {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-09 23:54:23 +00:00
|
|
|
type serverError struct {
|
|
|
|
|
Message string `json:"message"`
|
|
|
|
|
Errors []struct {
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
Reason string `json:"reason"`
|
|
|
|
|
} `json:"errors"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func extractServerErrorText(body io.Reader) string {
|
|
|
|
|
var serverErr serverError
|
|
|
|
|
if err := json.NewDecoder(body).Decode(&serverErr); err != nil {
|
|
|
|
|
return "unknown"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errText := serverErr.Message
|
|
|
|
|
if len(serverErr.Errors) > 0 {
|
|
|
|
|
errText += ": " + serverErr.Errors[0].Reason
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return errText
|
|
|
|
|
}
|
2023-04-03 18:25:49 +00:00
|
|
|
|
|
|
|
|
type statusCodeErr struct {
|
|
|
|
|
code int
|
|
|
|
|
body string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *statusCodeErr) Error() string {
|
|
|
|
|
return fmt.Sprintf("%d %s", e.code, e.body)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *statusCodeErr) StatusCode() int {
|
|
|
|
|
return e.code
|
|
|
|
|
}
|