From 6c436a481a478cde4a49b29983be852baf0ba49f Mon Sep 17 00:00:00 2001 From: Elad Iwanir <13205761+eladiw@users.noreply.github.com> Date: Mon, 6 Apr 2020 13:58:40 +0300 Subject: [PATCH 1/8] Supporting Windows and Linux web apps. Linux by default (#57) * Supporting Windows and Linux web apps. Linux by default * bug fix * update readme * adding doc * update readme --- README.md | 5 +- azuredeploy.json | 128 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 120 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 30caa9f..0332eaf 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ A simple web page to hand off users to the Microsoft Health bot [![Deploy to Azure](https://azuredeploy.net/deploybutton.png)](https://azuredeploy.net/) +Note: It is recommended you use the default Linux host type when deploying the container. +However, if you wish to enable online file editing using the App Service Editor, select 'Windows'. + 2.Set the following environment variables: `APP_SECRET` @@ -48,7 +51,7 @@ In some cases it is required to set the endpoint URI so that it points to a spec Pass your preferred geographic endpoint URI by setting the environment variable: `DIRECTLINE_ENDPOINT_URI` in your deployment. If no variable is found it will default to `directline.botframework.com` -**Note:** If you are deploying the code sample using the "Deploy to Azure" option, you should add the above secrets to the application settings for your App Service. +**Note:** If you are deploying the code sample using the "Deploy to Azure" option, you should add the above secrets to the application settings for your App Service. ## Agent webchat If the agent webchat sample is also required, [switch to the live agent handoff branch](https://github.com/Microsoft/HealthBotContainerSample/tree/live_agent_handoff) diff --git a/azuredeploy.json b/azuredeploy.json index 7e5f0ed..f7b8d45 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -7,13 +7,24 @@ "defaultValue": "[concat('HealthBot', uniqueString(resourceGroup().name, utcNow('F')))]", "metadata":{ "description": "Web site name. Has to be unique." - + + } + }, + "serverKind": { + "type": "string", + "defaultValue": "linux", + "allowedValues": [ + "linux", + "windows" + ], + "metadata": { + "description": "Host type: Linux or Windows. (Linux is recommended)" } }, "skuName": { "type": "string", "defaultValue": "P1V2", - "allowedValues": [ + "allowedValues": [ "B1", "S1", "P1V2" @@ -44,7 +55,7 @@ "webchatSecret": { "type": "securestring", "metadata":{ - "description": "Healthbot webchat secret." + "description": "Healthbot webchat secret." } } }, @@ -53,21 +64,33 @@ "skuCode": "[parameters('skuName')]", "numberOfWorkers": "[parameters('numberOfInstances')]", "linuxFxVersion": "NODE|lts", - "hostingPlanName": "[concat('hpn-', parameters('siteName'))]", + "hostingPlanNameLinux": "[concat('hpn-', parameters('siteName'))]", + "hostingPlanNameWin": "[concat('hpn-win-', parameters('siteName'))]", "repoURL": "https://github.com/microsoft/HealthBotContainerSample.git", - "branch": "master" + "branch": "master", + "kind": "[if(equals(parameters('serverKind'), 'windows'), 'app', 'linux')]", + "linuxSiteName": "[concat(parameters('siteName'), 'linux')]", + "windowsSiteName": "[concat(parameters('siteName'), 'windows')]", + "WinSkuCode": "[parameters('skuName')]", + "WinSku": "Standard", + "workerSize": "0", + "workerSizeId": "0", + "hostingEnvironment": "", + "nodeVersion": "12.13.0", + "currentStack": "node" }, "resources": [ { "apiVersion": "2018-02-01", - "name": "[parameters('siteName')]", + "name": "[variables('linuxSiteName')]", + "condition": "[equals(parameters('serverKind'),'linux')]", "type": "Microsoft.Web/sites", "location": "[parameters('siteLocation')]", "dependsOn": [ - "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]" + "[resourceId('Microsoft.Web/serverfarms/', variables('hostingPlanNameLinux'))]" ], "properties": { - "name": "[parameters('siteName')]", + "name": "[variables('linuxSiteName')]", "siteConfig": { "linuxFxVersion": "[variables('linuxFxVersion')]", "alwaysOn": "[variables('alwaysOn')]", @@ -82,17 +105,18 @@ } ] }, - "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanNameLinux'))]", "clientAffinityEnabled": false }, "resources": [ { "type": "sourcecontrols", + "condition": "[equals(parameters('serverKind'),'linux')]", "apiVersion": "2018-02-01", "name": "web", "location": "[parameters('siteLocation')]", "dependsOn": [ - "[resourceId('Microsoft.Web/sites', parameters('siteName'))]" + "[resourceId('Microsoft.Web/sites', variables('linuxSiteName'))]" ], "properties": { "repoUrl": "[variables('repoURL')]", @@ -104,7 +128,8 @@ }, { "apiVersion": "2018-02-01", - "name": "[variables('hostingPlanName')]", + "condition": "[equals(parameters('serverKind'),'linux')]", + "name": "[variables('hostingPlanNameLinux')]", "type": "Microsoft.Web/serverfarms", "location": "[parameters('siteLocation')]", "kind": "linux", @@ -112,10 +137,89 @@ "Name": "[variables('skuCode')]" }, "properties": { - "name": "[variables('hostingPlanName')]", + "name": "[variables('hostingPlanNameLinux')]", "numberOfWorkers": "[variables('numberOfWorkers')]", "reserved": true } + }, + { + "apiVersion": "2018-11-01", + "condition": "[equals(parameters('serverKind'),'windows')]", + "name": "[variables('windowsSiteName')]", + "type": "Microsoft.Web/sites", + "location": "[parameters('siteLocation')]", + "tags": null, + "dependsOn": [ + "[concat('Microsoft.Web/serverfarms/', variables('hostingPlanNameWin'))]" + ], + "properties": { + "name": "[variables('windowsSiteName')]", + "siteConfig": { + "appSettings": [ + { + "name": "APP_SECRET", + "value": "[parameters('appSecret')]" + }, + { + "name": "WEBCHAT_SECRET", + "value": "[parameters('webchatSecret')]" + }, + { + "name": "WEBSITE_NODE_DEFAULT_VERSION", + "value": "[variables('nodeVersion')]" + } + ], + "metadata": [ + { + "name": "CURRENT_STACK", + "value": "[variables('currentStack')]" + } + ], + "nodeVersion": "[variables('nodeVersion')]", + "alwaysOn": "[variables('alwaysOn')]" + }, + "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanNameWin'))]", + "hostingEnvironment": "[variables('hostingEnvironment')]", + "clientAffinityEnabled": true + }, + "resources": [ + { + "type": "sourcecontrols", + "condition": "[equals(parameters('serverKind'),'windows')]", + "apiVersion": "2018-11-01", + "name": "web", + "location": "[parameters('siteLocation')]", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', variables('windowsSiteName'))]" + ], + "properties": { + "repoUrl": "[variables('repoURL')]", + "branch": "[variables('branch')]", + "isManualIntegration": true + } + } + ] + }, + { + "apiVersion": "2018-11-01", + "name": "[variables('hostingPlanNameWin')]", + "condition": "[equals(parameters('serverKind'),'windows')]", + "type": "Microsoft.Web/serverfarms", + "location": "[parameters('siteLocation')]", + "kind": "", + "tags": null, + "dependsOn": [], + "properties": { + "name": "[variables('hostingPlanNameWin')]", + "workerSize": "[variables('workerSize')]", + "workerSizeId": "[variables('workerSizeId')]", + "numberOfWorkers": "[variables('numberOfWorkers')]", + "hostingEnvironment": "[variables('hostingEnvironment')]" + }, + "sku": { + "Tier": "[variables('WinSku')]", + "Name": "[variables('WinSkuCode')]" + } } ] } \ No newline at end of file From c134e60d0b0fa33a4788c36e2e257fcdff260717 Mon Sep 17 00:00:00 2001 From: GuyBeckerMicrosoft <61974899+GuyBeckerMicrosoft@users.noreply.github.com> Date: Tue, 7 Apr 2020 19:26:01 +0300 Subject: [PATCH 2/8] Origin/deployment script update (#64) --- azuredeploy.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/azuredeploy.json b/azuredeploy.json index f7b8d45..38f1973 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -10,7 +10,7 @@ } }, - "serverKind": { + "operatingSystem": { "type": "string", "defaultValue": "linux", "allowedValues": [ @@ -64,13 +64,13 @@ "skuCode": "[parameters('skuName')]", "numberOfWorkers": "[parameters('numberOfInstances')]", "linuxFxVersion": "NODE|lts", - "hostingPlanNameLinux": "[concat('hpn-', parameters('siteName'))]", - "hostingPlanNameWin": "[concat('hpn-win-', parameters('siteName'))]", + "hostingPlanNameLinux": "[concat('plan-linux-', parameters('siteName'))]", + "hostingPlanNameWin": "[concat('plan-win-', parameters('siteName'))]", "repoURL": "https://github.com/microsoft/HealthBotContainerSample.git", "branch": "master", - "kind": "[if(equals(parameters('serverKind'), 'windows'), 'app', 'linux')]", - "linuxSiteName": "[concat(parameters('siteName'), 'linux')]", - "windowsSiteName": "[concat(parameters('siteName'), 'windows')]", + "kind": "[if(equals(parameters('operatingSystem'), 'windows'), 'app', 'linux')]", + "linuxSiteName": "[if(equals(parameters('operatingSystem'), 'linux'), parameters('siteName'), 'app-na')]", + "windowsSiteName": "[if(equals(parameters('operatingSystem'), 'windows'), parameters('siteName'), 'app-na')]", "WinSkuCode": "[parameters('skuName')]", "WinSku": "Standard", "workerSize": "0", @@ -83,7 +83,7 @@ { "apiVersion": "2018-02-01", "name": "[variables('linuxSiteName')]", - "condition": "[equals(parameters('serverKind'),'linux')]", + "condition": "[equals(parameters('operatingSystem'),'linux')]", "type": "Microsoft.Web/sites", "location": "[parameters('siteLocation')]", "dependsOn": [ @@ -111,7 +111,7 @@ "resources": [ { "type": "sourcecontrols", - "condition": "[equals(parameters('serverKind'),'linux')]", + "condition": "[equals(parameters('operatingSystem'),'linux')]", "apiVersion": "2018-02-01", "name": "web", "location": "[parameters('siteLocation')]", @@ -128,7 +128,7 @@ }, { "apiVersion": "2018-02-01", - "condition": "[equals(parameters('serverKind'),'linux')]", + "condition": "[equals(parameters('operatingSystem'),'linux')]", "name": "[variables('hostingPlanNameLinux')]", "type": "Microsoft.Web/serverfarms", "location": "[parameters('siteLocation')]", @@ -144,7 +144,7 @@ }, { "apiVersion": "2018-11-01", - "condition": "[equals(parameters('serverKind'),'windows')]", + "condition": "[equals(parameters('operatingSystem'),'windows')]", "name": "[variables('windowsSiteName')]", "type": "Microsoft.Web/sites", "location": "[parameters('siteLocation')]", @@ -185,7 +185,7 @@ "resources": [ { "type": "sourcecontrols", - "condition": "[equals(parameters('serverKind'),'windows')]", + "condition": "[equals(parameters('operatingSystem'),'windows')]", "apiVersion": "2018-11-01", "name": "web", "location": "[parameters('siteLocation')]", @@ -203,7 +203,7 @@ { "apiVersion": "2018-11-01", "name": "[variables('hostingPlanNameWin')]", - "condition": "[equals(parameters('serverKind'),'windows')]", + "condition": "[equals(parameters('operatingSystem'),'windows')]", "type": "Microsoft.Web/serverfarms", "location": "[parameters('siteLocation')]", "kind": "", From f97e69e462da4041b67b09cb30a0e4793fbe4614 Mon Sep 17 00:00:00 2001 From: amir-microsoft <44203837+amir-microsoft@users.noreply.github.com> Date: Tue, 7 Apr 2020 20:01:05 +0300 Subject: [PATCH 3/8] Removing locale validation: (#63) Current locale validation doesn't support all cases, such as: de, zh-Hant-TW, En-au,aZ_cYrl-aZ The locale is validated in the WebChat app anyway so it's redundant. --- public/index.js | 14 ++++++-------- server.js | 11 +---------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/public/index.js b/public/index.js index 3c4b3cb..d44cb55 100644 --- a/public/index.js +++ b/public/index.js @@ -1,12 +1,10 @@ const defaultLocale = 'en-US'; -const localeRegExPattern = /^[a-z]{2}(-[A-Z]{2})?$/; function requestChatBot(loc) { const params = new URLSearchParams(location.search); - const locale = params.has('locale') ? extractLocale(params.get('locale')) : defaultLocale; const oReq = new XMLHttpRequest(); oReq.addEventListener("load", initBotConversation); - var path = "/chatBot?locale=" + locale; + var path = "/chatBot?locale=" + extractLocale(params.get('locale')); if (loc) { path += "&lat=" + loc.lat + "&long=" + loc.long; @@ -22,15 +20,15 @@ function requestChatBot(loc) { } function extractLocale(localeParam) { - if(localeParam === 'autodetect') { + if (!localeParam) { + return defaultLocale; + } + else if (localeParam === 'autodetect') { return navigator.language; } - - //Before assigning, ensure it's a valid locale string (xx or xx-XX) - if(localeParam.search(localeRegExPattern) === 0) { + else { return localeParam; } - return defaultLocale; } function chatRequested() { diff --git a/server.js b/server.js index d37695b..412cc5a 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,4 @@ require('dotenv').config(); -const defaultLocale = 'en-US'; -const localeRegExPattern = /^[a-z]{2}(-[A-Z]{2})?$/; const crypto = require('crypto'); const express = require("express"); const path = require("path"); @@ -31,13 +29,6 @@ function isUserAuthenticated(){ return true; } -function getValidatedLocale(loc) { - if (loc.search(localeRegExPattern) === 0) { - return loc; - } - return defaultLocale; -} - const appConfig = { isHealthy : false, options : { @@ -96,7 +87,7 @@ app.post('/chatBot', function(req, res) { var response = {}; response['userId'] = userid; response['userName'] = req.query.userName; - response['locale'] = getValidatedLocale(req.query.locale); + response['locale'] = req.query.locale; response['connectorToken'] = parsedBody.token; /* From e9769030e2bc6740ea5cca32c717cfffc9034f73 Mon Sep 17 00:00:00 2001 From: amir-microsoft <44203837+amir-microsoft@users.noreply.github.com> Date: Sun, 19 Apr 2020 19:52:02 +0300 Subject: [PATCH 4/8] Dynamic branch and repo for deploy (#70) * When using "deploy to azure" button, taking the repo and branch from the page where the button was clicked --- azuredeploy.json | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/azuredeploy.json b/azuredeploy.json index 38f1973..1f750fe 100644 --- a/azuredeploy.json +++ b/azuredeploy.json @@ -57,6 +57,12 @@ "metadata":{ "description": "Healthbot webchat secret." } + }, + "repoUrl": { + "type": "string" + }, + "branch": { + "type": "string" } }, "variables":{ @@ -66,8 +72,6 @@ "linuxFxVersion": "NODE|lts", "hostingPlanNameLinux": "[concat('plan-linux-', parameters('siteName'))]", "hostingPlanNameWin": "[concat('plan-win-', parameters('siteName'))]", - "repoURL": "https://github.com/microsoft/HealthBotContainerSample.git", - "branch": "master", "kind": "[if(equals(parameters('operatingSystem'), 'windows'), 'app', 'linux')]", "linuxSiteName": "[if(equals(parameters('operatingSystem'), 'linux'), parameters('siteName'), 'app-na')]", "windowsSiteName": "[if(equals(parameters('operatingSystem'), 'windows'), parameters('siteName'), 'app-na')]", @@ -119,8 +123,8 @@ "[resourceId('Microsoft.Web/sites', variables('linuxSiteName'))]" ], "properties": { - "repoUrl": "[variables('repoURL')]", - "branch": "[variables('branch')]", + "repoUrl": "[parameters('repoURL')]", + "branch": "[parameters('branch')]", "isManualIntegration": true } } @@ -193,8 +197,8 @@ "[resourceId('Microsoft.Web/sites', variables('windowsSiteName'))]" ], "properties": { - "repoUrl": "[variables('repoURL')]", - "branch": "[variables('branch')]", + "repoUrl": "[parameters('repoURL')]", + "branch": "[parameters('branch')]", "isManualIntegration": true } } From 8ad7c036111a87b50439d3f42377edeee1731cd0 Mon Sep 17 00:00:00 2001 From: amirt Date: Sun, 17 May 2020 14:42:47 +0300 Subject: [PATCH 5/8] Adding example for using Content security policy to limit which domains are allowed to embed this page as a frame --- Web.config | 5 ----- server.js | 6 +++++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Web.config b/Web.config index 4eb0322..45c8280 100644 --- a/Web.config +++ b/Web.config @@ -24,11 +24,6 @@ - - - - - diff --git a/server.js b/server.js index 412cc5a..750c7f8 100644 --- a/server.js +++ b/server.js @@ -13,9 +13,13 @@ const directLineTokenEp = `https://${DIRECTLINE_ENDPOINT_URI || "directline.botf // Initialize the web app instance, const app = express(); app.use(cookieParser()); + +let options = {}; +// uncomment the line below if you wish to allow only specific domains to embed this page as a frame +//options = {setHeaders: (res, path, stat) => {res.set('Content-Security-Policy', 'frame-ancestors example.com')}}; // Indicate which directory static resources // (e.g. stylesheets) should be served from. -app.use(express.static(path.join(__dirname, "public"))); +app.use(express.static(path.join(__dirname, "public"), options)); // begin listening for requests. const port = process.env.PORT || 8080; const region = process.env.REGION || "Unknown"; From aa3aaf597664ec197dc8e87bcf719f9169750abd Mon Sep 17 00:00:00 2001 From: GuyBeckerMicrosoft <61974899+GuyBeckerMicrosoft@users.noreply.github.com> Date: Sun, 24 May 2020 10:22:52 +0300 Subject: [PATCH 6/8] remove private preview from readme (#76) * remove private preview from readme * Description change Co-authored-by: Guy Becker --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0332eaf..11e22f8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Health Bot Container +A simple web page that allows users to communicate with the [Microsoft Health Bot service](https://www.microsoft.com/en-us/research/project/health-bot/) through a WebChat. + **Note:** In order to use this Web Chat with the Health Bot service, you will need to obtain your Web Chat secret by going to ["Integration/Secrets"](./secrets.png) on the navigation panel. -Please refer to [Microsoft Health Bot](https://www.microsoft.com/en-us/research/project/health-bot/) for a private preview and details. -A simple web page to hand off users to the Microsoft Health bot 1.Deploy the website: From 48d598677dd3b3aebf6fb69ee58a15dffb6975aa Mon Sep 17 00:00:00 2001 From: AdamWalkerMicrosoft <40535367+AdamWalkerMicrosoft@users.noreply.github.com> Date: Wed, 3 Jun 2020 11:11:34 +0300 Subject: [PATCH 7/8] Update index.html --- public/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/index.html b/public/index.html index 103212f..0e46867 100644 --- a/public/index.html +++ b/public/index.html @@ -17,7 +17,7 @@ );window[aiName]=aisdk,aisdk.queue&&0===aisdk.queue.length&&aisdk.trackPageView({}); --> - + From 0f369396f5ff64f1b61b31a39b114dbc88f62aeb Mon Sep 17 00:00:00 2001 From: amir-microsoft <> Date: Thu, 11 Jun 2020 19:19:04 +0300 Subject: [PATCH 8/8] Fixing a bug where a redundant parameters was passed to the function passed to --- public/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/public/index.js b/public/index.js index a7f5cd9..6d8462e 100644 --- a/public/index.js +++ b/public/index.js @@ -53,7 +53,6 @@ function chatRequested(info) { function getUserLocation(info, callback) { navigator.geolocation.getCurrentPosition( - null, function(position) { var latitude = position.coords.latitude; var longitude = position.coords.longitude;