-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathForwarderFunction.cs
More file actions
116 lines (96 loc) · 3.62 KB
/
ForwarderFunction.cs
File metadata and controls
116 lines (96 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
using System.Security.Cryptography;
using System.Net;
using System.Security.Claims;
using System.Text.Json;
using System.Text.Json.Serialization;
using Azure.Messaging.ServiceBus;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Configuration;
using System.Text;
using System.Collections.Concurrent;
namespace WebRequestServiceBusForwarder;
public class ForwarderFunction(IConfiguration configuration, ServiceBusSender sender)
{
private static readonly JsonSerializerOptions jsonSerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull | JsonIgnoreCondition.WhenWritingDefault,
};
[Function("ForwarderFunction")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, ["get", "post"], Route = "{*ignored}")] HttpRequestData req
)
{
var requestUri = req.Url;
var cookies = req.Cookies;
var headers = req.Headers;
var identities = req.Identities;
byte[]? body = null;
if (req.Body != Stream.Null)
{
if (req.Body is MemoryStream ms)
{
body = ms.ToArray();
}
else
{
using var memoryStream = new MemoryStream();
await req.Body.CopyToAsync(memoryStream);
body = memoryStream.ToArray();
}
}
if (headers.TryGetValues("x-xero-signature", out var results))
{
var path = req.Url.LocalPath[1..];
var signatureBytes = results.First();
using var sr = new StreamReader(new MemoryStream(body));
var payload = sr.ReadToEnd();
if (!_signingKeys.TryGetValue(path, out var signingKeyBytes))
{
var signingKey = configuration["XeroKeys:" + path];
//Xero requires everything be done in UTF-8
signingKeyBytes = Encoding.UTF8.GetBytes(signingKey);
_signingKeys.TryAdd(path, signingKeyBytes);
}
byte[] payloadBytes = Encoding.UTF8.GetBytes(payload);
var signature = Convert.ToBase64String(HMACSHA256.HashData(signingKeyBytes, payloadBytes));
if (signature != signatureBytes)
{
return req.CreateResponse(HttpStatusCode.Unauthorized);
}
}
var outputMessage = new OutputRequest()
{
RequestUri = requestUri,
Body = body
};
if (cookies != null)
{
outputMessage.Cookies = cookies;
}
if (headers != null)
{
outputMessage.Headers = headers;
}
if (identities != null)
{
outputMessage.Identities = identities;
}
var msg = new ServiceBusMessage(JsonSerializer.Serialize(outputMessage, jsonSerializerOptions));
msg.ApplicationProperties.Add("RequestUri", requestUri.ToString());
await sender.SendMessageAsync(msg);
var response = req.CreateResponse(HttpStatusCode.OK);
return response;
}
private static readonly ConcurrentDictionary<string, byte[]> _signingKeys = new();
}
public class OutputRequest
{
public Uri? RequestUri { get; init; }
public IReadOnlyCollection<IHttpCookie>? Cookies { get; internal set; }
public HttpHeadersCollection? Headers { get; internal set; }
public IEnumerable<ClaimsIdentity>? Identities { get; internal set; }
public byte[]? Body { get; internal set; }
}