diff --git a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/Auth/AbstractFirebaseAuthTest.cs b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/Auth/AbstractFirebaseAuthTest.cs index 13b0a9b4..2d7129d2 100644 --- a/FirebaseAdmin/FirebaseAdmin.IntegrationTests/Auth/AbstractFirebaseAuthTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.IntegrationTests/Auth/AbstractFirebaseAuthTest.cs @@ -36,6 +36,13 @@ public abstract class AbstractFirebaseAuthTest HandleCodeInApp = false, }; + private static readonly ActionCodeSettings InvalidEmailLinkSettingsWithCustomDomain = new ActionCodeSettings() + { + Url = ContinueUrl, + HandleCodeInApp = true, + LinkDomain = "cool.link.domain", + }; + private readonly AbstractAuthFixture fixture; private readonly TemporaryUserBuilder userBuilder; @@ -658,6 +665,18 @@ public async Task SignInWithEmailLink() Assert.True(user.EmailVerified); } + [Fact] + public async Task AuthErrorCodeParse() + { + var user = await this.userBuilder.CreateRandomUserAsync(); + + var exception = await Assert.ThrowsAsync( + () => this.Auth.GeneratePasswordResetLinkAsync( + user.Email, InvalidEmailLinkSettingsWithCustomDomain)); + Assert.Equal(ErrorCode.InvalidArgument, exception.ErrorCode); + Assert.Equal(AuthErrorCode.InvalidHostingLinkDomain, exception.AuthErrorCode); + } + private async Task AssertValidIdTokenAsync( string idToken, bool checkRevoked = false) { diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/AuthErrorHandlerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/AuthErrorHandlerTest.cs index 87f792ca..aa6cd272 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/AuthErrorHandlerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/AuthErrorHandlerTest.cs @@ -121,6 +121,31 @@ public void KnownErrorCodeWithDetails( Assert.EndsWith($" ({code}): Some details.", error.Message); } + [Theory] + [MemberData(nameof(AuthErrorCodes))] + public void KnownErrorCodeWithDetailsAndWhiteSpace( + string code, ErrorCode expectedCode, AuthErrorCode expectedAuthCode) + { + var json = $@"{{ + ""error"": {{ + ""message"": ""{code} : Some details. "", + }} + }}"; + var resp = new HttpResponseMessage() + { + StatusCode = HttpStatusCode.ServiceUnavailable, + Content = new StringContent(json, Encoding.UTF8, "application/json"), + }; + + var error = AuthErrorHandler.Instance.HandleHttpErrorResponse(resp, json); + + Assert.Equal(expectedCode, error.ErrorCode); + Assert.Equal(expectedAuthCode, error.AuthErrorCode); + Assert.Same(resp, error.HttpResponse); + Assert.Null(error.InnerException); + Assert.EndsWith($" ({code}): Some details.", error.Message); + } + [Fact] public void UnknownErrorCode() { diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/AuthErrorHandler.cs b/FirebaseAdmin/FirebaseAdmin/Auth/AuthErrorHandler.cs index a40ebaac..c09844d6 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/AuthErrorHandler.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/AuthErrorHandler.cs @@ -216,7 +216,8 @@ private sealed class AuthError /// /// Gets the Firebase Auth error code extracted from the response. Returns empty string - /// if the error code cannot be determined. + /// if the error code cannot be determined. These error messages take the form + /// {"error": {"message": "CODE : OPTIONAL DETAILS"}}. /// internal string Code { @@ -225,7 +226,7 @@ internal string Code var separator = this.GetSeparator(); if (separator != -1) { - return this.Message.Substring(0, separator); + return this.Message.Substring(0, separator).Trim(); } return this.Message ?? string.Empty;