Skip to content

Commit e835445

Browse files
committed
Merge branch 'feature/signed-urls'
# Conflicts: # CloudConvert.API/CloudConvertAPI.cs
2 parents f12f307 + 63aa0a1 commit e835445

3 files changed

Lines changed: 110 additions & 2 deletions

File tree

CloudConvert.API/CloudConvertAPI.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public interface ICloudConvertAPI
3434

3535
Task<string> UploadAsync(string url, byte[] file, string fileName, object parameters);
3636
bool ValidateWebhookSignatures(string payloadString, string signature, string signingSecret);
37+
string CreateSignedUrl(string baseUrl, string signingSecret, JobCreateRequest job, string cacheKey = null);
3738
}
3839

3940
public class CloudConvertAPI : ICloudConvertAPI
@@ -45,9 +46,10 @@ public class CloudConvertAPI : ICloudConvertAPI
4546
readonly string _api_key = "Bearer ";
4647
const string sandboxUrlApi = "https://api.sandbox.cloudconvert.com/v2";
4748
const string publicUrlApi = "https://api.cloudconvert.com/v2";
48-
4949
const string sandboxUrlSyncApi = "https://sync.api.sandbox.cloudconvert.com/v2";
5050
const string publicUrlSyncApi = "https://sync.api.cloudconvert.com/v2";
51+
static readonly char[] base64Padding = { '=' };
52+
5153

5254
public CloudConvertAPI(string api_key, bool isSandbox = false)
5355
{
@@ -212,6 +214,25 @@ private HttpRequestMessage GetMultipartFormDataRequest(string endpoint, HttpMeth
212214

213215
public Task<string> UploadAsync(string url, byte[] file, string fileName, object parameters) => _restHelper.RequestAsync(GetMultipartFormDataRequest($"{url}", HttpMethod.Post, file, fileName, GetParameters(parameters)));
214216

217+
public string CreateSignedUrl(string baseUrl, string signingSecret, JobCreateRequest job, string cacheKey = null)
218+
{
219+
string url = baseUrl;
220+
string jobJson = JsonConvert.SerializeObject(job);
221+
string base64Job = System.Convert.ToBase64String(Encoding.ASCII.GetBytes(jobJson)).TrimEnd(base64Padding).Replace('+', '-').Replace('/', '_');
222+
223+
url += "?job=" + base64Job;
224+
225+
if(cacheKey != null) {
226+
url += "&cache_key=" + cacheKey;
227+
}
228+
229+
string signature = HashHMAC(signingSecret, url);
230+
231+
url += "&s=" + signature;
232+
233+
return url;
234+
}
235+
215236
public bool ValidateWebhookSignatures(string payloadString, string signature, string signingSecret)
216237
{
217238
string hashHMAC = HashHMAC(signingSecret, payloadString);

CloudConvert.Test/TestSignedUrl.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
using CloudConvert.API;
3+
using CloudConvert.API.Models.JobModels;
4+
using CloudConvert.API.Models.TaskOperations;
5+
using CloudConvert.API.Models.ImportOperations;
6+
using CloudConvert.API.Models.ExportOperations;
7+
using NUnit.Framework;
8+
9+
10+
namespace CloudConvert.Test
11+
{
12+
public class TestSignedUrl
13+
{
14+
const string apiKey = "";
15+
readonly ICloudConvertAPI _cloudConvertAPI = new CloudConvertAPI(apiKey, true);
16+
17+
[Test]
18+
public void Sign()
19+
{
20+
21+
string baseUrl = "https://s.cloudconvert.com/b3d85428-584e-4639-bc11-76b7dee9c109";
22+
string signingSecret = "NT8dpJkttEyfSk3qlRgUJtvTkx64vhyX";
23+
string cacheKey = "mykey";
24+
25+
JobCreateRequest job = new JobCreateRequest
26+
{
27+
Tasks = new
28+
{
29+
import_example_1 = new ImportUploadCreateRequest(),
30+
convert = new ConvertCreateRequest
31+
{
32+
Input = "import_example_1",
33+
Input_Format = "pdf",
34+
Output_Format = "docx"
35+
},
36+
export = new ExportUrlCreateRequest
37+
{
38+
Input = "convert"
39+
}
40+
},
41+
42+
};
43+
44+
45+
string signedUrl = _cloudConvertAPI.CreateSignedUrl(baseUrl, signingSecret, job, cacheKey);
46+
47+
48+
StringAssert.StartsWith(baseUrl, signedUrl);
49+
StringAssert.Contains("?job=", signedUrl);
50+
StringAssert.Contains("&cache_key=mykey", signedUrl);
51+
StringAssert.Contains("&s=05521324eb16876aac906f2edc42a7ebfe6e71743e6cb965c4b3bf224c2b581f", signedUrl);
52+
53+
54+
}
55+
}
56+
}

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,38 @@ var isValid = _cloudConvertAPI.ValidateWebhookSignatures(payloadString, signatur
120120
// returns true or false
121121
```
122122

123-
## Using Sandbox
123+
## Signed URLs
124+
125+
Signed URLs allow converting files on demand only using URL query parameters. The .NET SDK allows to generate such URLs. Therefore, you need to obtain a signed URL base and a signing secret on the [CloudConvert Dashboard](https://cloudconvert.com/dashboard/api/v2/signed-urls).
126+
127+
```c#
128+
var signedUrlBase = 'https://s.cloudconvert.com/...'; // You can find it in your signed URL settings.
129+
var signingSecret = '...'; // You can find it in your signed URL settings.
130+
var cacheKey = 'cache-key'; // Allows caching of the result file for 24h
131+
132+
var job = new JobCreateRequest
133+
{
134+
Tasks = new
135+
{
136+
import_example_1 = new ImportUploadCreateRequest(),
137+
convert = new ConvertCreateRequest
138+
{
139+
Input = "import_example_1",
140+
Input_Format = "pdf",
141+
Output_Format = "docx"
142+
},
143+
export = new ExportUrlCreateRequest
144+
{
145+
Input = "convert"
146+
}
147+
},
148+
};
149+
150+
string signedUrl = _cloudConvertAPI.CreateSignedUrl(baseUrl, signingSecret, job, cacheKey)
151+
// returns the signed URL
152+
```
153+
154+
## Using the Sandbox
124155

125156
You can use the Sandbox to avoid consuming your quota while testing your application. The .net SDK allows you to do that.
126157

0 commit comments

Comments
 (0)