From bb1bf371be5f18f647f528832327d11464a8e5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20BIAUDET?= Date: Tue, 1 Sep 2020 21:46:07 +0200 Subject: [PATCH 1/5] Create Intercom WebHook --- .../yarn.lock | 234 +----------------- src/WebHooks/WebHooks.sln | 7 + .../IntercomMvcBuilderExtensions.cs | 41 +++ .../IntercomMvcCoreBuilderExtensions.cs | 43 ++++ .../IntercomServiceCollectionSetup.cs | 31 +++ .../Filters/IntercomVerifySignatureFilter.cs | 148 +++++++++++ .../IntercomConstants.cs | 42 ++++ .../IntercomWebHookAttribute.cs | 18 ++ .../Metadata/IntercomMetadata.cs | 58 +++++ ...NetCore.WebHooks.Receivers.Intercom.csproj | 16 ++ .../Properties/AssemblyInfo.cs | 5 + .../Properties/Resources.Designer.cs | 81 ++++++ .../Properties/Resources.resx | 126 ++++++++++ 13 files changed, 628 insertions(+), 222 deletions(-) create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomMvcBuilderExtensions.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomMvcCoreBuilderExtensions.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomServiceCollectionSetup.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Filters/IntercomVerifySignatureFilter.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomConstants.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomWebHookAttribute.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Metadata/IntercomMetadata.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Microsoft.AspNetCore.WebHooks.Receivers.Intercom.csproj create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/AssemblyInfo.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.Designer.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.resx diff --git a/src/ComponentsElectron/src/Microsoft.AspNetCore.Components.Electron.JS/yarn.lock b/src/ComponentsElectron/src/Microsoft.AspNetCore.Components.Electron.JS/yarn.lock index 511528405..58604a6bf 100644 --- a/src/ComponentsElectron/src/Microsoft.AspNetCore.Components.Electron.JS/yarn.lock +++ b/src/ComponentsElectron/src/Microsoft.AspNetCore.Components.Electron.JS/yarn.lock @@ -178,11 +178,6 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - acorn@^6.2.1: version "6.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" @@ -213,11 +208,6 @@ ansi-regex@^2.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -238,19 +228,11 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -aproba@^1.0.3, aproba@^1.1.1: +aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -702,11 +684,6 @@ console-browserify@^1.1.0: resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= - constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -819,7 +796,7 @@ debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@^3.0.0, debug@^3.2.6: +debug@^3.0.0: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -868,11 +845,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - des.js@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" @@ -886,11 +858,6 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -1266,13 +1233,6 @@ fs-extra@^4.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-minipass@^1.2.5: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" @@ -1296,20 +1256,6 @@ fsevents@^1.2.7: bindings "^1.5.0" nan "^2.12.1" -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - get-caller-file@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -1418,11 +1364,6 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -1505,13 +1446,6 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -iconv-lite@^0.4.4: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - ieee754@^1.1.4: version "1.1.13" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" @@ -1522,13 +1456,6 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -ignore-walk@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" - integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== - dependencies: - minimatch "^3.0.4" - import-local@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" @@ -2069,21 +1996,6 @@ minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.3.tgz#3db5c0765545ab8637be71f333a104a965a9ca3f" integrity sha512-+bMdgqjMN/Z77a6NlY/I3U5LlRDbnmaAk6lDveAPKwSpcPM4tKAuYsvYF8xjhOPXhOYGe/73vVLVez5PW+jqhw== -minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - mississippi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" @@ -2108,7 +2020,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: +mkdirp@0.5.1, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -2159,15 +2071,6 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" -needle@^2.2.1: - version "2.3.3" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.3.tgz#a041ad1d04a871b0ebb666f40baaf1fb47867117" - integrity sha512-EkY0GeSq87rWp1hoq/sH/wnTWgFVhYlnIkbJ0YJFfRgEFlz2RraCjBpFQ+vrEgEdp0ThfyHADmkChEhcb7PKyw== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - neo-async@^2.5.0, neo-async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" @@ -2207,30 +2110,6 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pre-gyp@*: - version "0.14.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" - integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4.4.2" - -nopt@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" - integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== - dependencies: - abbrev "1" - osenv "^0.1.4" - normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -2253,27 +2132,6 @@ normalize-path@^3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -npm-bundled@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" - integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== - dependencies: - npm-normalize-package-bin "^1.0.1" - -npm-normalize-package-bin@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" - integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== - -npm-packlist@^1.1.6: - version "1.4.8" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" - integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - npm-normalize-package-bin "^1.0.1" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -2281,16 +2139,6 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - nugget@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0" @@ -2314,7 +2162,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -2359,11 +2207,6 @@ os-browserify@^0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= - os-locale@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" @@ -2373,19 +2216,6 @@ os-locale@^3.1.0: lcid "^2.0.0" mem "^4.0.0" -os-tmpdir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" @@ -2687,7 +2517,7 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -rc@^1.2.1, rc@^1.2.7: +rc@^1.2.1: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -2714,7 +2544,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -2857,7 +2687,7 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: +rimraf@^2.5.4, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -2896,16 +2726,11 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - schema-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" @@ -2915,7 +2740,7 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -2925,7 +2750,7 @@ serialize-javascript@^2.1.2: resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== -set-blocking@^2.0.0, set-blocking@~2.0.0: +set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= @@ -3155,14 +2980,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -3191,20 +3008,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: +strip-ansi@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -3267,19 +3077,6 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tar@^4.4.2: - version "4.4.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" - integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.8.6" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" - terser-webpack-plugin@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" @@ -3630,13 +3427,6 @@ which@^1.2.14, which@^1.2.9, which@^1.3.1: dependencies: isexe "^2.0.0" -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - worker-farm@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" @@ -3675,7 +3465,7 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: +yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== diff --git a/src/WebHooks/WebHooks.sln b/src/WebHooks/WebHooks.sln index 6df629902..6f74b779a 100644 --- a/src/WebHooks/WebHooks.sln +++ b/src/WebHooks/WebHooks.sln @@ -99,6 +99,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrelloCoreReceiver", "sampl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebHooks.FunctionalTest", "test\Microsoft.AspNetCore.WebHooks.FunctionalTest\Microsoft.AspNetCore.WebHooks.FunctionalTest.csproj", "{F42E56B7-60D4-481A-8585-04015B2B501E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.WebHooks.Receivers.Intercom", "src\Microsoft.AspNetCore.WebHooks.Receivers.Intercom\Microsoft.AspNetCore.WebHooks.Receivers.Intercom.csproj", "{920467E5-A7BD-4425-967E-32D9F411DE6C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -249,6 +251,10 @@ Global {F42E56B7-60D4-481A-8585-04015B2B501E}.Debug|Any CPU.Build.0 = Debug|Any CPU {F42E56B7-60D4-481A-8585-04015B2B501E}.Release|Any CPU.ActiveCfg = Release|Any CPU {F42E56B7-60D4-481A-8585-04015B2B501E}.Release|Any CPU.Build.0 = Release|Any CPU + {920467E5-A7BD-4425-967E-32D9F411DE6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {920467E5-A7BD-4425-967E-32D9F411DE6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {920467E5-A7BD-4425-967E-32D9F411DE6C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {920467E5-A7BD-4425-967E-32D9F411DE6C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -290,6 +296,7 @@ Global {91E02D64-BA6E-473C-A250-D1051A50DDAB} = {9575CB90-BC4B-43BB-8AEA-82C53FDA4187} {E9E37253-3FE1-44A4-A9E7-A2B6C54EECFE} = {E957C8D9-B4A0-488B-838F-BAB4DE080A76} {F42E56B7-60D4-481A-8585-04015B2B501E} = {9575CB90-BC4B-43BB-8AEA-82C53FDA4187} + {920467E5-A7BD-4425-967E-32D9F411DE6C} = {929F44D0-A040-4DC3-A22F-4C5829C05D44} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {12CE6238-F847-4984-8622-1ED46072150A} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomMvcBuilderExtensions.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomMvcBuilderExtensions.cs new file mode 100644 index 000000000..1c96718d0 --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomMvcBuilderExtensions.cs @@ -0,0 +1,41 @@ +// 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 System; +using System.ComponentModel; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// Extension methods for setting up Intercom WebHooks in an . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class IntercomMvcBuilderExtensions + { + /// + /// + /// Add Intercom WebHook configuration and services to the specified . See + /// for additional details about Intercom WebHook requests. + /// + /// + /// The 'WebHooks:Intercom:SecretKey:default' configuration value contains the secret key for Intercom + /// WebHook URIs of the form 'https://{host}/api/webhooks/incoming/intercom'. + /// 'WebHooks:Intercom:SecretKey:{id}' configuration values contain secret keys for Intercom WebHook URIs of + /// the form 'https://{host}/api/webhooks/incoming/intercom/{id}'. + /// + /// + /// The to configure. + /// The . + public static IMvcBuilder AddIntercomWebHooks(this IMvcBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + IntercomServiceCollectionSetup.AddIntercomServices(builder.Services); + + return builder.AddWebHooks(); + } + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomMvcCoreBuilderExtensions.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomMvcCoreBuilderExtensions.cs new file mode 100644 index 000000000..6c0f19177 --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomMvcCoreBuilderExtensions.cs @@ -0,0 +1,43 @@ +// 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 System; +using System.ComponentModel; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// Extension methods for setting up Intercom WebHooks in an . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class IntercomMvcCoreBuilderExtensions + { + /// + /// + /// Add Intercom WebHook configuration and services to the specified . See + /// for additional details about Intercom WebHook requests. + /// + /// + /// The 'WebHooks:Intercom:SecretKey:default' configuration value contains the secret key for Intercom + /// WebHook URIs of the form 'https://{host}/api/webhooks/incoming/intercom'. + /// 'WebHooks:Intercom:SecretKey:{id}' configuration values contain secret keys for Intercom WebHook URIs of + /// the form 'https://{host}/api/webhooks/incoming/intercom/{id}'. + /// + /// + /// The to configure. + /// The . + public static IMvcCoreBuilder AddIntercomWebHooks(this IMvcCoreBuilder builder) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + IntercomServiceCollectionSetup.AddIntercomServices(builder.Services); + + return builder + .AddJsonFormatters() + .AddWebHooks(); + } + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomServiceCollectionSetup.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomServiceCollectionSetup.cs new file mode 100644 index 000000000..91c0c20bf --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Extensions/IntercomServiceCollectionSetup.cs @@ -0,0 +1,31 @@ +// 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 System; +using Microsoft.AspNetCore.WebHooks.Filters; +using Microsoft.AspNetCore.WebHooks.Metadata; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// Methods to add services for the GitHub receiver. + /// + internal static class IntercomServiceCollectionSetup + { + /// + /// Add services for the Intercom receiver. + /// + /// The to update. + public static void AddIntercomServices(IServiceCollection services) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + WebHookMetadata.Register(services); + services.TryAddSingleton(); + } + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Filters/IntercomVerifySignatureFilter.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Filters/IntercomVerifySignatureFilter.cs new file mode 100644 index 000000000..84fbc71b9 --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Filters/IntercomVerifySignatureFilter.cs @@ -0,0 +1,148 @@ +// 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 System; +using System.Globalization; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.WebHooks.Properties; +using Microsoft.AspNetCore.WebHooks.Utilities; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNetCore.WebHooks.Filters +{ + /// + /// An that verifies the Intercom signature header. Confirms the header exists, + /// reads Body bytes, and compares the hashes. + /// + public class IntercomVerifySignatureFilter : WebHookVerifySignatureFilter, IAsyncResourceFilter + { + // Character that appears between the key and value in the signature header. + private static readonly char[] PairSeparators = new[] { '=' }; + + /// + /// Instantiates a new instance. + /// + /// + /// The used to initialize . + /// + /// + /// The used to initialize + /// . + /// + /// + /// The used to initialize . + /// + public IntercomVerifySignatureFilter( + IConfiguration configuration, + IHostingEnvironment hostingEnvironment, + ILoggerFactory loggerFactory) + : base(configuration, hostingEnvironment, loggerFactory) + { + } + + /// + public override string ReceiverName => IntercomConstants.ReceiverName; + + /// + public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + if (next == null) + { + throw new ArgumentNullException(nameof(next)); + } + + var request = context.HttpContext.Request; + if (HttpMethods.IsPost(request.Method)) + { + // 1. Confirm a secure connection. + var errorResult = EnsureSecureConnection(ReceiverName, context.HttpContext.Request); + if (errorResult != null) + { + context.Result = errorResult; + return; + } + + // 2. Get the expected hash from the signature header. + var header = GetRequestHeader(request, IntercomConstants.SignatureHeaderName, out errorResult); + if (errorResult != null) + { + context.Result = errorResult; + return; + } + + var values = new TrimmingTokenizer(header, PairSeparators); + var enumerator = values.GetEnumerator(); + enumerator.MoveNext(); + var headerKey = enumerator.Current; + if (values.Count != 2 || + !StringSegment.Equals( + headerKey, + IntercomConstants.SignatureHeaderKey, + StringComparison.OrdinalIgnoreCase)) + { + Logger.LogWarning( + 0, + $"Invalid '{IntercomConstants.SignatureHeaderName}' header value. Expecting a value of " + + $"'{IntercomConstants.SignatureHeaderKey}='."); + + var message = string.Format( + CultureInfo.CurrentCulture, + Resources.SignatureFilter_BadHeaderValue, + IntercomConstants.SignatureHeaderName, + IntercomConstants.SignatureHeaderKey, + ""); + errorResult = new BadRequestObjectResult(message); + + context.Result = errorResult; + return; + } + + enumerator.MoveNext(); + var headerValue = enumerator.Current.Value; + + var expectedHash = FromHex(headerValue, IntercomConstants.SignatureHeaderName); + if (expectedHash == null) + { + context.Result = CreateBadHexEncodingResult(IntercomConstants.SignatureHeaderKey); + return; + } + + // 3. Get the configured secret key. + var secretKey = GetSecretKey(ReceiverName, context.RouteData, IntercomConstants.SecretKeyMinLength); + if (secretKey == null) + { + context.Result = new NotFoundResult(); + return; + } + + var secret = Encoding.UTF8.GetBytes(secretKey); + + // 4. Get the actual hash of the request body. + var actualHash = await ComputeRequestBodySha1HashAsync(request, secret); + + // 5. Verify that the actual hash matches the expected hash. + if (!SecretEqual(expectedHash, actualHash)) + { + // Log about the issue and short-circuit remainder of the pipeline. + errorResult = CreateBadSignatureResult(IntercomConstants.SignatureHeaderName); + + context.Result = errorResult; + return; + } + } + + await next(); + } + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomConstants.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomConstants.cs new file mode 100644 index 000000000..9d265f83f --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomConstants.cs @@ -0,0 +1,42 @@ +// 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. + +namespace Microsoft.AspNetCore.WebHooks +{ + /// + /// Well-known names and values used in Intercom receivers and handlers. + /// + public static class IntercomConstants + { + /// + /// Gets the name of the Intercom WebHook receiver. + /// + public static string ReceiverName => "intercom"; + + /// + /// Gets the name of the header containing the Intercom event name e.g. ping or push. + /// + public static string EventHeaderName => "X-Github-Event"; + + /// + /// Gets the name of the Intercom ping event. + /// + public static string PingEventName => "ping"; + + /// + /// Gets the minimum length of the secret key configured for this receiver. + /// + public static int SecretKeyMinLength => 16; + + /// + /// Gets the key of the hex-encoded signature in the value. + /// + public static string SignatureHeaderKey => "sha1"; + + /// + /// Gets the name of the HTTP header containing key / value pairs, including the (hex-encoded) signature of the + /// request. + /// + public static string SignatureHeaderName => "X-Hub-Signature"; + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomWebHookAttribute.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomWebHookAttribute.cs new file mode 100644 index 000000000..6285d48dd --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomWebHookAttribute.cs @@ -0,0 +1,18 @@ +using System; +using Microsoft.AspNetCore.WebHooks; + +namespace Microsoft.AspNetCore.WebHooks +{ + public class IntercomWebHookAttribute : WebHookAttribute + { + /// + /// Instantiates a new instance indicating the associated action is a + /// Intercom WebHook endpoint. + /// + public IntercomWebHookAttribute() + : base(IntercomConstants.ReceiverName) + { + } + + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Metadata/IntercomMetadata.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Metadata/IntercomMetadata.cs new file mode 100644 index 000000000..53c3ac4cb --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Metadata/IntercomMetadata.cs @@ -0,0 +1,58 @@ +// 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 Microsoft.AspNetCore.WebHooks.Filters; + +namespace Microsoft.AspNetCore.WebHooks.Metadata +{ + /// + /// An service containing metadata about the GitHub receiver. + /// + public class IntercomMetadata : + WebHookMetadata, + IWebHookEventMetadata, + IWebHookFilterMetadata, + IWebHookPingRequestMetadata + { + private readonly IntercomVerifySignatureFilter _verifySignatureFilter; + + /// + /// Instantiates a new instance. + /// + /// The . + public IntercomMetadata(IntercomVerifySignatureFilter verifySignatureFilter) + : base(IntercomConstants.ReceiverName) + { + _verifySignatureFilter = verifySignatureFilter; + } + + // IWebHookBodyTypeMetadataService... + + /// + public override WebHookBodyType BodyType => WebHookBodyType.Json; + + // IWebHookEventMetadata... + + /// + public string ConstantValue => null; + + /// + public string HeaderName => IntercomConstants.EventHeaderName; + + /// + public string QueryParameterName => null; + + // IWebHookPingRequestMetadata... + + /// + public string PingEventName => IntercomConstants.PingEventName; + + // IWebHookFilterMetadata... + + /// + public void AddFilters(WebHookFilterMetadataContext context) + { + context.Results.Add(_verifySignatureFilter); + } + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Microsoft.AspNetCore.WebHooks.Receivers.Intercom.csproj b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Microsoft.AspNetCore.WebHooks.Receivers.Intercom.csproj new file mode 100644 index 000000000..e340aff49 --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Microsoft.AspNetCore.WebHooks.Receivers.Intercom.csproj @@ -0,0 +1,16 @@ + + + + ASP.NET Core Intercom WebHooks infrastructure. Contains the IntercomWebHookAttribute class and AddIntercomWebHooks method. + aspnetcore;webhook;receiver;intercom + + + + + Utilities\TrimmingTokenizer.cs + + + + + + diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/AssemblyInfo.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0676e6507 --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/AssemblyInfo.cs @@ -0,0 +1,5 @@ +// 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 System.Runtime.CompilerServices; + diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.Designer.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.Designer.cs new file mode 100644 index 000000000..d1f2eb8b1 --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.Designer.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.AspNetCore.WebHooks.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNetCore.WebHooks.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Value cannot be null or empty.. + /// + internal static string General_ArgumentCannotBeNullOrEmpty { + get { + return ResourceManager.GetString("General_ArgumentCannotBeNullOrEmpty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid '{0}' header value. Expecting a value of '{1}={2}'.. + /// + internal static string SignatureFilter_BadHeaderValue { + get { + return ResourceManager.GetString("SignatureFilter_BadHeaderValue", resourceCulture); + } + } + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.resx b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.resx new file mode 100644 index 000000000..601992ca4 --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Value cannot be null or empty. + + + Invalid '{0}' header value. Expecting a value of '{1}={2}'. + + \ No newline at end of file From 41b83f749da029ce6b1aaedcea6f35eed4e47c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20BIAUDET?= Date: Tue, 1 Sep 2020 22:18:43 +0200 Subject: [PATCH 2/5] Add Intercom Notification Data --- .../IntercomNotification.cs | 68 +++++++++++ .../IntercomNotificationData.cs | 21 ++++ .../ModelBinding/UnixTimeConverter.cs | 112 ++++++++++++++++++ .../Properties/Resources.Designer.cs | 18 +++ .../Properties/Resources.resx | 62 +++++----- 5 files changed, 253 insertions(+), 28 deletions(-) create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotification.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotificationData.cs create mode 100644 src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/ModelBinding/UnixTimeConverter.cs diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotification.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotification.cs new file mode 100644 index 000000000..f5063c67c --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotification.cs @@ -0,0 +1,68 @@ +// 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 System.Collections.Generic; +using System; +using Newtonsoft.Json; +using Microsoft.AspNetCore.WebHooks.ModelBinding; + +namespace Microsoft.AspNetCore.WebHooks +{ + /// + /// Contains information sent in a WebHook notification from Intercom. + /// + public class IntercomNotification + { + private readonly IDictionary _properties = new Dictionary(); + + /// + /// Gets or sets the type of notification. Value is 'notification_event'. + /// + [JsonProperty("type", Required = Required.Always)] + public string Type { get; set; } + + /// + /// Gets or sets the notification id. + /// + [JsonProperty("id", Required = Required.Always)] + public string Id { get; set; } + + /// + /// Gets or sets the Intercom defined URL for the subscription + /// + [JsonProperty("self")] + public string Self { get; set; } + + /// + /// Gets or sets the time the notification was created. + /// + [JsonConverter(typeof(UnixTimeConverter))] + [JsonProperty("created_at", Required = Required.Always)] + public DateTime CreatedAt { get; set; } + + /// + /// Gets or sets the topic + /// + [JsonProperty("topic", Required = Required.Always)] + public string Topic { get; set; } + + /// + /// Gets or sets the number of times this notification has been attempted. + /// + [JsonProperty("delivery_attempts", Required = Required.Always)] + public int DeliveryAttempts { get; set; } + + /// + /// Gets or sets the first time the delivery was attempted. + /// + [JsonConverter(typeof(UnixTimeConverter))] + [JsonProperty("first_sent_at", Required = Required.Always)] + public DateTime FirstSentAt { get; set; } + + /// + /// Gets or sets the data associated with the notification. + /// + [JsonProperty("data", Required = Required.Always)] + public IntercomNotificationData Data { get; set; } + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotificationData.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotificationData.cs new file mode 100644 index 000000000..4a18c13e3 --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotificationData.cs @@ -0,0 +1,21 @@ +// 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 System.Collections.Generic; +using Newtonsoft.Json; + +namespace Microsoft.AspNetCore.WebHooks +{ + /// + /// A container for the data associated with the notification. + /// + public class IntercomNotificationData + { + + /// + /// Gets or sets the data associated with the notification, which will have a 'type' field. + /// + [JsonProperty("item", Required = Required.Always)] + public object Item { get; set; } + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/ModelBinding/UnixTimeConverter.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/ModelBinding/UnixTimeConverter.cs new file mode 100644 index 000000000..6168e9171 --- /dev/null +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/ModelBinding/UnixTimeConverter.cs @@ -0,0 +1,112 @@ +// 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 System; +using System.Globalization; +using Microsoft.AspNetCore.WebHooks.Properties; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Microsoft.AspNetCore.WebHooks.ModelBinding +{ + /// + /// Converts a Unix time stamp string or integer value to and from a . By default, the + /// gets serialized to an integer. + /// + public class UnixTimeConverter : DateTimeConverterBase + { + private static readonly DateTime _Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + private readonly bool _stringConverter; + + /// + /// Instantiates a new instance. + /// + public UnixTimeConverter() + : this(false) + { + } + + /// + /// Instantiates a new instance. + /// + /// + /// When only deserializes string values and serializes to a string value; + /// otherwise deserializes string and integer values and serializes to an integer value. + /// + protected UnixTimeConverter(bool stringConverter) + { + _stringConverter = stringConverter; + } + + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (writer == null) + { + throw new ArgumentNullException(nameof(writer)); + } + + var utc = ((DateTime)value).ToUniversalTime(); + var time = (long)(utc - _Epoch).TotalSeconds; + if (_stringConverter) + { + writer.WriteValue(time.ToString(CultureInfo.InvariantCulture)); + } + else + { + writer.WriteValue(time); + } + } + + /// + public override object ReadJson( + JsonReader reader, + Type objectType, + object existingValue, + JsonSerializer serializer) + { + if (reader == null) + { + throw new ArgumentNullException(nameof(reader)); + } + if (reader.Value == null) + { + var message = string.Format( + CultureInfo.CurrentCulture, + Resources.DateTime_NullError, + typeof(DateTime)); + throw new InvalidOperationException(message); + } + + long time = 0; + if (reader.TokenType == JsonToken.String || _stringConverter) + { + if (!long.TryParse(reader.Value as string, out time)) + { + var message = string.Format( + CultureInfo.CurrentCulture, + Resources.DateTime_BadFormat, + reader.Value, + typeof(DateTime)); + throw new InvalidOperationException(message); + } + } + else if (reader.TokenType == JsonToken.Integer) + { + time = Convert.ToInt64(reader.Value, CultureInfo.InvariantCulture); + } + else + { + var message = string.Format( + CultureInfo.CurrentCulture, + Resources.DateTime_BadFormat, + reader.Value, + typeof(DateTime)); + throw new InvalidOperationException(message); + } + + var utc = _Epoch.AddSeconds(time); + return utc; + } + } +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.Designer.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.Designer.cs index d1f2eb8b1..5f6396ab8 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.Designer.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.Designer.cs @@ -60,6 +60,24 @@ internal Resources() { } } + /// + /// Looks up a localized string similar to Cannot read value '{0}' as type '{1}'.. + /// + internal static string DateTime_BadFormat { + get { + return ResourceManager.GetString("DateTime_BadFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cannot convert null value to type '{0}'.. + /// + internal static string DateTime_NullError { + get { + return ResourceManager.GetString("DateTime_NullError", resourceCulture); + } + } + /// /// Looks up a localized string similar to Value cannot be null or empty.. /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.resx b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.resx index 601992ca4..44a279f55 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.resx +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Properties/Resources.resx @@ -1,17 +1,17 @@  - @@ -117,10 +117,16 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Cannot read value '{0}' as type '{1}'. + + + Cannot convert null value to type '{0}'. + Value cannot be null or empty. Invalid '{0}' header value. Expecting a value of '{1}={2}'. - \ No newline at end of file + From 6a5e9afe7fd9947e6a5ce0b92396866a42394026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20BIAUDET?= Date: Wed, 2 Sep 2020 22:29:49 +0200 Subject: [PATCH 3/5] Fix IDE0016 Null check can be simplified warning --- .../SalesforceNotificationsModelBinder.cs | 7 +---- .../SalesforceNotifications.cs | 6 +---- .../SlackAttachment.cs | 24 +++-------------- .../SlackField.cs | 24 +++-------------- .../SlackResponse.cs | 12 ++------- .../SlackSlashResponse.cs | 12 ++------- .../Filters/WebHookEventNameMapperFilter.cs | 26 +++---------------- .../Filters/WebHookGetHeadRequestFilter.cs | 14 ++-------- .../Filters/WebHookPingRequestFilter.cs | 12 ++------- .../Filters/WebHookSecurityFilter.cs | 19 +++----------- .../Filters/WebHookVerifyBodyTypeFilter.cs | 26 +++---------------- .../Filters/WebHookVerifyCodeFilter.cs | 14 ++-------- .../WebHookVerifyRequiredValueFilter.cs | 13 ++-------- .../Routing/WebHookEventNameConstraint.cs | 21 +++------------ .../WebHookEventNameMapperConstraint.cs | 12 ++------- 15 files changed, 38 insertions(+), 204 deletions(-) diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Salesforce/ModelBinding/SalesforceNotificationsModelBinder.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Salesforce/ModelBinding/SalesforceNotificationsModelBinder.cs index 261b0066e..443765d69 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Salesforce/ModelBinding/SalesforceNotificationsModelBinder.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Salesforce/ModelBinding/SalesforceNotificationsModelBinder.cs @@ -21,12 +21,7 @@ public class SalesforceNotificationsModelBinder : IModelBinder /// The to bind models from the request body. public SalesforceNotificationsModelBinder(IModelBinder bodyModelBinder) { - if (bodyModelBinder == null) - { - throw new ArgumentNullException(nameof(bodyModelBinder)); - } - - _bodyModelBinder = bodyModelBinder; + _bodyModelBinder = bodyModelBinder ?? throw new ArgumentNullException(nameof(bodyModelBinder)); } /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Salesforce/SalesforceNotifications.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Salesforce/SalesforceNotifications.cs index 1e840bbbb..1b04c54bf 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Salesforce/SalesforceNotifications.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Salesforce/SalesforceNotifications.cs @@ -35,11 +35,7 @@ public class SalesforceNotifications /// An Outbound SOAP Message received from Salesforce. public SalesforceNotifications(XElement doc) { - if (doc == null) - { - throw new ArgumentNullException(nameof(doc)); - } - _doc = doc; + _doc = doc ?? throw new ArgumentNullException(nameof(doc)); } /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackAttachment.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackAttachment.cs index 8c9028601..65feb5af3 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackAttachment.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackAttachment.cs @@ -30,16 +30,8 @@ public class SlackAttachment /// that don't show formatted text (e.g. IRC, mobile notifications). It should not contain any markup. public SlackAttachment(string text, string fallback) { - if (text == null) - { - throw new ArgumentNullException(nameof(text)); - } - if (fallback == null) - { - throw new ArgumentNullException(nameof(fallback)); - } - _text = text; - _fallback = fallback; + _text = text ?? throw new ArgumentNullException(nameof(text)); + _fallback = fallback ?? throw new ArgumentNullException(nameof(fallback)); } /// @@ -63,11 +55,7 @@ public string Fallback } set { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _fallback = value; + _fallback = value ?? throw new ArgumentNullException(nameof(value)); } } @@ -134,11 +122,7 @@ public string Text } set { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _text = value; + _text = value ?? throw new ArgumentNullException(nameof(value)); } } diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackField.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackField.cs index a72c2d6df..5150cf5f2 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackField.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackField.cs @@ -31,16 +31,8 @@ public class SlackField /// public SlackField(string title, string value) { - if (title == null) - { - throw new ArgumentNullException(nameof(title)); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _title = title; - _value = value; + _title = title ?? throw new ArgumentNullException(nameof(title)); + _value = value ?? throw new ArgumentNullException(nameof(value)); } /// @@ -63,11 +55,7 @@ public string Title } set { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _title = value; + _title = value ?? throw new ArgumentNullException(nameof(value));; } } @@ -85,11 +73,7 @@ public string Value } set { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _value = value; + _value = value ?? throw new ArgumentNullException(nameof(value)); } } diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackResponse.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackResponse.cs index b3bb52bd9..94b25ec82 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackResponse.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackResponse.cs @@ -20,11 +20,7 @@ public class SlackResponse /// public SlackResponse(string text) { - if (text == null) - { - throw new ArgumentNullException(nameof(text)); - } - _text = text; + _text = text ?? throw new ArgumentNullException(nameof(text)); } /// @@ -39,11 +35,7 @@ public string Text } set { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _text = value; + _text = value ?? throw new ArgumentNullException(nameof(value)); } } } diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackSlashResponse.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackSlashResponse.cs index 91816f48c..2b8f8892f 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackSlashResponse.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Slack/SlackSlashResponse.cs @@ -49,16 +49,12 @@ public SlackSlashResponse(string text) /// public SlackSlashResponse(string text, params SlackAttachment[] attachments) { - if (text == null) - { - throw new ArgumentNullException(nameof(text)); - } if (attachments == null) { throw new ArgumentNullException(nameof(attachments)); } - _text = text; + _text = text ?? throw new ArgumentNullException(nameof(text));; foreach (var att in attachments) { _attachments.Add(att); @@ -84,11 +80,7 @@ public string Text } set { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - _text = value; + _text = value ?? throw new ArgumentNullException(nameof(value)); } } diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookEventNameMapperFilter.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookEventNameMapperFilter.cs index 6ba7b915e..892ec736a 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookEventNameMapperFilter.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookEventNameMapperFilter.cs @@ -55,17 +55,8 @@ public WebHookEventNameMapperFilter( IWebHookEventFromBodyMetadata eventFromBodyMetadata) : this(requestReader, loggerFactory) { - if (bodyTypeMetadata == null) - { - throw new ArgumentNullException(nameof(bodyTypeMetadata)); - } - if (eventFromBodyMetadata == null) - { - throw new ArgumentNullException(nameof(eventFromBodyMetadata)); - } - - _bodyTypeMetadata = bodyTypeMetadata; - _eventFromBodyMetadata = eventFromBodyMetadata; + _bodyTypeMetadata = bodyTypeMetadata ?? throw new ArgumentNullException(nameof(bodyTypeMetadata)); + _eventFromBodyMetadata = eventFromBodyMetadata ?? throw new ArgumentNullException(nameof(eventFromBodyMetadata)); } /// @@ -85,27 +76,18 @@ public WebHookEventNameMapperFilter( WebHookMetadataProvider metadataProvider) : this(requestReader, loggerFactory) { - if (metadataProvider == null) - { - throw new ArgumentNullException(nameof(metadataProvider)); - } - - _metadataProvider = metadataProvider; + _metadataProvider = metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider)); } private WebHookEventNameMapperFilter(IWebHookRequestReader requestReader, ILoggerFactory loggerFactory) { - if (requestReader == null) - { - throw new ArgumentNullException(nameof(requestReader)); - } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } _logger = loggerFactory.CreateLogger(); - _requestReader = requestReader; + _requestReader = requestReader ?? throw new ArgumentNullException(nameof(requestReader));; } /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookGetHeadRequestFilter.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookGetHeadRequestFilter.cs index b6df774e2..a56c69bda 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookGetHeadRequestFilter.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookGetHeadRequestFilter.cs @@ -46,12 +46,7 @@ public WebHookGetHeadRequestFilter( IWebHookGetHeadRequestMetadata getHeadRequestMetadata) : base(configuration, hostingEnvironment, loggerFactory) { - if (getHeadRequestMetadata == null) - { - throw new ArgumentNullException(nameof(getHeadRequestMetadata)); - } - - _getHeadRequestMetadata = getHeadRequestMetadata; + _getHeadRequestMetadata = getHeadRequestMetadata ?? throw new ArgumentNullException(nameof(getHeadRequestMetadata));; } /// @@ -80,12 +75,7 @@ public WebHookGetHeadRequestFilter( WebHookMetadataProvider metadataProvider) : base(configuration, hostingEnvironment, loggerFactory) { - if (metadataProvider == null) - { - throw new ArgumentNullException(nameof(metadataProvider)); - } - - _metadataProvider = metadataProvider; + _metadataProvider = metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider));; } /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookPingRequestFilter.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookPingRequestFilter.cs index a13a5fe91..e72522201 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookPingRequestFilter.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookPingRequestFilter.cs @@ -35,13 +35,9 @@ public WebHookPingRequestFilter( { throw new ArgumentNullException(nameof(loggerFactory)); } - if (pingRequestMetadata == null) - { - throw new ArgumentNullException(nameof(pingRequestMetadata)); - } _logger = loggerFactory.CreateLogger(); - _pingRequestMetadata = pingRequestMetadata; + _pingRequestMetadata = pingRequestMetadata ?? throw new ArgumentNullException(nameof(pingRequestMetadata)); } /// @@ -62,13 +58,9 @@ public WebHookPingRequestFilter( { throw new ArgumentNullException(nameof(loggerFactory)); } - if (metadataProvider == null) - { - throw new ArgumentNullException(nameof(metadataProvider)); - } _logger = loggerFactory.CreateLogger(); - _metadataProvider = metadataProvider; + _metadataProvider = metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider)); } /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookSecurityFilter.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookSecurityFilter.cs index ac0a1de1b..2f9dfdf5b 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookSecurityFilter.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookSecurityFilter.cs @@ -40,22 +40,9 @@ protected WebHookSecurityFilter( IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) { - if (configuration == null) - { - throw new ArgumentNullException(nameof(configuration)); - } - if (hostingEnvironment == null) - { - throw new ArgumentNullException(nameof(hostingEnvironment)); - } - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - Configuration = configuration; - HostingEnvironment = hostingEnvironment; - Logger = loggerFactory.CreateLogger(GetType()); + Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); + HostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); + Logger = loggerFactory?.CreateLogger(GetType()) ?? throw new ArgumentNullException(nameof(loggerFactory)); } /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyBodyTypeFilter.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyBodyTypeFilter.cs index 36335c0eb..4d1c61af5 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyBodyTypeFilter.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyBodyTypeFilter.cs @@ -59,17 +59,8 @@ public WebHookVerifyBodyTypeFilter( ILoggerFactory loggerFactory, IWebHookBodyTypeMetadataService bodyTypeMetadata) { - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - if (bodyTypeMetadata == null) - { - throw new ArgumentNullException(nameof(bodyTypeMetadata)); - } - - _bodyTypeMetadata = bodyTypeMetadata; - _logger = loggerFactory.CreateLogger(); + _logger = loggerFactory?.CreateLogger() ?? throw new ArgumentNullException(nameof(loggerFactory)); + _bodyTypeMetadata = bodyTypeMetadata ?? throw new ArgumentNullException(nameof(bodyTypeMetadata)); } /// @@ -84,17 +75,8 @@ public WebHookVerifyBodyTypeFilter( /// This overload is intended for use with . public WebHookVerifyBodyTypeFilter(ILoggerFactory loggerFactory, WebHookMetadataProvider metadataProvider) { - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - if (metadataProvider == null) - { - throw new ArgumentNullException(nameof(metadataProvider)); - } - - _logger = loggerFactory.CreateLogger(); - _metadataProvider = metadataProvider; + _logger = loggerFactory?.CreateLogger() ?? throw new ArgumentNullException(nameof(loggerFactory)); + _metadataProvider = metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider)); } /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyCodeFilter.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyCodeFilter.cs index f7d976cdb..8f7a8c0f8 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyCodeFilter.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyCodeFilter.cs @@ -48,12 +48,7 @@ public WebHookVerifyCodeFilter( IWebHookVerifyCodeMetadata verifyCodeMetadata) : base(configuration, hostingEnvironment, loggerFactory) { - if (verifyCodeMetadata == null) - { - throw new ArgumentNullException(nameof(verifyCodeMetadata)); - } - - _verifyCodeMetadata = verifyCodeMetadata; + _verifyCodeMetadata = verifyCodeMetadata ?? throw new ArgumentNullException(nameof(verifyCodeMetadata)); } /// @@ -81,12 +76,7 @@ public WebHookVerifyCodeFilter( WebHookMetadataProvider metadataProvider) : base(configuration, hostingEnvironment, loggerFactory) { - if (metadataProvider == null) - { - throw new ArgumentNullException(nameof(metadataProvider)); - } - - _metadataProvider = metadataProvider; + _metadataProvider = metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider)); } /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyRequiredValueFilter.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyRequiredValueFilter.cs index f68732e64..6ad057867 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyRequiredValueFilter.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Filters/WebHookVerifyRequiredValueFilter.cs @@ -50,12 +50,7 @@ public WebHookVerifyRequiredValueFilter( { throw new ArgumentNullException(nameof(loggerFactory)); } - if (bindingMetadata == null) - { - throw new ArgumentNullException(nameof(bindingMetadata)); - } - - _bindingMetadata = bindingMetadata; + _bindingMetadata = bindingMetadata ?? throw new ArgumentNullException(nameof(bindingMetadata)); _logger = loggerFactory.CreateLogger(); } @@ -76,13 +71,9 @@ public WebHookVerifyRequiredValueFilter( { throw new ArgumentNullException(nameof(loggerFactory)); } - if (metadataProvider == null) - { - throw new ArgumentNullException(nameof(metadataProvider)); - } _logger = loggerFactory.CreateLogger(); - _metadataProvider = metadataProvider; + _metadataProvider = metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider)); } /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Routing/WebHookEventNameConstraint.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Routing/WebHookEventNameConstraint.cs index 2690ecb9c..76a79ccc8 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Routing/WebHookEventNameConstraint.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Routing/WebHookEventNameConstraint.cs @@ -27,12 +27,7 @@ public class WebHookEventNameConstraint : IActionConstraint /// Name of the event this action expects. public WebHookEventNameConstraint(string eventName) { - if (eventName == null) - { - throw new ArgumentNullException(nameof(eventName)); - } - - _eventName = eventName; + _eventName = eventName ?? throw new ArgumentNullException(nameof(eventName)); } /// @@ -47,12 +42,7 @@ public WebHookEventNameConstraint(string eventName) public WebHookEventNameConstraint(string eventName, IWebHookPingRequestMetadata pingRequestMetadata) : this(eventName) { - if (pingRequestMetadata == null) - { - throw new ArgumentNullException(nameof(pingRequestMetadata)); - } - - _pingRequestMetadata = pingRequestMetadata; + _pingRequestMetadata = pingRequestMetadata ?? throw new ArgumentNullException(nameof(pingRequestMetadata)); } /// @@ -70,12 +60,7 @@ public WebHookEventNameConstraint(string eventName, IWebHookPingRequestMetadata public WebHookEventNameConstraint(string eventName, WebHookMetadataProvider metadataProvider) : this(eventName) { - if (metadataProvider == null) - { - throw new ArgumentNullException(nameof(metadataProvider)); - } - - _metadataProvider = metadataProvider; + _metadataProvider = metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider)); } // Running this constraint last avoids NotFound responses to ping requests because other actions have different diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Routing/WebHookEventNameMapperConstraint.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Routing/WebHookEventNameMapperConstraint.cs index 030f2f0e5..5b2df1d41 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Routing/WebHookEventNameMapperConstraint.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers/Routing/WebHookEventNameMapperConstraint.cs @@ -38,12 +38,8 @@ public WebHookEventNameMapperConstraint( { throw new ArgumentNullException(nameof(loggerFactory)); } - if (eventMetadata == null) - { - throw new ArgumentNullException(nameof(eventMetadata)); - } - _eventMetadata = eventMetadata; + _eventMetadata = eventMetadata ?? throw new ArgumentNullException(nameof(eventMetadata)); _logger = loggerFactory.CreateLogger(); } @@ -64,13 +60,9 @@ public WebHookEventNameMapperConstraint( { throw new ArgumentNullException(nameof(loggerFactory)); } - if (metadataProvider == null) - { - throw new ArgumentNullException(nameof(metadataProvider)); - } _logger = loggerFactory.CreateLogger(); - _metadataProvider = metadataProvider; + _metadataProvider = metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider)); } /// From 439a6a0d720ee3574ac07e48fe62dfc4978f0b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20BIAUDET?= Date: Fri, 4 Sep 2020 23:20:08 +0200 Subject: [PATCH 4/5] Add Intercom Tests --- src/WebHooks/WebHooks.sln | 7 +++ .../Controllers/IntercomController.cs | 63 +++++++++++++++++++ .../IntercomCoreReceiver.csproj | 10 +++ .../samples/IntercomCoreReceiver/Program.cs | 17 +++++ .../samples/IntercomCoreReceiver/Startup.cs | 24 +++++++ .../IntercomCoreReceiver/appsettings.json | 3 + .../IntercomConstants.cs | 11 ++-- .../IntercomNotification.cs | 2 +- .../Metadata/IntercomMetadata.cs | 25 ++++---- .../IntercomCoreReceiverTest.cs | 61 ++++++++++++++++++ ....AspNetCore.WebHooks.FunctionalTest.csproj | 1 + .../Resources/RequestBodies/Intercom.json | 17 +++++ 12 files changed, 223 insertions(+), 18 deletions(-) create mode 100644 src/WebHooks/samples/IntercomCoreReceiver/Controllers/IntercomController.cs create mode 100644 src/WebHooks/samples/IntercomCoreReceiver/IntercomCoreReceiver.csproj create mode 100644 src/WebHooks/samples/IntercomCoreReceiver/Program.cs create mode 100644 src/WebHooks/samples/IntercomCoreReceiver/Startup.cs create mode 100644 src/WebHooks/samples/IntercomCoreReceiver/appsettings.json create mode 100644 src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/IntercomCoreReceiverTest.cs create mode 100644 src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/Resources/RequestBodies/Intercom.json diff --git a/src/WebHooks/WebHooks.sln b/src/WebHooks/WebHooks.sln index 6f74b779a..9301323ca 100644 --- a/src/WebHooks/WebHooks.sln +++ b/src/WebHooks/WebHooks.sln @@ -101,6 +101,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.WebHoo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.WebHooks.Receivers.Intercom", "src\Microsoft.AspNetCore.WebHooks.Receivers.Intercom\Microsoft.AspNetCore.WebHooks.Receivers.Intercom.csproj", "{920467E5-A7BD-4425-967E-32D9F411DE6C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntercomCoreReceiver", "samples\IntercomCoreReceiver\IntercomCoreReceiver.csproj", "{0F90B202-3D68-4EE2-B310-6D81A9440E22}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -255,6 +257,10 @@ Global {920467E5-A7BD-4425-967E-32D9F411DE6C}.Debug|Any CPU.Build.0 = Debug|Any CPU {920467E5-A7BD-4425-967E-32D9F411DE6C}.Release|Any CPU.ActiveCfg = Release|Any CPU {920467E5-A7BD-4425-967E-32D9F411DE6C}.Release|Any CPU.Build.0 = Release|Any CPU + {0F90B202-3D68-4EE2-B310-6D81A9440E22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0F90B202-3D68-4EE2-B310-6D81A9440E22}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0F90B202-3D68-4EE2-B310-6D81A9440E22}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0F90B202-3D68-4EE2-B310-6D81A9440E22}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -297,6 +303,7 @@ Global {E9E37253-3FE1-44A4-A9E7-A2B6C54EECFE} = {E957C8D9-B4A0-488B-838F-BAB4DE080A76} {F42E56B7-60D4-481A-8585-04015B2B501E} = {9575CB90-BC4B-43BB-8AEA-82C53FDA4187} {920467E5-A7BD-4425-967E-32D9F411DE6C} = {929F44D0-A040-4DC3-A22F-4C5829C05D44} + {0F90B202-3D68-4EE2-B310-6D81A9440E22} = {E957C8D9-B4A0-488B-838F-BAB4DE080A76} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {12CE6238-F847-4984-8622-1ED46072150A} diff --git a/src/WebHooks/samples/IntercomCoreReceiver/Controllers/IntercomController.cs b/src/WebHooks/samples/IntercomCoreReceiver/Controllers/IntercomController.cs new file mode 100644 index 000000000..b279175bd --- /dev/null +++ b/src/WebHooks/samples/IntercomCoreReceiver/Controllers/IntercomController.cs @@ -0,0 +1,63 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.WebHooks; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace IntercomCoreReceiver.Controllers +{ + public class IntercomController : ControllerBase + { + private readonly ILogger _logger; + + public IntercomController(ILoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(); + } + + [IntercomWebHook(Id = "It")] + public IActionResult IntercomForIt(string @event, string notificationId, JObject data) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + return Ok(); + } + + [IntercomWebHook] + public IActionResult Intercom(string id, string @event, string notificationId, JObject dataObj) + { + + var data = dataObj.ToObject(); + + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + _logger.LogInformation( + 0, + $"{nameof(IntercomController)} / '{{ReceiverId}}' received a '{{EventType}}' notification (event " + + "'{EventName}').", + id, + data.Type, + @event); + + _logger.LogInformation( + 1, + "Data created at '{Created}' and contains Notification ID '{Id}' / '{NotificationId}', Topic " + + "'{Topic}'.", + data.CreatedAt, + data.Id, + notificationId, + data.Topic); + + var details = data.Data.Item; + + return Ok(); + } + } +} diff --git a/src/WebHooks/samples/IntercomCoreReceiver/IntercomCoreReceiver.csproj b/src/WebHooks/samples/IntercomCoreReceiver/IntercomCoreReceiver.csproj new file mode 100644 index 000000000..e420e6504 --- /dev/null +++ b/src/WebHooks/samples/IntercomCoreReceiver/IntercomCoreReceiver.csproj @@ -0,0 +1,10 @@ + + + $(StandardTestWebsiteTfms) + + + + + + + diff --git a/src/WebHooks/samples/IntercomCoreReceiver/Program.cs b/src/WebHooks/samples/IntercomCoreReceiver/Program.cs new file mode 100644 index 000000000..ab4cf4224 --- /dev/null +++ b/src/WebHooks/samples/IntercomCoreReceiver/Program.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; + +namespace IntercomCoreReceiver +{ + public class Program + { + public static void Main(string[] args) + { + CreateWebHostBuilder(args).Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup(); + } +} diff --git a/src/WebHooks/samples/IntercomCoreReceiver/Startup.cs b/src/WebHooks/samples/IntercomCoreReceiver/Startup.cs new file mode 100644 index 000000000..a1639cf87 --- /dev/null +++ b/src/WebHooks/samples/IntercomCoreReceiver/Startup.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; + +namespace IntercomCoreReceiver +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + services + .AddMvcCore() + .AddIntercomWebHooks(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + app.UseMvc(); + } + } +} diff --git a/src/WebHooks/samples/IntercomCoreReceiver/appsettings.json b/src/WebHooks/samples/IntercomCoreReceiver/appsettings.json new file mode 100644 index 000000000..3f677b3a8 --- /dev/null +++ b/src/WebHooks/samples/IntercomCoreReceiver/appsettings.json @@ -0,0 +1,3 @@ +{ + "WebHooks:Intercom:SecretKey:default": "0123456789012345" +} diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomConstants.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomConstants.cs index 9d265f83f..418534d82 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomConstants.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomConstants.cs @@ -13,11 +13,6 @@ public static class IntercomConstants /// public static string ReceiverName => "intercom"; - /// - /// Gets the name of the header containing the Intercom event name e.g. ping or push. - /// - public static string EventHeaderName => "X-Github-Event"; - /// /// Gets the name of the Intercom ping event. /// @@ -38,5 +33,11 @@ public static class IntercomConstants /// request. /// public static string SignatureHeaderName => "X-Hub-Signature"; + + /// + /// Gets the JSON path of the property in an Intercom WebHook request body containing the Intercom event + /// topic. Matches the topic name. + /// + public static string EventBodyPropertyPath => "$['topic']"; } } diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotification.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotification.cs index f5063c67c..30b3e65f0 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotification.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/IntercomNotification.cs @@ -24,7 +24,7 @@ public class IntercomNotification /// /// Gets or sets the notification id. /// - [JsonProperty("id", Required = Required.Always)] + [JsonProperty("id", Required = Required.AllowNull)] public string Id { get; set; } /// diff --git a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Metadata/IntercomMetadata.cs b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Metadata/IntercomMetadata.cs index 53c3ac4cb..ffe3505f1 100644 --- a/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Metadata/IntercomMetadata.cs +++ b/src/WebHooks/src/Microsoft.AspNetCore.WebHooks.Receivers.Intercom/Metadata/IntercomMetadata.cs @@ -6,13 +6,13 @@ namespace Microsoft.AspNetCore.WebHooks.Metadata { /// - /// An service containing metadata about the GitHub receiver. + /// An service containing metadata about the Intercom receiver. /// public class IntercomMetadata : WebHookMetadata, - IWebHookEventMetadata, - IWebHookFilterMetadata, - IWebHookPingRequestMetadata + IWebHookPingRequestMetadata, + IWebHookEventFromBodyMetadata, + IWebHookFilterMetadata { private readonly IntercomVerifySignatureFilter _verifySignatureFilter; @@ -31,14 +31,6 @@ public IntercomMetadata(IntercomVerifySignatureFilter verifySignatureFilter) /// public override WebHookBodyType BodyType => WebHookBodyType.Json; - // IWebHookEventMetadata... - - /// - public string ConstantValue => null; - - /// - public string HeaderName => IntercomConstants.EventHeaderName; - /// public string QueryParameterName => null; @@ -47,6 +39,15 @@ public IntercomMetadata(IntercomVerifySignatureFilter verifySignatureFilter) /// public string PingEventName => IntercomConstants.PingEventName; + + // IWebHookEventFromBodyMetadata... + + /// + public bool AllowMissing => false; + + /// + public string BodyPropertyPath => IntercomConstants.EventBodyPropertyPath; + // IWebHookFilterMetadata... /// diff --git a/src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/IntercomCoreReceiverTest.cs b/src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/IntercomCoreReceiverTest.cs new file mode 100644 index 000000000..b43f30634 --- /dev/null +++ b/src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/IntercomCoreReceiverTest.cs @@ -0,0 +1,61 @@ +// 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 System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using IntercomCoreReceiver; +using Xunit; + +namespace Microsoft.AspNetCore.WebHooks.FunctionalTest +{ + public class IntercomCoreReceiverTest : IClassFixture> + { + private readonly HttpClient _client; + + public IntercomCoreReceiverTest(WebHookTestFixture fixture) + { + _client = fixture.CreateClient(); + } + + [Fact] + public async Task HomePage_IsNotFound() + { + // Arrange & Act + var response = await _client.GetAsync("/"); + + // Assert + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + public static TheoryData NonPostDataSet + { + get + { + return new TheoryData + { + HttpMethod.Get, + HttpMethod.Head, + HttpMethod.Put, + }; + } + } + [Theory] + [MemberData(nameof(NonPostDataSet))] + public async Task WebHookAction_NonPost_IsNotAllowed(HttpMethod method) + { + // Arrange + var expectedErrorMessage = $"The 'intercom' WebHook receiver does not support the HTTP '{method.Method}' " + + "method."; + var request = new HttpRequestMessage(method, "/api/webhooks/incoming/intercom"); + + // Act + var response = await _client.SendAsync(request); + + // Assert + Assert.Equal(HttpStatusCode.MethodNotAllowed, response.StatusCode); + var responseText = await response.Content.ReadAsStringAsync(); + Assert.Equal(expectedErrorMessage, responseText); + } + } +} diff --git a/src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/Microsoft.AspNetCore.WebHooks.FunctionalTest.csproj b/src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/Microsoft.AspNetCore.WebHooks.FunctionalTest.csproj index a844c93d0..83ccb907b 100644 --- a/src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/Microsoft.AspNetCore.WebHooks.FunctionalTest.csproj +++ b/src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/Microsoft.AspNetCore.WebHooks.FunctionalTest.csproj @@ -14,6 +14,7 @@ + diff --git a/src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/Resources/RequestBodies/Intercom.json b/src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/Resources/RequestBodies/Intercom.json new file mode 100644 index 000000000..8ca663262 --- /dev/null +++ b/src/WebHooks/test/Microsoft.AspNetCore.WebHooks.FunctionalTest/Resources/RequestBodies/Intercom.json @@ -0,0 +1,17 @@ +{ + "type" : "notification_event", + "id" : "notif_78c122d0-23ba-11e4-9464-79b01267cc2e", + "topic" : "user.created", + "app_id" : "a86dr8yl", + "data" : { + "type" : "notification_event_data", + "item" : { + "type" : "user", + "id" : "530370b477ad7120001d", + "user_id" : "25", + "name" : "Hoban Washburne", + "unsubscribed_from_emails" : false, + "custom_attributes" : {} + } + } +} From 8ad944601731f7ccc070537ac4707ca4e53591c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81bastien=20BIAUDET?= Date: Fri, 4 Sep 2020 23:29:13 +0200 Subject: [PATCH 5/5] Update Readme with Intercom receiver --- src/WebHooks/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/WebHooks/README.md b/src/WebHooks/README.md index f21ab86b5..ee8824c9e 100644 --- a/src/WebHooks/README.md +++ b/src/WebHooks/README.md @@ -12,6 +12,7 @@ ASP.NET Core WebHooks provide support for receiving WebHooks. The packages depen - [Dropbox](./samples/DropboxCoreReceiver) - [DynamicCRM](./samples/DynamicsCRMCoreReceiver) - [GitHub](./samples/GitHubCoreReceiver) +- [Intercom](./samples/IntercomCoreReceiver) - [Kudu](./samples/KuduCoreReceiver) - [MailChimp](./samples/MailChimpCoreReceiver) - [Pusher](./samples/PusherCoreReceiver)