package data import ( "fmt" ) type ErrorCode int const ( // 400 variants // 401 variants errCodeInvalidCredentials ErrorCode = 4011 errCodeInvalidAuthToken ErrorCode = 4012 errCodeAuthRequired ErrorCode = 4013 // 403 variants errCodeInactiveAccount ErrorCode = 4031 errCodeNotPermitted ErrorCode = 4032 // 409 variants errCodeEditConflict ErrorCode = 4091 errCodeAlreadyVoted ErrorCode = 4092 errCodeAlreadyBlindSigned ErrorCode = 4093 errCodeVoteAlreadyCast ErrorCode = 4094 // 422 variants errCodeValidationFailed ErrorCode = 4221 errCodeBlindedVoteRange ErrorCode = 4222 errCodeInvalidSignature ErrorCode = 4223 errCodeHasNotStarted ErrorCode = 4224 ) type Error struct { HttpCode int `json:"http_code,omitempty"` Code ErrorCode `json:"code,omitempty"` Message string `json:"message"` Details map[string]string `json:"details,omitempty"` } func (e *Error) Error() string { return e.Message } func (e *Error) WithDetails(details map[string]string) error { e.Details = details return e } func (e *Error) DetailMessages() []string { msgs := make([]string, 0, len(e.Details)) for key, msg := range e.Details { msgs = append(msgs, fmt.Sprintf("%s: %s", key, msg)) } return msgs } func New(httpCode int, code ErrorCode, text string) error { return &Error{HttpCode: httpCode, Code: code, Message: text} } var ( // 400 Bad Request ErrFailedPEM = New(400, 400, "failed to decode PEM block") ErrBadlyFormedJSON = New(400, 400, "body contains badly-formed JSON") ErrBodyEmpty = New(400, 400, "body must not be empty") ErrSingleValue = New(400, 400, "body must only contain a single JSON value") ErrInvalidID = New(400, 400, "invalid id parameter") ErrBadRequest = New(400, 400, "the server cannot process the request due to a client error") // 401 Unauthorized ErrInvalidCredentials = New(401, errCodeInvalidCredentials, "invalid credentials") ErrInvalidAuthToken = New(401, errCodeInvalidAuthToken, "invalid or missing authentication token") ErrNoToken = New(401, errCodeInvalidAuthToken, "token must be provided") ErrAuthRequired = New(401, errCodeAuthRequired, "you must be authenticated to access this resource") // 403 Forbidden ErrInactiveAccount = New(403, errCodeInactiveAccount, "your user account must be activated to access this resource") ErrNotPermitted = New(403, errCodeNotPermitted, "your user account doesn't have the necessary permissions to access this resource") ErrAuthenticatedVoteRejected = New(403, errCodeNotPermitted, "authenticated vote rejected") // 404 Not Found ErrRecordNotFound = New(404, 404, "record not found") ErrNoPath = New(404, 404, "path is required") // 409 Conflict ErrEditConflict = New(409, errCodeEditConflict, "edit conflict") ErrDuplicateVote = New(409, errCodeAlreadyVoted, "this signature has already been used to cast a vote") ErrDuplicateBlindSign = New(409, errCodeAlreadyBlindSigned, "user has already requested a blind signature for this issue") ErrDuplicateSignature = New(409, errCodeVoteAlreadyCast, "this signature has already been used to cast a vote") ErrDuplicateEmail = New(409, 409, "duplicate email") ErrDuplicateUser = New(409, 409, "duplicate username") // 422 Unprocessable Entity ErrValidationFailed = New(422, errCodeValidationFailed, "validation failed") ErrInvalidBlindedVote = New(422, errCodeBlindedVoteRange, "blinded_vote is out of valid range [1, n-1]") ErrInvalidSignature = New(422, errCodeInvalidSignature, "signature verification failed") ErrHasNotStarted = New(422, errCodeHasNotStarted, "the vote has not yet started") // 429 Too Many Requests ErrRateLimitExceeded = New(429, 429, "rate limit exceeded") )