diff --git a/Vonage.Test/SimSwap/Authenticate/AuthenticateRequest.cs b/Vonage.Test/SimSwap/Authenticate/AuthenticateRequestTest.cs
similarity index 54%
rename from Vonage.Test/SimSwap/Authenticate/AuthenticateRequest.cs
rename to Vonage.Test/SimSwap/Authenticate/AuthenticateRequestTest.cs
index 34e37d4d..ea17f347 100644
--- a/Vonage.Test/SimSwap/Authenticate/AuthenticateRequest.cs
+++ b/Vonage.Test/SimSwap/Authenticate/AuthenticateRequestTest.cs
@@ -1,34 +1,45 @@
using FluentAssertions;
using Vonage.Common.Failures;
+using Vonage.SimSwap.Authenticate;
using Vonage.Test.Common.Extensions;
using Xunit;
namespace Vonage.Test.SimSwap.Authenticate;
[Trait("Category", "Request")]
-public class AuthenticateRequest
+public class AuthenticateRequestTest
{
+ private const string ValidScope = "scope=test";
+
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public void Parse_ShouldReturnFailure_GivenNumberIsNullOrWhitespace(string value) =>
- Vonage.SimSwap.Authenticate.AuthenticateRequest.Parse(value).Should()
+ AuthenticateRequest.Parse(value, ValidScope).Should()
.BeFailure(ResultFailure.FromErrorMessage("Number cannot be null or whitespace."));
+ [Theory]
+ [InlineData("")]
+ [InlineData(" ")]
+ [InlineData(null)]
+ public void Parse_ShouldReturnFailure_GivenScopeIsNullOrWhitespace(string value) =>
+ AuthenticateRequest.Parse("1234567", value).Should()
+ .BeParsingFailure("Scope cannot be null or whitespace.");
+
[Fact]
public void Parse_ShouldReturnFailure_GivenNumberContainsNonDigits() =>
- Vonage.SimSwap.Authenticate.AuthenticateRequest.Parse("1234567abc123").Should()
+ AuthenticateRequest.Parse("1234567abc123", ValidScope).Should()
.BeFailure(ResultFailure.FromErrorMessage("Number can only contain digits."));
[Fact]
public void Parse_ShouldReturnFailure_GivenNumberLengthIsHigherThan7() =>
- Vonage.SimSwap.Authenticate.AuthenticateRequest.Parse("123456").Should()
+ AuthenticateRequest.Parse("123456", ValidScope).Should()
.BeFailure(ResultFailure.FromErrorMessage("Number length cannot be lower than 7."));
[Fact]
public void Parse_ShouldReturnFailure_GivenNumberLengthIsLowerThan15() =>
- Vonage.SimSwap.Authenticate.AuthenticateRequest.Parse("1234567890123456").Should()
+ AuthenticateRequest.Parse("1234567890123456", ValidScope).Should()
.BeFailure(ResultFailure.FromErrorMessage("Number length cannot be higher than 15."));
[Theory]
@@ -37,14 +48,23 @@ public void Parse_ShouldReturnFailure_GivenNumberLengthIsLowerThan15() =>
[InlineData("+1234567890", "1234567890")]
[InlineData("+123456789012345", "123456789012345")]
[InlineData("+++1234567890", "1234567890")]
- public void Parse_ShouldReturnSuccess_GivenNumberIsValid(string value, string expected) =>
- Vonage.SimSwap.Authenticate.AuthenticateRequest.Parse(value).Map(number => number.PhoneNumber.Number).Should()
+ public void Parse_ShouldSetNumber(string value, string expected) =>
+ AuthenticateRequest.Parse(value, ValidScope)
+ .Map(request => request.PhoneNumber.Number)
+ .Should()
.BeSuccess(expected);
+ [Fact]
+ public void Parse_ShouldSetScope() =>
+ AuthenticateRequest.Parse("1234567", ValidScope)
+ .Map(request => request.Scope)
+ .Should()
+ .BeSuccess(ValidScope);
+
[Fact]
public void BuildAuthorizeRequest()
{
- var request = Vonage.SimSwap.Authenticate.AuthenticateRequest.Parse("123456789").GetSuccessUnsafe();
+ var request = AuthenticateRequest.Parse("123456789", ValidScope).GetSuccessUnsafe();
request.BuildAuthorizeRequest().Number.Should().Be(request.PhoneNumber);
}
}
\ No newline at end of file
diff --git a/Vonage.Test/SimSwap/Authenticate/AuthorizeRequestTest.cs b/Vonage.Test/SimSwap/Authenticate/AuthorizeRequestTest.cs
index f8becb43..633cddc8 100644
--- a/Vonage.Test/SimSwap/Authenticate/AuthorizeRequestTest.cs
+++ b/Vonage.Test/SimSwap/Authenticate/AuthorizeRequestTest.cs
@@ -1,4 +1,5 @@
-using Vonage.Test.Common.Extensions;
+using Vonage.SimSwap.Authenticate;
+using Vonage.Test.Common.Extensions;
using Xunit;
namespace Vonage.Test.SimSwap.Authenticate;
@@ -8,7 +9,7 @@ public class AuthorizeRequestTest
{
[Fact]
public void GetEndpointPath_ShouldReturnApiEndpoint() =>
- Vonage.SimSwap.Authenticate.AuthenticateRequest.Parse("123456789")
+ AuthenticateRequest.Parse("123456789", "scope")
.Map(request => request.BuildAuthorizeRequest())
.Map(r => r.GetEndpointPath())
.Should().BeSuccess("oauth2/bc-authorize");
diff --git a/Vonage.Test/SimSwap/Authenticate/E2ETest.cs b/Vonage.Test/SimSwap/Authenticate/E2ETest.cs
index 7ab8df50..d580bac1 100644
--- a/Vonage.Test/SimSwap/Authenticate/E2ETest.cs
+++ b/Vonage.Test/SimSwap/Authenticate/E2ETest.cs
@@ -33,7 +33,8 @@ public async Task Authenticate()
.RespondWith(Response.Create().WithStatusCode(HttpStatusCode.OK)
.WithBody(this.Serialization.GetResponseJson(nameof(SerializationTest.ShouldDeserializeAccessToken))));
await this.Helper.VonageClient.SimSwapClient
- .AuthenticateAsync(Vonage.SimSwap.Authenticate.AuthenticateRequest.Parse("447700900000"))
+ .AuthenticateAsync(AuthenticateRequest.Parse("447700900000",
+ "scope=openid dpv:FraudPreventionAndDetection#check-sim-swap"))
.Should()
.BeSuccessAsync(new AuthenticateResponse("ABCDEFG"));
}
diff --git a/Vonage/SimSwap/Authenticate/AuthenticateRequest.cs b/Vonage/SimSwap/Authenticate/AuthenticateRequest.cs
index 240a42fc..ae682eed 100644
--- a/Vonage/SimSwap/Authenticate/AuthenticateRequest.cs
+++ b/Vonage/SimSwap/Authenticate/AuthenticateRequest.cs
@@ -1,5 +1,6 @@
using Vonage.Common;
using Vonage.Common.Monads;
+using Vonage.Common.Validation;
namespace Vonage.SimSwap.Authenticate;
@@ -12,17 +13,29 @@ public readonly struct AuthenticateRequest
/// Parses the input into an AuthenticateRequest.
///
/// The phone number.
+ /// The authorization scope for the token.
/// Success if the input matches all requirements. Failure otherwise.
- public static Result Parse(string number) =>
+ public static Result Parse(string number, string tokenScope) =>
PhoneNumber.Parse(number).Map(phoneNumber => new AuthenticateRequest
- {
- PhoneNumber = phoneNumber,
- });
+ {
+ PhoneNumber = phoneNumber,
+ Scope = tokenScope,
+ })
+ .Map(InputEvaluation.Evaluate)
+ .Bind(evaluation => evaluation.WithRules(VerifyScope));
///
/// Subscriber number in E.164 format (starting with country code). Optionally prefixed with '+'.
///
public PhoneNumber PhoneNumber { get; private init; }
+ ///
+ /// The authorization scope for the token.
+ ///
+ public string Scope { get; private init; }
+
+ private static Result VerifyScope(AuthenticateRequest request) =>
+ InputValidation.VerifyNotEmpty(request, request.Scope, nameof(request.Scope));
+
internal AuthorizeRequest BuildAuthorizeRequest() => new AuthorizeRequest(this.PhoneNumber);
}
\ No newline at end of file
diff --git a/Vonage/SimSwap/Check/CheckRequest.cs b/Vonage/SimSwap/Check/CheckRequest.cs
index c0efdc2c..aee019c1 100644
--- a/Vonage/SimSwap/Check/CheckRequest.cs
+++ b/Vonage/SimSwap/Check/CheckRequest.cs
@@ -3,8 +3,10 @@
using System.Text.Json.Serialization;
using Vonage.Common;
using Vonage.Common.Client;
+using Vonage.Common.Monads;
using Vonage.Common.Serialization;
using Vonage.Serialization;
+using Vonage.SimSwap.Authenticate;
namespace Vonage.SimSwap.Check;
@@ -42,6 +44,15 @@ private StringContent GetRequestContent() =>
[JsonPropertyName("maxAge")]
public int Period { get; internal init; }
+ ///
+ /// The authorization scope for the token.
+ ///
+ [JsonIgnore]
+ public string Scope => "scope=openid dpv:FraudPreventionAndDetection#check-sim-swap";
+
+ internal Result BuildAuthenticationRequest() =>
+ AuthenticateRequest.Parse(this.PhoneNumber.NumberWithInternationalIndicator, this.Scope);
+
///
/// Initializes a builder.
///
diff --git a/Vonage/SimSwap/SimSwapClient.cs b/Vonage/SimSwap/SimSwapClient.cs
index a2329c36..d0adb260 100644
--- a/Vonage/SimSwap/SimSwapClient.cs
+++ b/Vonage/SimSwap/SimSwapClient.cs
@@ -37,8 +37,8 @@ private VonageHttpClient BuildClientWithAuthenticationHeader(AuthenticationHeade
private static AuthenticationHeaderValue BuildAuthenticationHeader(AuthenticateResponse authentication) =>
authentication.BuildAuthenticationHeader();
- private Task> AuthenticateCheckRequest(CheckRequest r) =>
- this.AuthenticateAsync(AuthenticateRequest.Parse(r.PhoneNumber.NumberWithInternationalIndicator));
+ private Task> AuthenticateCheckRequest(CheckRequest request) =>
+ this.AuthenticateAsync(request.BuildAuthenticationRequest());
private static AuthenticateResponse BuildAuthenticateResponse(GetTokenResponse response) =>
new AuthenticateResponse(response.AccessToken);