Skip to content

Commit 79b2882

Browse files
annahiletameihDS
andauthored
Added HMAC validate code example (#150)
* added HMAC validate code example * fixed pipeline * changed to use a var * added changes to manifest * Update CodeExamplesManifest.json fixed a typo removed a period updated title to "Validate HMAC signature" Signed-off-by: meihDS <[email protected]> --------- Signed-off-by: meihDS <[email protected]> Co-authored-by: meihDS <[email protected]>
1 parent 12ec3dd commit 79b2882

File tree

8 files changed

+210
-42
lines changed

8 files changed

+210
-42
lines changed

ExamplesApiTypeExtensions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ public enum ExamplesApiType
3737
/// </summary>
3838
[Description("aeg")]
3939
Admin = 4,
40+
41+
/// <summary>
42+
/// Connect API
43+
/// </summary>
44+
[Description("con")]
45+
Connect = 5,
4046
}
4147

4248
public static class ExamplesApiTypeExtensions
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// <copyright file="ValidateWebhookMessage.cs" company="DocuSign">
2+
// Copyright (c) DocuSign. All rights reserved.
3+
// </copyright>
4+
5+
namespace DocuSign.CodeExamples.Connect.Controllers
6+
{
7+
using DocuSign.CodeExamples.Common;
8+
using DocuSign.CodeExamples.Controllers;
9+
using DocuSign.CodeExamples.Models;
10+
using DocuSign.Connect.Examples;
11+
using Microsoft.AspNetCore.Mvc;
12+
13+
[Area("Connect")]
14+
[Route("con001")]
15+
public class ValidateWebhookMessage : EgController
16+
{
17+
public ValidateWebhookMessage(DsConfiguration config, LauncherTexts launcherTexts, IRequestItemsService requestItemsService)
18+
: base(config, launcherTexts, requestItemsService)
19+
{
20+
this.CodeExampleText = this.GetExampleText(this.EgName, ExamplesApiType.Connect);
21+
this.ViewBag.title = this.CodeExampleText.ExampleName;
22+
}
23+
24+
public override string EgName => "con001";
25+
26+
[SetViewBag]
27+
[HttpPost]
28+
[ValidateAntiForgeryToken]
29+
public ActionResult ValidateMessageUsing(string hmacSecret, string jsonPayload)
30+
{
31+
jsonPayload = jsonPayload.Replace("\\", string.Empty);
32+
33+
string hashedOutput = HMACValidation.ComputeHash(hmacSecret, jsonPayload);
34+
35+
this.ViewBag.h1 = this.CodeExampleText.ExampleName;
36+
this.ViewBag.message = this.CodeExampleText.ResultsPageText.Replace("{0}", hashedOutput);
37+
38+
return this.View("example_done");
39+
}
40+
}
41+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// <copyright file="HMACValidation.cs" company="DocuSign">
2+
// Copyright (c) DocuSign. All rights reserved.
3+
// </copyright>
4+
5+
namespace DocuSign.Connect.Examples
6+
{
7+
using System;
8+
using System.Security.Cryptography;
9+
using System.Text;
10+
11+
public static class HMACValidation
12+
{
13+
public static string ComputeHash(string secret, string payload)
14+
{
15+
byte[] bytes = Encoding.UTF8.GetBytes(secret);
16+
var hmac = new HMACSHA256(bytes);
17+
bytes = Encoding.UTF8.GetBytes(payload);
18+
19+
return Convert.ToBase64String(hmac.ComputeHash(bytes));
20+
}
21+
22+
public static bool HashIsValid(string secret, string payload, string verify)
23+
{
24+
ReadOnlySpan<byte> hashBytes = Convert.FromBase64String(ComputeHash(secret, payload));
25+
ReadOnlySpan<byte> verifyBytes = Convert.FromBase64String(verify);
26+
27+
return CryptographicOperations.FixedTimeEquals(hashBytes, verifyBytes);
28+
}
29+
}
30+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
@{
2+
int formNumber = 0;
3+
int hmacInputNumber = 0;
4+
int jsonInputNumber = 1;
5+
}
6+
7+
<h4>@Html.Raw(ViewBag.CodeExampleText.ExampleName)</h4>
8+
<p>
9+
@Html.Raw(ViewBag.CodeExampleText.ExampleDescription)
10+
</p>
11+
12+
<partial name="../../../Views/Shared/LinkToMethodView" model="ViewBag.CodeExampleText" />
13+
<p>
14+
@Html.Raw(
15+
@String.Format(
16+
ViewBag.SupportingTexts.ViewSourceFile,
17+
"<a target='_blank' href=" + @ViewBag.source + ">HmacSha256Encrypts.cs</a>"
18+
)
19+
)
20+
</p>
21+
22+
<p>
23+
<b>Prerequisites:</b> See <a href="https://developers.docusign.com/platform/webhooks/connect/validate/">How to validate a webhook message using HMAC</a>.
24+
</p>
25+
26+
<form class="eg" action="" method="post" data-busy="form">
27+
<div class="form-group" style="display: flex;">
28+
<label for="hmacSecret" style="width: 50%;">
29+
@Html.Raw(ViewBag.CodeExampleText.Forms[formNumber].Inputs[hmacInputNumber].InputName)
30+
</label>
31+
32+
<input type="text"
33+
class="form-control"
34+
id="hmacSecret"
35+
name="hmacSecret"
36+
required/>
37+
</div>
38+
<div class="form-group">
39+
<label for="jsonPayload">
40+
@Html.Raw(ViewBag.CodeExampleText.Forms[formNumber].Inputs[jsonInputNumber].InputName)
41+
</label>
42+
43+
<textarea
44+
rows="6"
45+
class="form-control"
46+
id="jsonPayload"
47+
name="jsonPayload"
48+
required ></textarea>
49+
</div>
50+
<input type="hidden" name="_csrf" value="@ViewBag.csrfToken">
51+
<button type="submit" class="btn btn-primary">@Html.Raw(ViewBag.SupportingTexts.SubmitButton)</button>
52+
</form>
53+

launcher-csharp/Views/Home/Index.cshtml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
: ((ApIs) api).Name.ToLower() == ExamplesApiType.Click.ToString().ToLower() ? ExamplesApiType.Click.ToKeywordString()
4343
: ((ApIs) api).Name.ToLower() == ExamplesApiType.Monitor.ToString().ToLower() ? ExamplesApiType.Monitor.ToKeywordString()
4444
: ((ApIs) api).Name.ToLower() == ExamplesApiType.Rooms.ToString().ToLower() ? ExamplesApiType.Rooms.ToKeywordString()
45+
: ((ApIs) api).Name.ToLower() == ExamplesApiType.Connect.ToString().ToLower() ? ExamplesApiType.Connect.ToKeywordString()
4546
: ExamplesApiType.Admin.ToKeywordString();
4647

4748
@foreach(var exampleGroup in api.Groups)
Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
1-
@model DocuSign.CodeExamples.ESignature.Models.CodeExampleText
1+
@using Microsoft.EntityFrameworkCore.Migrations
2+
@model DocuSign.CodeExamples.ESignature.Models.CodeExampleText
23
<p>
3-
@if(Model.LinksToApiMethod.Count == 1)
4+
@if (Model.LinksToApiMethod.Count != 0)
45
{
5-
<span>@Html.Raw(ViewBag.SupportingTexts.ApiMethodUsed)</span>
6-
}
7-
else
8-
{
9-
<span>@Html.Raw(ViewBag.SupportingTexts.ApiMethodUsedPlural)</span>
10-
}
11-
12-
@for(int i = 0; i < Model.LinksToApiMethod.Count; ++i)
13-
{
14-
<a target='_blank' href="@Model.LinksToApiMethod[i].Path">@Html.Raw(Model.LinksToApiMethod[i].PathName)</a>
15-
@if(i + 1 == Model.LinksToApiMethod.Count)
6+
@if (Model.LinksToApiMethod.Count == 1)
167
{
17-
<span></span>
8+
<span>@Html.Raw(ViewBag.SupportingTexts.ApiMethodUsed)</span>
189
}
19-
else if(i + 1 == Model.LinksToApiMethod.Count - 1)
10+
else
2011
{
21-
<span> and </span>
12+
<span>@Html.Raw(ViewBag.SupportingTexts.ApiMethodUsedPlural)</span>
2213
}
23-
else
14+
15+
@for (int i = 0; i < Model.LinksToApiMethod.Count; ++i)
2416
{
25-
<span>, </span>
17+
<a target='_blank' href="@Model.LinksToApiMethod[i].Path">@Html.Raw(Model.LinksToApiMethod[i].PathName)</a>
18+
@if (i + 1 == Model.LinksToApiMethod.Count)
19+
{
20+
<span></span>
21+
}
22+
else if (i + 1 == Model.LinksToApiMethod.Count - 1)
23+
{
24+
<span> and </span>
25+
}
26+
else
27+
{
28+
<span>, </span>
29+
}
2630
}
2731
}
2832
</p>

launcher-csharp/wwwroot/js/search.js

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
CLICK: 'click',
66
ROOMS: 'rooms',
77
ADMIN: 'admin',
8+
CONNECT: 'connect'
89
};
910

1011
let processJSONData = function () {
@@ -121,7 +122,9 @@
121122
case API_TYPES.MONITOR:
122123
return "meg";
123124
case API_TYPES.ESIGNATURE:
124-
return "eg"
125+
return "eg";
126+
case API_TYPES.CONNECT:
127+
return "con";
125128
}
126129
}
127130

