Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ func (c *baseClient) verifyIDToken(ctx context.Context, idToken string, checkRev
if c.tenantID != "" && c.tenantID != decoded.Firebase.Tenant {
return nil, &internal.FirebaseError{
ErrorCode: internal.InvalidArgument,
String: fmt.Sprintf("invalid tenant id: %q", decoded.Firebase.Tenant),
Message: fmt.Sprintf("invalid tenant id: %q", decoded.Firebase.Tenant),
Ext: map[string]interface{}{
authErrorCode: tenantIDMismatch,
},
Expand Down Expand Up @@ -428,7 +428,7 @@ func (c *baseClient) checkRevokedOrDisabled(ctx context.Context, token *Token, e
if user.Disabled {
return &internal.FirebaseError{
ErrorCode: internal.InvalidArgument,
String: "user has been disabled",
Message: "user has been disabled",
Ext: map[string]interface{}{
authErrorCode: userDisabled,
},
Expand All @@ -438,7 +438,7 @@ func (c *baseClient) checkRevokedOrDisabled(ctx context.Context, token *Token, e
if token.IssuedAt*1000 < user.TokensValidAfterMillis {
return &internal.FirebaseError{
ErrorCode: internal.InvalidArgument,
String: errMessage,
Message: errMessage,
Ext: map[string]interface{}{
authErrorCode: errCode,
},
Expand Down
12 changes: 6 additions & 6 deletions auth/token_verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func (tv *tokenVerifier) verifyContent(token string, isEmulator bool) (*Token, e
if token == "" {
return nil, &internal.FirebaseError{
ErrorCode: internal.InvalidArgument,
String: fmt.Sprintf("%s must be a non-empty string", tv.shortName),
Message: fmt.Sprintf("%s must be a non-empty string", tv.shortName),
Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode},
}
}
Expand All @@ -196,7 +196,7 @@ func (tv *tokenVerifier) verifyContent(token string, isEmulator bool) (*Token, e
if err != nil {
return nil, &internal.FirebaseError{
ErrorCode: internal.InvalidArgument,
String: fmt.Sprintf(
Message: fmt.Sprintf(
"%s; see %s for details on how to retrieve a valid %s",
err.Error(), tv.docURL, tv.shortName),
Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode},
Expand All @@ -210,15 +210,15 @@ func (tv *tokenVerifier) verifyTimestamps(payload *Token) error {
if (payload.IssuedAt - clockSkewSeconds) > tv.clock.Now().Unix() {
return &internal.FirebaseError{
ErrorCode: internal.InvalidArgument,
String: fmt.Sprintf("%s issued at future timestamp: %d", tv.shortName, payload.IssuedAt),
Message: fmt.Sprintf("%s issued at future timestamp: %d", tv.shortName, payload.IssuedAt),
Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode},
}
}

if (payload.Expires + clockSkewSeconds) < tv.clock.Now().Unix() {
return &internal.FirebaseError{
ErrorCode: internal.InvalidArgument,
String: fmt.Sprintf("%s has expired at: %d", tv.shortName, payload.Expires),
Message: fmt.Sprintf("%s has expired at: %d", tv.shortName, payload.Expires),
Ext: map[string]interface{}{authErrorCode: tv.expiredTokenCode},
}
}
Expand All @@ -231,15 +231,15 @@ func (tv *tokenVerifier) verifySignature(ctx context.Context, token string) erro
if err != nil {
return &internal.FirebaseError{
ErrorCode: internal.Unknown,
String: err.Error(),
Message: err.Error(),
Ext: map[string]interface{}{authErrorCode: certificateFetchFailed},
}
}

if !tv.verifySignatureWithKeys(ctx, token, keys) {
return &internal.FirebaseError{
ErrorCode: internal.InvalidArgument,
String: "failed to verify token signature",
Message: "failed to verify token signature",
Ext: map[string]interface{}{authErrorCode: tv.invalidTokenCode},
}
}
Expand Down
8 changes: 4 additions & 4 deletions auth/user_mgt.go
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ func (c *baseClient) GetUserByProviderUID(ctx context.Context, providerID string
if len(getUsersResult.Users) == 0 {
return nil, &internal.FirebaseError{
ErrorCode: internal.NotFound,
String: fmt.Sprintf("cannot find user from providerID: { %s, %s }", providerID, providerUID),
Message: fmt.Sprintf("cannot find user from providerID: { %s, %s }", providerID, providerUID),
Response: nil,
Ext: map[string]interface{}{
authErrorCode: userNotFound,
Expand Down Expand Up @@ -848,7 +848,7 @@ func (c *baseClient) getUser(ctx context.Context, query *userQuery) (*UserRecord
if len(parsed.Users) == 0 {
return nil, &internal.FirebaseError{
ErrorCode: internal.NotFound,
String: fmt.Sprintf("no user exists with the %s", query.description()),
Message: fmt.Sprintf("no user exists with the %s", query.description()),
Response: resp.LowLevelResponse(),
Ext: map[string]interface{}{
authErrorCode: userNotFound,
Expand Down Expand Up @@ -1487,9 +1487,9 @@ func handleHTTPError(resp *internal.Response) error {
err.ErrorCode = authErr.code
err.Ext[authErrorCode] = authErr.authCode
if detail != "" {
err.String = fmt.Sprintf("%s: %s", authErr.message, detail)
err.Message = fmt.Sprintf("%s: %s", authErr.message, detail)
} else {
err.String = authErr.message
err.Message = authErr.message
}
}

Expand Down
2 changes: 1 addition & 1 deletion db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func handleRTDBError(resp *internal.Response) error {
}
json.Unmarshal(resp.Body, &p)
if p.Error != "" {
err.String = fmt.Sprintf("http error status: %d; reason: %s", resp.Status, p.Error)
err.Message = fmt.Sprintf("http error status: %d; reason: %s", resp.Status, p.Error)
}

return err
Expand Down
137 changes: 117 additions & 20 deletions errorutils/errorutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,138 @@ package errorutils

import (
"net/http"
)

// ErrorCode represents the platform-wide error codes that can be raised by
// Admin SDK APIs.
type ErrorCode string

const (
// InvalidArgument is a OnePlatform error code.
InvalidArgument ErrorCode = "INVALID_ARGUMENT"

// FailedPrecondition is a OnePlatform error code.
FailedPrecondition ErrorCode = "FAILED_PRECONDITION"

// OutOfRange is a OnePlatform error code.
OutOfRange ErrorCode = "OUT_OF_RANGE"

// Unauthenticated is a OnePlatform error code.
Unauthenticated ErrorCode = "UNAUTHENTICATED"

// PermissionDenied is a OnePlatform error code.
PermissionDenied ErrorCode = "PERMISSION_DENIED"

// NotFound is a OnePlatform error code.
NotFound ErrorCode = "NOT_FOUND"

// Conflict is a custom error code that represents HTTP 409 responses.
//
// OnePlatform APIs typically respond with ABORTED or ALREADY_EXISTS explicitly. But a few
// old APIs send HTTP 409 Conflict without any additional details to distinguish between the two
// cases. For these we currently use this error code. As more APIs adopt OnePlatform conventions
// this will become less important.
Conflict ErrorCode = "CONFLICT"

// Aborted is a OnePlatform error code.
Aborted ErrorCode = "ABORTED"

// AlreadyExists is a OnePlatform error code.
AlreadyExists ErrorCode = "ALREADY_EXISTS"

// ResourceExhausted is a OnePlatform error code.
ResourceExhausted ErrorCode = "RESOURCE_EXHAUSTED"

// Cancelled is a OnePlatform error code.
Cancelled ErrorCode = "CANCELLED"

// DataLoss is a OnePlatform error code.
DataLoss ErrorCode = "DATA_LOSS"

// Unknown is a OnePlatform error code.
Unknown ErrorCode = "UNKNOWN"

"firebase.google.com/go/v4/internal"
// Internal is a OnePlatform error code.
Internal ErrorCode = "INTERNAL"

// Unavailable is a OnePlatform error code.
Unavailable ErrorCode = "UNAVAILABLE"

// DeadlineExceeded is a OnePlatform error code.
DeadlineExceeded ErrorCode = "DEADLINE_EXCEEDED"
)

// FirebaseError is an error type containing an:
// - error code string.
// - error message.
// - HTTP response that caused this error, if any.
// - additional metadata about the error.
type FirebaseError struct {
ErrorCode ErrorCode
Message string
Response *http.Response
Ext map[string]interface{}
}

// Error implements the error interface.
func (fe *FirebaseError) Error() string {
return fe.Message
}

// Code returns the canonical error code associated with this error.
func (fe *FirebaseError) Code() ErrorCode {
return fe.ErrorCode
}

// HTTPResponse returns the HTTP response that caused this error, if any.
// Returns nil if the error was not caused by an HTTP response.
func (fe *FirebaseError) HTTPResponse() *http.Response {
return fe.Response
}

// Extensions returns additional metadata associated with this error.
// Returns nil if no extensions are available.
func (fe *FirebaseError) Extensions() map[string]interface{} {
return fe.Ext
}

// IsInvalidArgument checks if the given error was due to an invalid client argument.
func IsInvalidArgument(err error) bool {
return internal.HasPlatformErrorCode(err, internal.InvalidArgument)
return HasPlatformErrorCode(err, InvalidArgument)
}

// IsFailedPrecondition checks if the given error was because a request could not be executed
// in the current system state, such as deleting a non-empty directory.
func IsFailedPrecondition(err error) bool {
return internal.HasPlatformErrorCode(err, internal.FailedPrecondition)
return HasPlatformErrorCode(err, FailedPrecondition)
}

// IsOutOfRange checks if the given error due to an invalid range specified by the client.
func IsOutOfRange(err error) bool {
return internal.HasPlatformErrorCode(err, internal.OutOfRange)
return HasPlatformErrorCode(err, OutOfRange)
}

// IsUnauthenticated checks if the given error was caused by an unauthenticated request.
//
// Unauthenticated requests are due to missing, invalid, or expired OAuth token.
func IsUnauthenticated(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Unauthenticated)
return HasPlatformErrorCode(err, Unauthenticated)
}

// IsPermissionDenied checks if the given error was due to a client not having suffificient
// IsPermissionDenied checks if the given error was due to a client not having sufficient
// permissions.
//
// This can happen because the OAuth token does not have the right scopes, the client doesn't have
// permission, or the API has not been enabled for the client project.
func IsPermissionDenied(err error) bool {
return internal.HasPlatformErrorCode(err, internal.PermissionDenied)
return HasPlatformErrorCode(err, PermissionDenied)
}

// IsNotFound checks if the given error was due to a specified resource being not found.
//
// This may also occur when the request is rejected by undisclosed reasons, such as whitelisting.
func IsNotFound(err error) bool {
return internal.HasPlatformErrorCode(err, internal.NotFound)
return HasPlatformErrorCode(err, NotFound)
}

// IsConflict checks if the given error was due to a concurrency conflict, such as a
Expand All @@ -66,58 +157,58 @@ func IsNotFound(err error) bool {
// This represents an HTTP 409 Conflict status code, without additional information to distinguish
// between ABORTED or ALREADY_EXISTS error conditions.
func IsConflict(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Conflict)
return HasPlatformErrorCode(err, Conflict)
}

// IsAborted checks if the given error was due to a concurrency conflict, such as a
// read-modify-write conflict.
func IsAborted(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Aborted)
return HasPlatformErrorCode(err, Aborted)
}

// IsAlreadyExists checks if the given error was because a resource that a client tried to create
// already exists.
func IsAlreadyExists(err error) bool {
return internal.HasPlatformErrorCode(err, internal.AlreadyExists)
return HasPlatformErrorCode(err, AlreadyExists)
}

// IsResourceExhausted checks if the given error was caused by either running out of a quota or
// reaching a rate limit.
func IsResourceExhausted(err error) bool {
return internal.HasPlatformErrorCode(err, internal.ResourceExhausted)
return HasPlatformErrorCode(err, ResourceExhausted)
}

// IsCancelled checks if the given error was due to the client cancelling a request.
func IsCancelled(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Cancelled)
return HasPlatformErrorCode(err, Cancelled)
}

// IsDataLoss checks if the given error was due to an unrecoverable data loss or corruption.
//
// The client should report such errors to the end user.
func IsDataLoss(err error) bool {
return internal.HasPlatformErrorCode(err, internal.DataLoss)
return HasPlatformErrorCode(err, DataLoss)
}

// IsUnknown checks if the given error was cuased by an unknown server error.
// IsUnknown checks if the given error was caused by an unknown server error.
//
// This typically indicates a server bug.
func IsUnknown(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Unknown)
return HasPlatformErrorCode(err, Unknown)
}

// IsInternal checks if the given error was due to an internal server error.
//
// This typically indicates a server bug.
func IsInternal(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Internal)
return HasPlatformErrorCode(err, Internal)
}

// IsUnavailable checks if the given error was caused by an unavailable service.
//
// This typically indicates that the target service is temporarily down.
func IsUnavailable(err error) bool {
return internal.HasPlatformErrorCode(err, internal.Unavailable)
return HasPlatformErrorCode(err, Unavailable)
}

// IsDeadlineExceeded checks if the given error was due a request exceeding a deadline.
Expand All @@ -126,7 +217,7 @@ func IsUnavailable(err error) bool {
// deadline (i.e. requested deadline is not enough for the server to process the request) and the
// request did not finish within the deadline.
func IsDeadlineExceeded(err error) bool {
return internal.HasPlatformErrorCode(err, internal.DeadlineExceeded)
return HasPlatformErrorCode(err, DeadlineExceeded)
}

// HTTPResponse returns the http.Response instance that caused the given error.
Expand All @@ -136,10 +227,16 @@ func IsDeadlineExceeded(err error) bool {
// Returns a buffered copy of the original response received from the network stack. It is safe to
// read the response content from the returned http.Response.
func HTTPResponse(err error) *http.Response {
fe, ok := err.(*internal.FirebaseError)
fe, ok := err.(*FirebaseError)
if ok {
return fe.Response
}

return nil
}

// HasPlatformErrorCode checks if the given error contains a specific error code.
func HasPlatformErrorCode(err error, code ErrorCode) bool {
fe, ok := err.(*FirebaseError)
return ok && fe.ErrorCode == code
}
Loading