@@ -23,8 +23,10 @@ import (
23
23
"strings"
24
24
"time"
25
25
26
+ "firebase.google.com/go/internal"
26
27
"golang.org/x/net/context"
27
28
29
+ "google.golang.org/api/googleapi"
28
30
"google.golang.org/api/identitytoolkit/v3"
29
31
"google.golang.org/api/iterator"
30
32
)
@@ -215,8 +217,10 @@ func (c *Client) DeleteUser(ctx context.Context, uid string) error {
215
217
216
218
call := c .is .Relyingparty .DeleteAccount (request )
217
219
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
220
224
}
221
225
222
226
// 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) {
279
283
it .client .setHeader (call )
280
284
resp , err := call .Context (it .ctx ).Do ()
281
285
if err != nil {
282
- return "" , err
286
+ return "" , handleServerError ( err )
283
287
}
284
288
285
289
for _ , u := range resp .Users {
@@ -345,10 +349,7 @@ func processClaims(p map[string]interface{}) error {
345
349
return nil
346
350
}
347
351
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 {})
352
353
for _ , key := range reservedClaims {
353
354
if _ , ok := claims [key ]; ok {
354
355
return fmt .Errorf ("claim %q is reserved and must not be set" , key )
@@ -372,6 +373,83 @@ func processClaims(p map[string]interface{}) error {
372
373
return nil
373
374
}
374
375
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
+
375
453
// Validators.
376
454
377
455
func validateDisplayName (val interface {}) error {
@@ -532,7 +610,7 @@ func (c *Client) createUser(ctx context.Context, user *UserToCreate) (string, er
532
610
c .setHeader (call )
533
611
resp , err := call .Context (ctx ).Do ()
534
612
if err != nil {
535
- return "" , err
613
+ return "" , handleServerError ( err )
536
614
}
537
615
538
616
return resp .LocalId , nil
@@ -555,20 +633,29 @@ func (c *Client) updateUser(ctx context.Context, uid string, user *UserToUpdate)
555
633
556
634
call := c .is .Relyingparty .SetAccountInfo (request )
557
635
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
561
640
}
562
641
563
642
func (c * Client ) getUser (ctx context.Context , request * identitytoolkit.IdentitytoolkitRelyingpartyGetAccountInfoRequest ) (* UserRecord , error ) {
564
643
call := c .is .Relyingparty .GetAccountInfo (request )
565
644
c .setHeader (call )
566
645
resp , err := call .Context (ctx ).Do ()
567
646
if err != nil {
568
- return nil , err
647
+ return nil , handleServerError ( err )
569
648
}
570
649
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 )
572
659
}
573
660
574
661
eu , err := makeExportedUser (resp .Users [0 ])
@@ -581,8 +668,7 @@ func (c *Client) getUser(ctx context.Context, request *identitytoolkit.Identityt
581
668
func makeExportedUser (r * identitytoolkit.UserInfo ) (* ExportedUserRecord , error ) {
582
669
var cc map [string ]interface {}
583
670
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 {
586
672
return nil , err
587
673
}
588
674
if len (cc ) == 0 {
0 commit comments