@@ -156,33 +159,34 @@
156159
$("#filtered_code_examples").append("<p>" + example.ExampleDescription + "</p>");
157160

158161
$("#filtered_code_examples").append("<p>");
159-
160-
if (example.LinksToAPIMethod.length == 1) {
161-
$("#filtered_code_examples").append(processJSONData().SupportingTexts.APIMethodUsed);
162-
}
163-
else {
164-
$("#filtered_code_examples").append(processJSONData().SupportingTexts.APIMethodUsedPlural);
165-
}
166-
167-
for (let index = 0; index < example.LinksToAPIMethod.length; index++) {
168-
$("#filtered_code_examples").append(
169-
" <a target='_blank' href='"
170-
+ example.LinksToAPIMethod[index].Path
171-
+ "'>"
172-
+ example.LinksToAPIMethod[index].PathName
173-
+ "</a>"
174-
);
175-
176-
if (index + 1 === example.LinksToAPIMethod.length) {
177-
$("#filtered_code_examples").append("<span></span>");
178-
}
179-
else if (index + 1 === example.LinksToAPIMethod.length - 1) {
180-
$("#filtered_code_examples").append("<span> and </span>");
162+
if (example.LinksToAPIMethod.length !== 0) {
163+
if (example.LinksToAPIMethod.length == 1) {
164+
$("#filtered_code_examples").append(processJSONData().SupportingTexts.APIMethodUsed);
181165
}
182166
else {
183-
$("#filtered_code_examples").append("<span>, </span>");
167+
$("#filtered_code_examples").append(processJSONData().SupportingTexts.APIMethodUsedPlural);
184168
}
185169

170+
for (let index = 0; index < example.LinksToAPIMethod.length; index++) {
171+
$("#filtered_code_examples").append(
172+
" <a target='_blank' href='"
173+
+ example.LinksToAPIMethod[index].Path
174+
+ "'>"
175+
+ example.LinksToAPIMethod[index].PathName
176+
+ "</a>"
177+
);
178+
179+
if (index + 1 === example.LinksToAPIMethod.length) {
180+
$("#filtered_code_examples").append("<span></span>");
181+
}
182+
else if (index + 1 === example.LinksToAPIMethod.length - 1) {
183+
$("#filtered_code_examples").append("<span> and </span>");
184+
}
185+
else {
186+
$("#filtered_code_examples").append("<span>, </span>");
187+
}
188+
189+
}
186190
}
187191

188192
$("#filtered_code_examples").append("</p> ");

manifest/CodeExamplesManifest.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2588,6 +2588,35 @@
25882588
]
25892589
}
25902590
]
2591+
},
2592+
{
2593+
"Name": "Connect",
2594+
"Groups": [
2595+
{
2596+
"Name": "Connect examples",
2597+
"Examples": [
2598+
{
2599+
"ExampleNumber": 1,
2600+
"ExampleName": "Validate HMAC signature",
2601+
"ExampleDescription": "Demonstrates an example workflow for a client app receiving and validating a webhook (DocuSign Connect) message using HMAC security.",
2602+
"Forms": [
2603+
{
2604+
"Inputs": [
2605+
{
2606+
"InputName": "HMAC secret"
2607+
},
2608+
{
2609+
"InputName": "Plain text JSON payload"
2610+
}
2611+
]
2612+
}
2613+
],
2614+
"ResultsPageText": "This value should match the value of your x-docusign-signature header: <br/>HMAC signature {0}",
2615+
"SkipForLanguages": "bash;powershell;ruby;java;php;python;node"
2616+
}
2617+
]
2618+
}
2619+
]
25912620
}
25922621
]
25932622
}

0 commit comments

Comments
 (0)