Skip to content

Commit 7f0a0da

Browse files
authored
Release 2.7.0 (#135)
* Changlog updates (#123) * Reading FCM error code from details section (#127) * Adding additional details to the error message when available (#129) * Implementing support for APNS content-mutable field (#126) * Implementing support for APNS content-mutable field * Corrected the mutable-content option name * Renamed CustomFields to CustomData * Added comment * Implementing Functions to Test Error Codes (#131) * Adding error codes to the auth package * Added error codes for messaging * Responding to review feedback; Updated changelog * Add Go import comments. (#132) * Bumped version to 2.7.0 (#133) * Bumped version to 2.7.0 * Updated changelog
1 parent c5db67b commit 7f0a0da

File tree

14 files changed

+494
-110
lines changed

14 files changed

+494
-110
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Unreleased
22

3+
-
4+
5+
# v2.7.0
6+
7+
- [added] Added several new functions for testing errors
8+
(e.g. `auth.IsUserNotFound()`).
9+
- [added] Added support for setting the `mutable-content` property on
10+
FCM messages sent via APNS.
11+
- [changed] Updated the error messages returned by the `messaging`
12+
package. These errors now contain the full details sent by the
13+
back-end server.
14+
315
# v2.6.1
416

517
- [added] Added support for Go 1.6.

auth/auth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ func (c *Client) VerifyIDTokenAndCheckRevoked(ctx context.Context, idToken strin
265265
}
266266

267267
if p.IssuedAt*1000 < user.TokensValidAfterMillis {
268-
return nil, fmt.Errorf("ID token has been revoked")
268+
return nil, internal.Error(idTokenRevoked, "ID token has been revoked")
269269
}
270270
return p, nil
271271
}

auth/auth_std.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// See the License for the specific language governing permissions and
1515
// limitations under the License.
1616

17-
package auth
17+
package auth // import "firebase.google.com/go/auth"
1818

1919
import "golang.org/x/net/context"
2020

auth/auth_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ func TestVerifyIDTokenAndCheckRevokedInvalidated(t *testing.T) {
233233

234234
p, err := s.Client.VerifyIDTokenAndCheckRevoked(ctx, tok)
235235
we := "ID token has been revoked"
236-
if p != nil || err == nil || err.Error() != we {
236+
if p != nil || err == nil || err.Error() != we || !IsIDTokenRevoked(err) {
237237
t.Errorf("VerifyIDTokenAndCheckRevoked(ctx, token) =(%v, %v); want = (%v, %v)",
238238
p, err, nil, we)
239239
}

auth/user_mgt.go

Lines changed: 101 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ import (
2323
"strings"
2424
"time"
2525

26+
"firebase.google.com/go/internal"
2627
"golang.org/x/net/context"
2728

29+
"google.golang.org/api/googleapi"
2830
"google.golang.org/api/identitytoolkit/v3"
2931
"google.golang.org/api/iterator"
3032
)
@@ -215,8 +217,10 @@ func (c *Client) DeleteUser(ctx context.Context, uid string) error {
215217

216218
call := c.is.Relyingparty.DeleteAccount(request)
217219
c.setHeader(call)
218-
_, err := call.Context(ctx).Do()
219-
return err
220+
if _, err := call.Context(ctx).Do(); err != nil {
221+
return handleServerError(err)
222+
}
223+
return nil
220224
}
221225

222226
// GetUser gets the user data corresponding to the specified user ID.
@@ -279,7 +283,7 @@ func (it *UserIterator) fetch(pageSize int, pageToken string) (string, error) {
279283
it.client.setHeader(call)
280284
resp, err := call.Context(it.ctx).Do()
281285
if err != nil {
282-
return "", err
286+
return "", handleServerError(err)
283287
}
284288

285289
for _, u := range resp.Users {
@@ -345,10 +349,7 @@ func processClaims(p map[string]interface{}) error {
345349
return nil
346350
}
347351

348-
claims, ok := cc.(map[string]interface{})
349-
if !ok {
350-
return fmt.Errorf("unexpected type for custom claims")
351-
}
352+
claims := cc.(map[string]interface{})
352353
for _, key := range reservedClaims {
353354
if _, ok := claims[key]; ok {
354355
return fmt.Errorf("claim %q is reserved and must not be set", key)
@@ -372,6 +373,83 @@ func processClaims(p map[string]interface{}) error {
372373
return nil
373374
}
374375

376+
// Error handlers.
377+
378+
const (
379+
emailAlredyExists = "email-already-exists"
380+
idTokenRevoked = "id-token-revoked"
381+
insufficientPermission = "insufficient-permission"
382+
phoneNumberAlreadyExists = "phone-number-already-exists"
383+
projectNotFound = "project-not-found"
384+
uidAlreadyExists = "uid-already-exists"
385+
unknown = "unknown-error"
386+
userNotFound = "user-not-found"
387+
)
388+
389+
// IsEmailAlreadyExists checks if the given error was due to a duplicate email.
390+
func IsEmailAlreadyExists(err error) bool {
391+
return internal.HasErrorCode(err, emailAlredyExists)
392+
}
393+
394+
// IsIDTokenRevoked checks if the given error was due to a revoked ID token.
395+
func IsIDTokenRevoked(err error) bool {
396+
return internal.HasErrorCode(err, idTokenRevoked)
397+
}
398+
399+
// IsInsufficientPermission checks if the given error was due to insufficient permissions.
400+
func IsInsufficientPermission(err error) bool {
401+
return internal.HasErrorCode(err, insufficientPermission)
402+
}
403+
404+
// IsPhoneNumberAlreadyExists checks if the given error was due to a duplicate phone number.
405+
func IsPhoneNumberAlreadyExists(err error) bool {
406+
return internal.HasErrorCode(err, phoneNumberAlreadyExists)
407+
}
408+
409+
// IsProjectNotFound checks if the given error was due to a non-existing project.
410+
func IsProjectNotFound(err error) bool {
411+
return internal.HasErrorCode(err, projectNotFound)
412+
}
413+
414+
// IsUIDAlreadyExists checks if the given error was due to a duplicate uid.
415+
func IsUIDAlreadyExists(err error) bool {
416+
return internal.HasErrorCode(err, uidAlreadyExists)
417+
}
418+
419+
// IsUnknown checks if the given error was due to a unknown server error.
420+
func IsUnknown(err error) bool {
421+
return internal.HasErrorCode(err, unknown)
422+
}
423+
424+
// IsUserNotFound checks if the given error was due to non-existing user.
425+
func IsUserNotFound(err error) bool {
426+
return internal.HasErrorCode(err, userNotFound)
427+
}
428+
429+
var serverError = map[string]string{
430+
"CONFIGURATION_NOT_FOUND": projectNotFound,
431+
"DUPLICATE_EMAIL": emailAlredyExists,
432+
"DUPLICATE_LOCAL_ID": uidAlreadyExists,
433+
"EMAIL_EXISTS": emailAlredyExists,
434+
"INSUFFICIENT_PERMISSION": insufficientPermission,
435+
"PHONE_NUMBER_EXISTS": phoneNumberAlreadyExists,
436+
"PROJECT_NOT_FOUND": projectNotFound,
437+
}
438+
439+
func handleServerError(err error) error {
440+
gerr, ok := err.(*googleapi.Error)
441+
if !ok {
442+
// Not a back-end error
443+
return err
444+
}
445+
serverCode := gerr.Message
446+
clientCode, ok := serverError[serverCode]
447+
if !ok {
448+
clientCode = unknown
449+
}
450+
return internal.Error(clientCode, err.Error())
451+
}
452+
375453
// Validators.
376454

377455
func validateDisplayName(val interface{}) error {
@@ -532,7 +610,7 @@ func (c *Client) createUser(ctx context.Context, user *UserToCreate) (string, er
532610
c.setHeader(call)
533611
resp, err := call.Context(ctx).Do()
534612
if err != nil {
535-
return "", err
613+
return "", handleServerError(err)
536614
}
537615

538616
return resp.LocalId, nil
@@ -555,20 +633,29 @@ func (c *Client) updateUser(ctx context.Context, uid string, user *UserToUpdate)
555633

556634
call := c.is.Relyingparty.SetAccountInfo(request)
557635
c.setHeader(call)
558-
_, err := call.Context(ctx).Do()
559-
560-
return err
636+
if _, err := call.Context(ctx).Do(); err != nil {
637+
return handleServerError(err)
638+
}
639+
return nil
561640
}
562641

563642
func (c *Client) getUser(ctx context.Context, request *identitytoolkit.IdentitytoolkitRelyingpartyGetAccountInfoRequest) (*UserRecord, error) {
564643
call := c.is.Relyingparty.GetAccountInfo(request)
565644
c.setHeader(call)
566645
resp, err := call.Context(ctx).Do()
567646
if err != nil {
568-
return nil, err
647+
return nil, handleServerError(err)
569648
}
570649
if len(resp.Users) == 0 {
571-
return nil, fmt.Errorf("cannot find user given params: id:%v, phone:%v, email: %v", request.LocalId, request.PhoneNumber, request.Email)
650+
var msg string
651+
if len(request.LocalId) == 1 {
652+
msg = fmt.Sprintf("cannot find user from uid: %q", request.LocalId[0])
653+
} else if len(request.Email) == 1 {
654+
msg = fmt.Sprintf("cannot find user from email: %q", request.Email[0])
655+
} else {
656+
msg = fmt.Sprintf("cannot find user from phone number: %q", request.PhoneNumber[0])
657+
}
658+
return nil, internal.Error(userNotFound, msg)
572659
}
573660

574661
eu, err := makeExportedUser(resp.Users[0])
@@ -581,8 +668,7 @@ func (c *Client) getUser(ctx context.Context, request *identitytoolkit.Identityt
581668
func makeExportedUser(r *identitytoolkit.UserInfo) (*ExportedUserRecord, error) {
582669
var cc map[string]interface{}
583670
if r.CustomAttributes != "" {
584-
err := json.Unmarshal([]byte(r.CustomAttributes), &cc)
585-
if err != nil {
671+
if err := json.Unmarshal([]byte(r.CustomAttributes), &cc); err != nil {
586672
return nil, err
587673
}
588674
if len(cc) == 0 {

auth/user_mgt_test.go

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -149,23 +149,21 @@ func TestGetNonExistingUser(t *testing.T) {
149149
s := echoServer([]byte(resp), t)
150150
defer s.Close()
151151

152-
want := "cannot find user given params: id:[%s], phone:[%s], email: [%s]"
153-
154-
we := fmt.Sprintf(want, "id-nonexisting", "", "")
152+
we := `cannot find user from uid: "id-nonexisting"`
155153
user, err := s.Client.GetUser(context.Background(), "id-nonexisting")
156-
if user != nil || err == nil || err.Error() != we {
154+
if user != nil || err == nil || err.Error() != we || !IsUserNotFound(err) {
157155
t.Errorf("GetUser(non-existing) = (%v, %q); want = (nil, %q)", user, err, we)
158156
}
159157

160-
we = fmt.Sprintf(want, "", "", "[email protected]")
158+
we = `cannot find user from email: "[email protected]"`
161159
user, err = s.Client.GetUserByEmail(context.Background(), "[email protected]")
162-
if user != nil || err == nil || err.Error() != we {
160+
if user != nil || err == nil || err.Error() != we || !IsUserNotFound(err) {
163161
t.Errorf("GetUserByEmail(non-existing) = (%v, %q); want = (nil, %q)", user, err, we)
164162
}
165163

166-
we = fmt.Sprintf(want, "", "+12345678901", "")
164+
we = `cannot find user from phone number: "+12345678901"`
167165
user, err = s.Client.GetUserByPhoneNumber(context.Background(), "+12345678901")
168-
if user != nil || err == nil || err.Error() != we {
166+
if user != nil || err == nil || err.Error() != we || !IsUserNotFound(err) {
169167
t.Errorf("GetUserPhoneNumber(non-existing) = (%v, %q); want = (nil, %q)", user, err, we)
170168
}
171169
}
@@ -642,7 +640,6 @@ func TestInvalidDeleteUser(t *testing.T) {
642640
}
643641

644642
func TestMakeExportedUser(t *testing.T) {
645-
646643
rur := &identitytoolkit.UserInfo{
647644
LocalId: "testuser",
648645
@@ -704,11 +701,39 @@ func TestHTTPError(t *testing.T) {
704701
}
705702

706703
want := `googleapi: got HTTP response code 500 with body: {"error":"test"}`
707-
if err.Error() != want {
704+
if err.Error() != want || !IsUnknown(err) {
708705
t.Errorf("GetUser() = %v; want = %q", err, want)
709706
}
710707
}
711708

709+
func TestHTTPErrorWithCode(t *testing.T) {
710+
errorCodes := map[string]func(error) bool{
711+
"CONFIGURATION_NOT_FOUND": IsProjectNotFound,
712+
"DUPLICATE_EMAIL": IsEmailAlreadyExists,
713+
"DUPLICATE_LOCAL_ID": IsUIDAlreadyExists,
714+
"EMAIL_EXISTS": IsEmailAlreadyExists,
715+
"INSUFFICIENT_PERMISSION": IsInsufficientPermission,
716+
"PHONE_NUMBER_EXISTS": IsPhoneNumberAlreadyExists,
717+
"PROJECT_NOT_FOUND": IsProjectNotFound,
718+
}
719+
s := echoServer(nil, t)
720+
defer s.Close()
721+
s.Status = http.StatusInternalServerError
722+
723+
for code, check := range errorCodes {
724+
s.Resp = []byte(fmt.Sprintf(`{"error":{"message":"%s"}}`, code))
725+
u, err := s.Client.GetUser(context.Background(), "some uid")
726+
if u != nil || err == nil {
727+
t.Fatalf("GetUser() = (%v, %v); want = (nil, error)", u, err)
728+
}
729+
730+
want := fmt.Sprintf("googleapi: Error 500: %s", code)
731+
if err.Error() != want || !check(err) {
732+
t.Errorf("GetUser() = %v; want = %q", err, want)
733+
}
734+
}
735+
}
736+
712737
type mockAuthServer struct {
713738
Resp []byte
714739
Header map[string]string

db/query.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package db
15+
package db // import "firebase.google.com/go/db"
1616

1717
import (
1818
"encoding/json"

firebase.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// Package firebase is the entry point to the Firebase Admin SDK. It provides functionality for initializing App
1616
// instances, which serve as the central entities that provide access to various other Firebase services exposed
1717
// from the SDK.
18-
package firebase
18+
package firebase // import "firebase.google.com/go"
1919

2020
import (
2121
"encoding/json"
@@ -42,7 +42,7 @@ import (
4242
var defaultAuthOverrides = make(map[string]interface{})
4343

4444
// Version of the Firebase Go Admin SDK.
45-
const Version = "2.6.1"
45+
const Version = "2.7.0"
4646

4747
// firebaseEnvName is the name of the environment variable with the Config.
4848
const firebaseEnvName = "FIREBASE_CONFIG"

iid/iid.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// limitations under the License.
1414

1515
// Package iid contains functions for deleting instance IDs from Firebase projects.
16-
package iid
16+
package iid // import "firebase.google.com/go/iid"
1717

1818
import (
1919
"errors"

0 commit comments

Comments
 (0)