@@ -18,6 +18,7 @@ package auth
18
18
import (
19
19
"context"
20
20
"encoding/base64"
21
+ "encoding/json"
21
22
"fmt"
22
23
"math/rand"
23
24
"net/url"
@@ -31,7 +32,14 @@ import (
31
32
"google.golang.org/api/iterator"
32
33
)
33
34
34
- const continueURL = "http://localhost/?a=1&b=2#c=3"
35
+ const (
36
+ continueURL = "http://localhost/?a=1&b=2#c=3"
37
+ continueURLKey = "continueUrl"
38
+ oobCodeKey = "oobCode"
39
+ modeKey = "mode"
40
+ resetPasswordURL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/resetPassword?key=%s"
41
+ emailLinkSignInURL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/emailLinkSignin?key=%s"
42
+ )
35
43
36
44
func TestGetUser (t * testing.T ) {
37
45
want := newUserWithParams (t )
@@ -466,20 +474,133 @@ func TestEmailVerificationLink(t *testing.T) {
466
474
t .Fatal (err )
467
475
}
468
476
469
- const (
470
- continueURLKey = "continueUrl"
471
- modeKey = "mode"
472
- verifyEmail = "verifyEmail"
473
- )
474
477
query := parsed .Query ()
475
478
if got := query .Get (continueURLKey ); got != continueURL {
476
479
t .Errorf ("EmailVerificationLinkWithSettings() %s = %q; want = %q" , continueURLKey , got , continueURL )
477
480
}
481
+
482
+ const verifyEmail = "verifyEmail"
478
483
if got := query .Get (modeKey ); got != verifyEmail {
479
484
t .Errorf ("EmailVerificationLinkWithSettings() %s = %q; want = %q" , modeKey , got , verifyEmail )
480
485
}
481
486
}
482
487
488
+ func TestPasswordResetLink (t * testing.T ) {
489
+ user := newUserWithParams (t )
490
+ defer deleteUser (user .UID )
491
+ link , err := client .PasswordResetLinkWithSettings (context .Background (), user .Email , & auth.ActionCodeSettings {
492
+ URL : continueURL ,
493
+ HandleCodeInApp : false ,
494
+ })
495
+ if err != nil {
496
+ t .Fatal (err )
497
+ }
498
+
499
+ parsed , err := url .ParseRequestURI (link )
500
+ if err != nil {
501
+ t .Fatal (err )
502
+ }
503
+
504
+ query := parsed .Query ()
505
+ if got := query .Get (continueURLKey ); got != continueURL {
506
+ t .Errorf ("PasswordResetLinkWithSettings() %s = %q; want = %q" , continueURLKey , got , continueURL )
507
+ }
508
+
509
+ oobCode := query .Get (oobCodeKey )
510
+ if err := resetPassword (user .Email , "password" , "newPassword" , oobCode ); err != nil {
511
+ t .Fatalf ("PasswordResetLinkWithSettings() reset = %v; want = nil" , err )
512
+ }
513
+
514
+ // Password reset also verifies the user's email
515
+ user , err = client .GetUser (context .Background (), user .UID )
516
+ if err != nil {
517
+ t .Fatalf ("GetUser() = %v; want = nil" , err )
518
+ }
519
+ if ! user .EmailVerified {
520
+ t .Error ("PasswordResetLinkWithSettings() EmailVerified = false; want = true" )
521
+ }
522
+ }
523
+
524
+ func TestEmailSignInLink (t * testing.T ) {
525
+ user := newUserWithParams (t )
526
+ defer deleteUser (user .UID )
527
+ link , err := client .EmailSignInLink (context .Background (), user .Email , & auth.ActionCodeSettings {
528
+ URL : continueURL ,
529
+ HandleCodeInApp : false ,
530
+ })
531
+ if err != nil {
532
+ t .Fatal (err )
533
+ }
534
+
535
+ parsed , err := url .ParseRequestURI (link )
536
+ if err != nil {
537
+ t .Fatal (err )
538
+ }
539
+
540
+ query := parsed .Query ()
541
+ if got := query .Get (continueURLKey ); got != continueURL {
542
+ t .Errorf ("EmailSignInLink() %s = %q; want = %q" , continueURLKey , got , continueURL )
543
+ }
544
+
545
+ oobCode := query .Get (oobCodeKey )
546
+ idToken , err := signInWithEmailLink (user .Email , oobCode )
547
+ if err != nil {
548
+ t .Fatalf ("EmailSignInLink() signIn = %v; want = nil" , err )
549
+ }
550
+ if idToken == "" {
551
+ t .Errorf ("ID Token = empty; want = non-empty" )
552
+ }
553
+
554
+ // Signing in with email link also verifies the user's email
555
+ user , err = client .GetUser (context .Background (), user .UID )
556
+ if err != nil {
557
+ t .Fatalf ("GetUser() = %v; want = nil" , err )
558
+ }
559
+ if ! user .EmailVerified {
560
+ t .Error ("EmailSignInLink() EmailVerified = false; want = true" )
561
+ }
562
+ }
563
+
564
+ func resetPassword (email , oldPassword , newPassword , oobCode string ) error {
565
+ req := map [string ]interface {}{
566
+ "email" : email ,
567
+ "oldPassword" : oldPassword ,
568
+ "newPassword" : newPassword ,
569
+ "oobCode" : oobCode ,
570
+ }
571
+ reqBytes , err := json .Marshal (req )
572
+ if err != nil {
573
+ return err
574
+ }
575
+
576
+ _ , err = postRequest (fmt .Sprintf (resetPasswordURL , apiKey ), reqBytes )
577
+ return err
578
+ }
579
+
580
+ func signInWithEmailLink (email , oobCode string ) (string , error ) {
581
+ req := map [string ]interface {}{
582
+ "email" : email ,
583
+ "oobCode" : oobCode ,
584
+ }
585
+ reqBytes , err := json .Marshal (req )
586
+ if err != nil {
587
+ return "" , err
588
+ }
589
+
590
+ b , err := postRequest (fmt .Sprintf (emailLinkSignInURL , apiKey ), reqBytes )
591
+ if err != nil {
592
+ return "" , err
593
+ }
594
+
595
+ var parsed struct {
596
+ IDToken string `json:"idToken"`
597
+ }
598
+ if err := json .Unmarshal (b , & parsed ); err != nil {
599
+ return "" , err
600
+ }
601
+ return parsed .IDToken , nil
602
+ }
603
+
483
604
var seededRand = rand .New (rand .NewSource (time .Now ().UnixNano ()))
484
605
485
606
func randomUID () string {
@@ -514,7 +635,6 @@ func newUserWithParams(t *testing.T) *auth.UserRecord {
514
635
PhoneNumber (phone ).
515
636
DisplayName ("Random User" ).
516
637
PhotoURL ("https://example.com/photo.png" ).
517
- EmailVerified (true ).
518
638
Password ("password" )
519
639
user , err := client .CreateUser (context .Background (), params )
520
640
if err != nil {
0 commit comments