From 5c499a94429e3920c130ec1e9e3d06351c35782b Mon Sep 17 00:00:00 2001 From: Scott Hyndman Date: Wed, 23 Feb 2022 15:56:45 -0500 Subject: [PATCH] feat(nhost_sdk): Add endpoint for resending verification email --- packages/nhost_sdk/lib/src/auth_client.dart | 19 +++ packages/nhost_sdk/test/auth_test.dart | 24 +++- ...uld_fail_when_the_user_does_not_exist.json | 42 +++++++ .../succeeds_if_the_user_exists.json | 116 ++++++++++++++++++ 4 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 packages/nhost_sdk/test/http_fixtures/auth/sending_verification_email/should_fail_when_the_user_does_not_exist.json create mode 100644 packages/nhost_sdk/test/http_fixtures/auth/sending_verification_email/succeeds_if_the_user_exists.json diff --git a/packages/nhost_sdk/lib/src/auth_client.dart b/packages/nhost_sdk/lib/src/auth_client.dart index 2b2d149a..730fbc7b 100644 --- a/packages/nhost_sdk/lib/src/auth_client.dart +++ b/packages/nhost_sdk/lib/src/auth_client.dart @@ -329,6 +329,25 @@ class AuthClient { return AuthResponse(session: null); } + /// Resends the sign-up verification email to the user with the specified + /// [email]. + Future sendVerificationEmail({ + required String email, + String? redirectTo, + }) async { + await _apiClient.post( + '/user/email/send-verification-email', + jsonBody: { + 'email': email, + if (redirectTo != null) + 'options': { + 'redirectTo': redirectTo, + }, + }, + headers: _session.authenticationHeaders, + ); + } + //#region Email and password changes /// Changes the email address of a logged in user. diff --git a/packages/nhost_sdk/test/auth_test.dart b/packages/nhost_sdk/test/auth_test.dart index 8fbc4624..da3e1b31 100644 --- a/packages/nhost_sdk/test/auth_test.dart +++ b/packages/nhost_sdk/test/auth_test.dart @@ -158,7 +158,8 @@ void main() async { test('should not be able to signIn with wrong password', () async { expect( - auth.signInEmailPassword(email: testEmail, password: 'wrong-password-1'), + auth.signInEmailPassword( + email: testEmail, password: 'wrong-password-1'), throwsA(isA().having( (e) => e.statusCode, 'statusCode', @@ -266,6 +267,23 @@ void main() async { }); }); + group('sending verification email', () { + test('should fail when the user does not exist', () { + expect( + auth.sendVerificationEmail(email: 'foo@bar.com'), + throwsA(anything), + ); + }); + + test('succeeds if the user exists', () async { + await registerTestUser(auth); + expect( + auth.sendVerificationEmail(email: defaultTestEmail), + completes, + ); + }); + }); + group('authentication state callbacks', () { AuthenticationState? authStateVar; late UnsubscribeDelegate unsubscribe; @@ -515,8 +533,8 @@ void main() async { test('should require TOTP for sign in once enabled', () async { final otpSecret = await registerMfaUser(auth); - final firstFactorAuthResult = - await auth.signInEmailPassword(email: testEmail, password: testPassword); + final firstFactorAuthResult = await auth.signInEmailPassword( + email: testEmail, password: testPassword); expect(firstFactorAuthResult.user, isNull); expect(auth.authenticationState, AuthenticationState.signedOut); expect(auth.accessToken, isNull); diff --git a/packages/nhost_sdk/test/http_fixtures/auth/sending_verification_email/should_fail_when_the_user_does_not_exist.json b/packages/nhost_sdk/test/http_fixtures/auth/sending_verification_email/should_fail_when_the_user_does_not_exist.json new file mode 100644 index 00000000..4c1e0c40 --- /dev/null +++ b/packages/nhost_sdk/test/http_fixtures/auth/sending_verification_email/should_fail_when_the_user_does_not_exist.json @@ -0,0 +1,42 @@ +{ + "name": "auth/sending_verification_email/should_fail_when_the_user_does_not_exist.json", + "interactions": [ + { + "request": { + "method": "post", + "uri": "http://localhost:1337/v1/auth/user/email/send-verification-email", + "headers": { + "content-type": "application/json; charset=utf-8" + }, + "body": { + "encoding": "utf-8", + "string": "{\"email\":\"foo@bar.com\"}" + } + }, + "response": { + "status": 400, + "headers": { + "surrogate-control": "no-store", + "cache-control": "no-store, no-cache, must-revalidate, proxy-revalidate", + "x-dns-prefetch-control": "off", + "date": "Wed, 23 Feb 2022 20:56:36 GMT", + "access-control-allow-origin": "*", + "strict-transport-security": "max-age=15552000; includeSubDomains", + "content-type": "application/json; charset=utf-8", + "pragma": "no-cache", + "x-xss-protection": "1; mode=block", + "content-length": "76", + "x-download-options": "noopen", + "etag": "W/\"4c-w0fVca1jWDndzB6CXE5yjIgrlWQ\"", + "x-frame-options": "SAMEORIGIN", + "x-content-type-options": "nosniff", + "expires": "0" + }, + "body": { + "encoding": "utf-8", + "string": "{\"statusCode\":400,\"error\":\"Bad Request\",\"message\":\"No user with such email\"}" + } + } + } + ] +} \ No newline at end of file diff --git a/packages/nhost_sdk/test/http_fixtures/auth/sending_verification_email/succeeds_if_the_user_exists.json b/packages/nhost_sdk/test/http_fixtures/auth/sending_verification_email/succeeds_if_the_user_exists.json new file mode 100644 index 00000000..ac2368ed --- /dev/null +++ b/packages/nhost_sdk/test/http_fixtures/auth/sending_verification_email/succeeds_if_the_user_exists.json @@ -0,0 +1,116 @@ +{ + "name": "auth/sending_verification_email/succeeds_if_the_user_exists.json", + "interactions": [ + { + "request": { + "method": "post", + "uri": "http://localhost:1337/v1/auth/signup/email-password", + "headers": { + "content-type": "application/json; charset=utf-8" + }, + "body": { + "encoding": "utf-8", + "string": "{\"email\":\"user-1@nhost.io\",\"password\":\"password-1\"}" + } + }, + "response": { + "status": 200, + "headers": { + "surrogate-control": "no-store", + "cache-control": "no-store, no-cache, must-revalidate, proxy-revalidate", + "x-dns-prefetch-control": "off", + "date": "Wed, 23 Feb 2022 20:56:36 GMT", + "access-control-allow-origin": "*", + "strict-transport-security": "max-age=15552000; includeSubDomains", + "content-type": "application/json; charset=utf-8", + "pragma": "no-cache", + "x-xss-protection": "1; mode=block", + "content-length": "927", + "x-download-options": "noopen", + "etag": "W/\"39f-IZsCGqJM5fq+0PcjvBP7FtF29ek\"", + "x-frame-options": "SAMEORIGIN", + "x-content-type-options": "nosniff", + "expires": "0" + }, + "body": { + "encoding": "utf-8", + "string": "{\"session\":{\"accessToken\":\"eyJhbGciOiJIUzI1NiJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsidXNlciIsIm1lIl0sIngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6InVzZXIiLCJ4LWhhc3VyYS11c2VyLWlkIjoiNzIyOWZlZTAtNzgxZC00MjdjLWEyNzQtMzhmNWM0MTkzMDViIiwieC1oYXN1cmEtdXNlci1pc0Fub255bW91cyI6ImZhbHNlIn0sInN1YiI6IjcyMjlmZWUwLTc4MWQtNDI3Yy1hMjc0LTM4ZjVjNDE5MzA1YiIsImlzcyI6Imhhc3VyYS1hdXRoIiwiaWF0IjoxNjQ1NjQ5Nzk2LCJleHAiOjE2NDU2NTA2OTZ9.8ckiq-toArcBnkwaPb6rEdN9Y2lbXpgJxoSFp1jYfmc\",\"accessTokenExpiresIn\":900,\"refreshToken\":\"376cf4c8-065a-4acb-857d-abccc643adfd\",\"user\":{\"id\":\"7229fee0-781d-427c-a274-38f5c419305b\",\"createdAt\":\"2022-02-23T20:56:36.918383+00:00\",\"displayName\":\"user-1@nhost.io\",\"avatarUrl\":\"https://s.gravatar.com/avatar/d86c12c3233e91ec90869a1f874cdf0e?r=g&default=blank\",\"locale\":\"en\",\"email\":\"user-1@nhost.io\",\"isAnonymous\":false,\"defaultRole\":\"user\",\"roles\":[\"user\",\"me\"],\"metadata\":{}}},\"mfa\":null}" + } + } + }, + { + "request": { + "method": "post", + "uri": "http://localhost:1337/v1/auth/signout", + "headers": { + "content-type": "application/json; charset=utf-8" + }, + "body": { + "encoding": "utf-8", + "string": "{\"refreshToken\":\"376cf4c8-065a-4acb-857d-abccc643adfd\",\"all\":false}" + } + }, + "response": { + "status": 200, + "headers": { + "surrogate-control": "no-store", + "cache-control": "no-store, no-cache, must-revalidate, proxy-revalidate", + "x-dns-prefetch-control": "off", + "date": "Wed, 23 Feb 2022 20:56:37 GMT", + "access-control-allow-origin": "*", + "strict-transport-security": "max-age=15552000; includeSubDomains", + "content-type": "text/html; charset=utf-8", + "pragma": "no-cache", + "x-xss-protection": "1; mode=block", + "content-length": "2", + "x-download-options": "noopen", + "etag": "W/\"2-nOO9QiTIwXgNtWtBJezz8kv3SLc\"", + "x-frame-options": "SAMEORIGIN", + "x-content-type-options": "nosniff", + "expires": "0" + }, + "body": { + "encoding": "utf-8", + "string": "OK" + } + } + }, + { + "request": { + "method": "post", + "uri": "http://localhost:1337/v1/auth/user/email/send-verification-email", + "headers": { + "content-type": "application/json; charset=utf-8" + }, + "body": { + "encoding": "utf-8", + "string": "{\"email\":\"user-1@nhost.io\"}" + } + }, + "response": { + "status": 200, + "headers": { + "surrogate-control": "no-store", + "cache-control": "no-store, no-cache, must-revalidate, proxy-revalidate", + "x-dns-prefetch-control": "off", + "date": "Wed, 23 Feb 2022 20:56:37 GMT", + "access-control-allow-origin": "*", + "strict-transport-security": "max-age=15552000; includeSubDomains", + "content-type": "text/html; charset=utf-8", + "pragma": "no-cache", + "x-xss-protection": "1; mode=block", + "content-length": "2", + "x-download-options": "noopen", + "etag": "W/\"2-eoX0dku9ba8cNUXvu/DyeabcC+s\"", + "x-frame-options": "SAMEORIGIN", + "x-content-type-options": "nosniff", + "expires": "0" + }, + "body": { + "encoding": "utf-8", + "string": "ok" + } + } + } + ] +} \ No newline at end of file