Skip to content

Commit 9b0eadd

Browse files
committed
webhooks API & client
1 parent 38243a9 commit 9b0eadd

16 files changed

Lines changed: 161 additions & 36 deletions

docker-compose.override.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,6 @@ services:
397397

398398
webhooks.client:
399399
environment:
400-
- ASPNETCORE_ENVIRONMENT=Development
401400
- ASPNETCORE_URLS=http://0.0.0.0:80
402401
- Token=6168DB8D-DC58-4094-AF24-483278923590 # Webhooks are registered with this token (any value is valid) but the client won't check it
403402
- IdentityUrl=http://10.0.75.1:5105

src/Services/Webhooks/Webhooks.API/Controllers/WebhooksController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public async Task<IActionResult> ListByUser()
3838
}
3939

4040
[Authorize]
41-
[HttpGet("{id:int}", Name = "Get")]
41+
[HttpGet("{id:int}")]
4242
[ProducesResponseType(typeof(WebhookSubscription), (int)HttpStatusCode.OK)]
4343
[ProducesResponseType((int)HttpStatusCode.NotFound)]
4444
public async Task<IActionResult> GetByUserAndId(int id)
@@ -82,7 +82,7 @@ public async Task<IActionResult> SubscribeWebhook(WebhookSubscriptionRequest req
8282

8383
_dbContext.Add(subscription);
8484
await _dbContext.SaveChangesAsync();
85-
return CreatedAtAction("Get", new { id = subscription.Id });
85+
return CreatedAtAction("GetByUserAndId", new { id = subscription.Id }, subscription);
8686
}
8787
else
8888
{
Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using Microsoft.Extensions.Logging;
2+
using System;
23
using System.Collections.Generic;
34
using System.Linq;
45
using System.Net.Http;
@@ -9,19 +10,30 @@ namespace Webhooks.API.Services
910
class GrantUrlTesterService : IGrantUrlTesterService
1011
{
1112
private readonly IHttpClientFactory _clientFactory;
12-
public GrantUrlTesterService(IHttpClientFactory factory)
13+
private readonly ILogger _logger;
14+
public GrantUrlTesterService(IHttpClientFactory factory, ILogger<IGrantUrlTesterService> logger)
1315
{
1416
_clientFactory = factory;
17+
_logger = logger;
1518
}
1619

1720
public async Task<bool> TestGrantUrl(string url, string token)
1821
{
1922
var client = _clientFactory.CreateClient("GrantClient");
20-
2123
var msg = new HttpRequestMessage(HttpMethod.Options, url);
2224
msg.Headers.Add("X-eshop-whtoken", token);
23-
var response = await client.SendAsync(msg);
24-
return response.IsSuccessStatusCode;
25+
_logger.LogTrace($"Sending the OPTIONS message to {url} with token {token ?? string.Empty}");
26+
try
27+
{
28+
var response = await client.SendAsync(msg);
29+
_logger.LogInformation($"Response code is {response.StatusCode} for url {url}");
30+
return response.IsSuccessStatusCode;
31+
}
32+
catch (Exception ex)
33+
{
34+
_logger.LogWarning($"Exception {ex.GetType().Name} when sending OPTIONS request. Url can't be granted.");
35+
return false;
36+
}
2537
}
2638
}
2739
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
!wwwroot
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using Microsoft.AspNetCore.Http;
2+
using Microsoft.AspNetCore.Mvc;
3+
using Microsoft.Extensions.Options;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Threading.Tasks;
8+
using WebhookClient.Models;
9+
10+
namespace WebhookClient.Controllers
11+
{
12+
[ApiController]
13+
[Route("webhook-received")]
14+
public class WebhooksReceivedController : Controller
15+
{
16+
17+
private readonly Settings _settings;
18+
19+
public WebhooksReceivedController(IOptions<Settings> settings)
20+
{
21+
_settings = settings.Value;
22+
}
23+
24+
public IActionResult NewWebhook(WebhookData hook)
25+
{
26+
var header = Request.Headers[HeaderNames.WebHookCheckHeader];
27+
var token = header.FirstOrDefault();
28+
if (!_settings.ValidateToken || _settings.Token == token)
29+
{
30+
var received = HttpContext.Session.Get<IEnumerable<WebHookReceived>>(SessionKeys.HooksKey)?.ToList() ?? new List<WebHookReceived>();
31+
received.Add(new WebHookReceived()
32+
{
33+
Data = hook.Payload,
34+
When = hook.When,
35+
Token = token
36+
});
37+
return Ok();
38+
}
39+
40+
return BadRequest();
41+
}
42+
}
43+
}

src/Web/WebhookClient/Models/WebHookReceived.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ public class WebHookReceived
99
{
1010
public DateTime When { get; set; }
1111
public string Data { get; set; }
12+
13+
public string Token { get; set; }
1214
}
1315
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace WebhookClient.Models
7+
{
8+
public class WebhookData
9+
{
10+
public DateTime When { get; }
11+
12+
public string Payload { get; }
13+
14+
public string Type { get; }
15+
}
16+
}

src/Web/WebhookClient/Pages/Index.cshtml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,25 @@
77
<div class="text-center">
88
<h1 class="display-4">Welcome</h1>
99
<p>eShopOnContainers - Webhook client</p>
10-
<a class="btn-primary btn" href="@Url.Action("SignIn","Account")">Login</a>
11-
<p>Why I need to login? You only need to login <bold>to setup a new webhook</bold>.</p>
10+
@if (!User.Identity.IsAuthenticated)
11+
{
12+
<a class="btn-primary btn" href="@Url.Action("SignIn", "Account")">Login</a>
13+
<p>Why I need to login? You only need to login <bold>to setup a new webhook</bold>.</p>
14+
}
1215
</div>
1316

1417
@if (User.Identity.IsAuthenticated)
1518
{
16-
1719
<div class="table">
18-
<h3>Current webhooks invoked</h3>
20+
<h3>Current webhooks received</h3>
21+
<p>(Data since last time web started up)<p>
1922
<table class="table">
2023
@foreach (var webhook in Model.WebHooksReceived)
2124
{
2225
<tr>
2326
<td>@webhook.When</td>
2427
<td><pre>@webhook.Data</pre></td>
28+
<td>@(webhook.Token ?? "--None--")</td>
2529
</tr>
2630
}
2731
</table>

src/Web/WebhookClient/Pages/Index.cshtml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class IndexModel : PageModel
1717

1818
public void OnGet()
1919
{
20-
WebHooksReceived = HttpContext.Session.Get<IEnumerable<WebHookReceived>>("webhooks.received") ?? Enumerable.Empty<WebHookReceived>();
20+
WebHooksReceived = HttpContext.Session.Get<IEnumerable<WebHookReceived>>(SessionKeys.HooksKey) ?? Enumerable.Empty<WebHookReceived>();
2121
}
2222
}
2323
}

src/Web/WebhookClient/Pages/RegisterWebhook.cshtml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,9 @@
1111
<form method="post">
1212
<p>Token: <input type="text" asp-for="Token" /></p>
1313
<input type="submit" value="send" />
14-
</form>
14+
</form>
15+
16+
@if (Model.ResponseCode != (int)System.Net.HttpStatusCode.OK)
17+
{
18+
<p>Error @Model.ResponseCode (@Model.ResponseMessage) when calling the Webhooks API (@Model.RequestUrl) with GrantUrl: @Model.GrantUrl):(</p>
19+
}

0 commit comments

Comments
 (0)