// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Newtonsoft.Json.Linq; using System; using System.Collections.Specialized; using System.Net.Http; using System.Threading.Tasks; using System.Web.Http.Controllers; using System.Xml.Linq; namespace Microsoft.AspNet.WebHooks { /// /// Provides an implementation which supports generic WebHooks /// containing valid JSON with no special validation logic or security requirements. This can for /// example be used to receive WebHooks from IFTTT's Maker Channel or a Zapier WebHooks Action. /// A sample WebHook URI is 'https://<host>/api/webhooks/incoming/genericjson/{id}?code=83699ec7c1d794c0c780e49a5c72972590571fd8'. /// For security reasons the WebHook URI must be an https URI and contain a 'code' query parameter with the /// same value as configured in the 'MS_WebHookReceiverSecret_GenericJson' application setting, optionally using IDs /// to differentiate between multiple WebHooks, for example 'secret0, id1=secret1, id2=secret2'. /// The 'code' parameter must be between 32 and 128 characters long. /// The URI may optionally include a 'action' query parameter which will serve as the WebHook action. /// public class SitecoreJsonWebHookReceiver : WebHookReceiver { internal const string RecName = "sitecorejson"; internal const string ActionQueryParameter = "action"; internal const string DefaultAction = "change"; /// /// Content type /// public static string ContentType; /// /// Gets the receiver name for this receiver. /// public static string ReceiverName { get { return RecName; } } /// public override string Name { get { return RecName; } } /// public override async Task ReceiveAsync(string id, HttpRequestContext context, HttpRequestMessage request) { if (id == null) { throw new ArgumentNullException(nameof(id)); } if (context == null) { throw new ArgumentNullException(nameof(context)); } if (request == null) { throw new ArgumentNullException(nameof(request)); } if (request.Method != HttpMethod.Post) { return CreateBadMethodResponse(request); } ContentType = request.Content.Headers.ContentType.MediaType.ToString(); // Ensure that we use https and have a valid code parameter await EnsureValidCode(request, id); // Get the action NameValueCollection queryParameters = request.RequestUri.ParseQueryString(); string action = queryParameters[ActionQueryParameter]; if (string.IsNullOrEmpty(action)) { action = DefaultAction; } JToken data=null; XElement xmldata = null; switch (ContentType) { case "application/json": // Read the request entity body data = await ReadAsJsonTokenAsync(request); // Call registered handlers return await ExecuteWebHookAsync(id, context, request, new[] { action }, data); case "application/xml": // Read the request entity body xmldata = await ReadAsXmlAsync(request); // Call registered handlers return await ExecuteWebHookAsync(id, context, request, new[] { action }, xmldata); default: return CreateBadMethodResponse(request); } } } }