Skip to content

Instantly share code, notes, and snippets.

@codingoutloud
Created March 25, 2018 19:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codingoutloud/e863bde7e53d777248bf4e87a34cee19 to your computer and use it in GitHub Desktop.
Save codingoutloud/e863bde7e53d777248bf4e87a34cee19 to your computer and use it in GitHub Desktop.
#r "Newtonsoft.Json"
using System.Net;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
#r "Newtonsoft.Json"
using System.Net;
using System.Net.Http;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public static async Task<string> GetUserAgentSummaryAsync(HttpRequest req, TraceWriter log)
{
const bool verbose = false;
var agents = req.Headers["User-Agent"];
if (verbose) log.Info($"AGENTS COUNT = {agents.Count}");
if (verbose) log.Info($"{agents}");
var agentjson = $"{{ \"user_agent\": \"{agents[0]}\" }}";
if (verbose) log.Info($"AGENT JSON = [{agentjson}]");
const string useragent_apikey_header = "X-API-KEY";
const string useragent_apikey_location = "HOSTHEADER_APIKEY";
var useragent_apikey = System.Environment.GetEnvironmentVariable(useragent_apikey_location); // CONFIGURE IN YOUR ENVIRONMENT
if (verbose) log.Info($"API KEY LENGTH = {useragent_apikey.Length}");
const string useragent_apiurl = "https://api.whatismybrowser.com/api/v2/user_agent_parse";
using (var httpClient = new HttpClient()) // okay for low-scale; else see https://docs.microsoft.com/en-us/azure/architecture/antipatterns/improper-instantiation/
{
var request = new HttpRequestMessage()
{
RequestUri = new Uri(useragent_apiurl),
Method = HttpMethod.Post,
Content = new StringContent(agentjson, Encoding.UTF8, "application/json")
};
request.Headers.Add(useragent_apikey_header, useragent_apikey);
// not needed, not harmful: request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (HttpResponseMessage response = await httpClient.SendAsync(request))
{
response.EnsureSuccessStatusCode(); // may throw
var result = await response.Content.ReadAsStringAsync();
if (verbose) log.Info($"RESULT = {result}");
if (verbose) log.Info($"AGENTS = {agents}");
var json = JObject.Parse(result);
bool parsedOk = ((string) (json["result"]["code"])) == "success";
bool is_abusive = (bool) (json["parse"]["is_abusive"]);
if (is_abusive || ! parsedOk)
{
throw new Exception($"Could not parse user agent ({parsedOk}) or was malformed ({is_abusive})");
}
var browser = (string) json["parse"]["software_name"];
var os = (string) json["parse"]["operating_system_name"];
var text = $"{browser} on {os}";
if (verbose) text = $"{text} [details: {result}]";
return text;
}
}
}
const bool format = true;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info("Handling CSP Report.");
//dynamic data = await req.Content.ReadAsAsync<object>();
var json = req.Content.ReadAsStringAsync().Result;
if (format) json = JValue.Parse(json).ToString(Formatting.Indented);
log.Info($"CSP REPORT payload (JSON):\n{json}");
var logicAppUrlBase = "https://prod-29.northcentralus.logic.azure.com:443";
var logicAppUrlParams = "/workflows/90485f53082e492e8c4e52d3aa2843cb/triggers/manual/paths/invoke?api-version=2016-10-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=7CdQoZUrRsWgyGtCZUZcraj6A518oMwovAk9FuIjbLo";
// ENRICH the usual CSP reporting JSON with User Agent, if it is available
string summaryUserAgent;
try
{
summaryUserAgent = await GetUserAgentSummaryAsync(req, log);
JObject report = JObject.Parse(json);
JObject channel = (JObject)report["csp-report"];
channel.Property("blocked-uri").AddBeforeSelf(new JProperty("user-agent-summary", summaryUserAgent));
}
catch (Exception ex)
{
; // continue
}
// TODO: figure out WHICH (whitelisted) Reporting endpoint posted the report
// forward to Logic App using above credendials
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(logicAppUrlBase);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var result = await client.PostAsync(logicAppUrlParams, content);
string resultContent = await result.Content.ReadAsStringAsync();
log.Info(resultContent);
if (result.IsSuccessStatusCode)
{
return req.CreateResponse(HttpStatusCode.OK);
}
else
{
return req.CreateResponse(HttpStatusCode.BadRequest,
"Failed while trying to forward to LA");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment