Skip to content

Commit

Permalink
feat: add uri validation on Voice GetRecording
Browse files Browse the repository at this point in the history
  • Loading branch information
Tr00d committed Feb 5, 2025
1 parent b0a7ec7 commit 240cf85
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 16 deletions.
22 changes: 20 additions & 2 deletions Vonage.Test/VoiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,17 +182,35 @@ await act.Should().ThrowExactlyAsync<VonageAuthenticationException>()
[Fact]
public async Task GetRecordingsAsync()
{
var expectedUri = this.fixture.Create<Uri>().ToString();
var expectedUri = "https://api.nexmo.com/v1/files/aaaaaaaa-bbbb-cccc-dddd-0123456789ab";
var expectedResponse = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
this.Setup(expectedUri, expectedResponse);
var response = await this.client.VoiceClient.GetRecordingAsync(expectedUri);
Assert.Equal(expectedResponse, response.ResultStream);
}

[Theory]
[InlineData("https://example.com/v1/abc123")]
[InlineData("http://api.sample.com/v1/abc123")]
public async Task GetRecordingsAsync_ShouldThrowException_GivenDomainIsRejected(string invalidUri)
{
var act = () => this.client.VoiceClient.GetRecordingAsync(invalidUri);
await act.Should().ThrowAsync<VonageException>().WithMessage("Invalid uri");
}

[Theory]
[InlineData("not a url")]
[InlineData("abc123")]
public async Task GetRecordingsAsync_ShouldThrowException_GivenUriIsInvalid(string invalidUri)
{
var act = () => this.client.VoiceClient.GetRecordingAsync(invalidUri);
await act.Should().ThrowAsync<VonageException>().WithMessage("Invalid uri");
}

[Fact]
public async Task GetRecordingsAsyncWithCredentials()
{
var expectedUri = this.fixture.Create<Uri>().ToString();
var expectedUri = "https://api.nexmo.com/v1/files/aaaaaaaa-bbbb-cccc-dddd-0123456789ab";
var expectedResponse = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
this.Setup(expectedUri, expectedResponse);
var response =
Expand Down
39 changes: 25 additions & 14 deletions Vonage/Voice/VoiceClient.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#region
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Vonage.Common;
using Vonage.Common.Exceptions;
using Vonage.Request;
#endregion

namespace Vonage.Voice;

Expand All @@ -14,7 +18,7 @@ public class VoiceClient : IVoiceClient
private readonly Configuration configuration;
private readonly Credentials credentials;
private readonly ITimeProvider timeProvider = new TimeProvider();

/// <summary>
/// Initializes a VoiceClient.
/// </summary>
Expand All @@ -24,14 +28,14 @@ public VoiceClient(Credentials credentials = null)
this.credentials = credentials;
this.configuration = Configuration.Instance;
}

internal VoiceClient(Credentials credentials, Configuration configuration, ITimeProvider timeProvider)
{
this.credentials = credentials;
this.configuration = configuration;
this.timeProvider = timeProvider;
}

/// <inheritdoc />
public Task<CallResponse> CreateCallAsync(CallCommand command, Credentials creds = null) =>
ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.timeProvider)
Expand All @@ -41,15 +45,15 @@ public Task<CallResponse> CreateCallAsync(CallCommand command, Credentials creds
command,
AuthType.Bearer
);

/// <inheritdoc />
public Task<CallRecord> GetCallAsync(string id, Credentials creds = null) =>
ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.timeProvider)
.DoGetRequestWithQueryParametersAsync<CallRecord>(
ApiRequest.GetBaseUri(ApiRequest.UriType.Api, this.configuration, $"{CallsEndpoint}/{id}"),
AuthType.Bearer
);

/// <inheritdoc />
public Task<PageResponse<CallList>> GetCallsAsync(CallSearchFilter filter, Credentials creds = null) =>
ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.timeProvider)
Expand All @@ -58,10 +62,17 @@ public Task<PageResponse<CallList>> GetCallsAsync(CallSearchFilter filter, Crede
AuthType.Bearer,
filter
);

/// <inheritdoc />
public async Task<GetRecordingResponse> GetRecordingAsync(string recordingUrl, Credentials creds = null)
{
var validHosts = new[] {"nexmo.com", "vonage.com"};
if (!Uri.TryCreate(recordingUrl, UriKind.Absolute, out var uri)
|| !validHosts.Any(host => uri.Host.EndsWith(host)))
{
throw new VonageException("Invalid uri");
}

using var response =
await ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.timeProvider)
.DoGetRequestWithJwtAsync(new Uri(recordingUrl)).ConfigureAwait(false);
Expand All @@ -71,7 +82,7 @@ await ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.time
Status = response.StatusCode,
};
}

/// <inheritdoc />
public Task<CallCommandResponse> StartDtmfAsync(string id, DtmfCommand cmd, Credentials creds = null) =>
ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.timeProvider)
Expand All @@ -81,7 +92,7 @@ public Task<CallCommandResponse> StartDtmfAsync(string id, DtmfCommand cmd, Cred
cmd,
AuthType.Bearer
);

/// <inheritdoc />
public Task<CallCommandResponse> StartStreamAsync(string id, StreamCommand command, Credentials creds = null) =>
ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.timeProvider)
Expand All @@ -91,7 +102,7 @@ public Task<CallCommandResponse> StartStreamAsync(string id, StreamCommand comma
command,
AuthType.Bearer
);

/// <inheritdoc />
public Task<CallCommandResponse> StartTalkAsync(string id, TalkCommand cmd, Credentials creds = null) =>
ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.timeProvider)
Expand All @@ -101,7 +112,7 @@ public Task<CallCommandResponse> StartTalkAsync(string id, TalkCommand cmd, Cred
cmd,
AuthType.Bearer
);

/// <inheritdoc />
public Task<CallCommandResponse> StopStreamAsync(string id, Credentials creds = null) =>
ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.timeProvider)
Expand All @@ -111,7 +122,7 @@ public Task<CallCommandResponse> StopStreamAsync(string id, Credentials creds =
new { },
AuthType.Bearer
);

/// <inheritdoc />
public Task<CallCommandResponse> StopTalkAsync(string id, Credentials creds = null) =>
ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.timeProvider)
Expand All @@ -121,7 +132,7 @@ public Task<CallCommandResponse> StopTalkAsync(string id, Credentials creds = nu
new { },
AuthType.Bearer
);

/// <inheritdoc />
public async Task<bool> UpdateCallAsync(string id, CallEditCommand command, Credentials creds = null)
{
Expand All @@ -134,9 +145,9 @@ await ApiRequest.Build(this.GetCredentials(creds), this.configuration, this.time
).ConfigureAwait(false);
return true;
}

private Credentials GetCredentials(Credentials overridenCredentials) => overridenCredentials ?? this.credentials;

private static async Task<byte[]> ReadContent(HttpContent content)
{
var readTask = await content.ReadAsStreamAsync().ConfigureAwait(false);
Expand Down

0 comments on commit 240cf85

Please sign in to comment.