mirror of
https://github.com/fleetdm/fleet
synced 2026-05-06 14:58:33 +00:00
253 lines
6.5 KiB
Go
253 lines
6.5 KiB
Go
package fleet
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
var (
|
|
ErrNoContext = errors.New("context key not set")
|
|
ErrPasswordResetRequired = &passwordResetRequiredError{}
|
|
ErrMissingLicense = &licenseError{}
|
|
)
|
|
|
|
// ErrWithInternal is an interface for errors that include extra "internal"
|
|
// information that should be logged in server logs but not sent to clients.
|
|
type ErrWithInternal interface {
|
|
error
|
|
// Internal returns the error string that must only be logged internally,
|
|
// not returned to the client.
|
|
Internal() string
|
|
}
|
|
|
|
// ErrWithInternal is an interface for errors that include additional logging
|
|
// fields that should be logged in server logs but not sent to clients.
|
|
type ErrWithLogFields interface {
|
|
error
|
|
// LogFields returns the additional log fields to add, which should come in
|
|
// key, value pairs (as used in go-kit log).
|
|
LogFields() []interface{}
|
|
}
|
|
|
|
// ErrWithRetryAfter is an interface for errors that should set a specific HTTP
|
|
// Header Retry-After value (see
|
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After)
|
|
type ErrWithRetryAfter interface {
|
|
error
|
|
// RetryAfter returns the number of seconds to wait before retry.
|
|
RetryAfter() int
|
|
}
|
|
|
|
type invalidArgWithStatusError struct {
|
|
InvalidArgumentError
|
|
code int
|
|
}
|
|
|
|
func (e invalidArgWithStatusError) Status() int {
|
|
if e.code == 0 {
|
|
// 422 is the default code for invalid args
|
|
return http.StatusUnprocessableEntity
|
|
}
|
|
return e.code
|
|
}
|
|
|
|
// InvalidArgumentError is the error returned when invalid data is presented to
|
|
// a service method.
|
|
type InvalidArgumentError []InvalidArgument
|
|
|
|
// InvalidArgument is the details about a single invalid argument.
|
|
type InvalidArgument struct {
|
|
name string
|
|
reason string
|
|
}
|
|
|
|
// NewInvalidArgumentError returns a InvalidArgumentError with at least
|
|
// one error.
|
|
func NewInvalidArgumentError(name, reason string) *InvalidArgumentError {
|
|
var invalid InvalidArgumentError
|
|
invalid = append(invalid, InvalidArgument{
|
|
name: name,
|
|
reason: reason,
|
|
})
|
|
return &invalid
|
|
}
|
|
|
|
func (e *InvalidArgumentError) Append(name, reason string) {
|
|
*e = append(*e, InvalidArgument{
|
|
name: name,
|
|
reason: reason,
|
|
})
|
|
}
|
|
|
|
func (e *InvalidArgumentError) Appendf(name, reasonFmt string, args ...interface{}) {
|
|
*e = append(*e, InvalidArgument{
|
|
name: name,
|
|
reason: fmt.Sprintf(reasonFmt, args...),
|
|
})
|
|
}
|
|
|
|
// WithStatus returns an error that combines the InvalidArgumentError
|
|
// with a custom status code.
|
|
func (e InvalidArgumentError) WithStatus(code int) error {
|
|
return invalidArgWithStatusError{e, code}
|
|
}
|
|
|
|
func (e *InvalidArgumentError) HasErrors() bool {
|
|
return len(*e) != 0
|
|
}
|
|
|
|
// Error implements the error interface.
|
|
func (e InvalidArgumentError) Error() string {
|
|
switch len(e) {
|
|
case 0:
|
|
return "validation failed"
|
|
case 1:
|
|
return fmt.Sprintf("validation failed: %s %s", e[0].name, e[0].reason)
|
|
default:
|
|
return fmt.Sprintf("validation failed: %s %s and %d other errors", e[0].name, e[0].reason,
|
|
len(e))
|
|
}
|
|
}
|
|
|
|
func (e InvalidArgumentError) Invalid() []map[string]string {
|
|
var invalid []map[string]string
|
|
for _, i := range e {
|
|
invalid = append(invalid, map[string]string{"name": i.name, "reason": i.reason})
|
|
}
|
|
return invalid
|
|
}
|
|
|
|
type AuthFailedError struct {
|
|
// internal is the reason that should only be logged internally
|
|
internal string
|
|
}
|
|
|
|
func NewAuthFailedError(internal string) *AuthFailedError {
|
|
return &AuthFailedError{internal: internal}
|
|
}
|
|
|
|
func (e AuthFailedError) Error() string {
|
|
return "Authentication failed"
|
|
}
|
|
|
|
func (e AuthFailedError) Internal() string {
|
|
return e.internal
|
|
}
|
|
|
|
func (e AuthFailedError) StatusCode() int {
|
|
return http.StatusUnauthorized
|
|
}
|
|
|
|
type AuthRequiredError struct {
|
|
// internal is the reason that should only be logged internally
|
|
internal string
|
|
}
|
|
|
|
func NewAuthRequiredError(internal string) *AuthRequiredError {
|
|
return &AuthRequiredError{internal: internal}
|
|
}
|
|
|
|
func (e AuthRequiredError) Error() string {
|
|
return "Authentication required"
|
|
}
|
|
|
|
func (e AuthRequiredError) Internal() string {
|
|
return e.internal
|
|
}
|
|
|
|
func (e AuthRequiredError) StatusCode() int {
|
|
return http.StatusUnauthorized
|
|
}
|
|
|
|
type AuthHeaderRequiredError struct {
|
|
// internal is the reason that should only be logged internally
|
|
internal string
|
|
}
|
|
|
|
func NewAuthHeaderRequiredError(internal string) *AuthHeaderRequiredError {
|
|
return &AuthHeaderRequiredError{internal: internal}
|
|
}
|
|
|
|
func (e AuthHeaderRequiredError) Error() string {
|
|
return "Authorization header required"
|
|
}
|
|
|
|
func (e AuthHeaderRequiredError) Internal() string {
|
|
return e.internal
|
|
}
|
|
|
|
func (e AuthHeaderRequiredError) StatusCode() int {
|
|
return http.StatusUnauthorized
|
|
}
|
|
|
|
// PermissionError, set when user is authenticated, but not allowed to perform action
|
|
type PermissionError struct {
|
|
message string
|
|
}
|
|
|
|
func NewPermissionError(message string) *PermissionError {
|
|
return &PermissionError{message: message}
|
|
}
|
|
|
|
func (e PermissionError) Error() string {
|
|
return e.message
|
|
}
|
|
|
|
func (e PermissionError) PermissionError() []map[string]string {
|
|
var forbidden []map[string]string
|
|
return forbidden
|
|
}
|
|
|
|
// licenseError is returned when the application is not properly licensed.
|
|
type licenseError struct{}
|
|
|
|
func (e licenseError) Error() string {
|
|
return "Requires Fleet Premium license"
|
|
}
|
|
|
|
func (e licenseError) StatusCode() int {
|
|
return http.StatusPaymentRequired
|
|
}
|
|
|
|
type passwordResetRequiredError struct{}
|
|
|
|
func (e passwordResetRequiredError) Error() string {
|
|
return "password reset required"
|
|
}
|
|
|
|
func (e passwordResetRequiredError) StatusCode() int {
|
|
return http.StatusUnauthorized
|
|
}
|
|
|
|
// Error is a user facing error (API user). It's meant to be used for errors that are
|
|
// related to fleet logic specifically. Other errors, such as mysql errors, shouldn't
|
|
// be translated to this.
|
|
type Error struct {
|
|
Code int `json:"code,omitempty"`
|
|
Message string `json:"message,omitempty"`
|
|
}
|
|
|
|
const (
|
|
// ErrNoRoleNeeded is the error number for valid role needed
|
|
ErrNoRoleNeeded = 1
|
|
// ErrNoOneAdminNeeded is the error number when all admins are about to be removed
|
|
ErrNoOneAdminNeeded = 2
|
|
// ErrNoUnknownTranslate is returned when an item type in the translate payload is unknown
|
|
ErrNoUnknownTranslate = 3
|
|
)
|
|
|
|
// NewError returns a fleet error with the code and message specified
|
|
func NewError(code int, message string) error {
|
|
return &Error{code, message}
|
|
}
|
|
|
|
// NewErrorf returns a fleet error with the code, and message formatted
|
|
// based on the format string and args specified
|
|
func NewErrorf(code int, format string, args ...interface{}) error {
|
|
return &Error{code, fmt.Sprintf(format, args...)}
|
|
}
|
|
|
|
func (ge *Error) Error() string {
|
|
return ge.Message
|
|
}
|