Try to create the app from scratch on Microsoft App domain.

This commit is contained in:
Rodrigo Rodriguez (pragmatismo.io) 2018-10-30 19:52:40 -03:00
parent 028a4455ea
commit fa8e310a2e
77 changed files with 165 additions and 96 deletions

2
.gitignore vendored
View file

@ -1,5 +1,5 @@
node_modules
/deploy/default.gbui/build
/packages/default.gbui/build
/dist
/guaribas.sqlite
/guaribas.log

View file

@ -1,5 +1,5 @@
node_modules
/deploy/default.gbui/build
/packages/default.gbui/build
/guaribas.sqlite
/guaribas.log
/work

View file

@ -29,7 +29,7 @@ Package Quick Reference
------------
|Whatsapp|Web|Core|KB|
|----|-----|----|----|
|[whatsapp.gblib](https://github.com/pragmatismo-io/BotServer/tree/master/deploy/whatsapp.gblib)|[default.gbui](https://github.com/pragmatismo-io/BotServer/tree/master/deploy/default.gbui)|[core.gbapp](https://github.com/pragmatismo-io/BotServer/tree/master/deploy/core.gbapp)|[kb.gbapp](https://github.com/pragmatismo-io/BotServer/tree/master/deploy/kb.gbapp)|
|[whatsapp.gblib](https://github.com/pragmatismo-io/BotServer/tree/master/packages/whatsapp.gblib)|[default.gbui](https://github.com/pragmatismo-io/BotServer/tree/master/packages/default.gbui)|[core.gbapp](https://github.com/pragmatismo-io/BotServer/tree/master/packages/core.gbapp)|[kb.gbapp](https://github.com/pragmatismo-io/BotServer/tree/master/packages/kb.gbapp)|
![General Bot Logo](https://raw.githubusercontent.com/pragmatismo-io/BotServer/master/docs/images/general-bots-stack.png)
@ -86,7 +86,7 @@ Note:
6. Clone the just forked repository by running `git clone <your-forked-repository-url>/BotServer.git` ;
7. Run `npm install -g typescript`;
8. Run `npm install` on Command Prompt or PowerShell on the General Bot source-code folder;
9. Enter './deploy/default.gbui' folder;
9. Enter './packages/default.gbui' folder;
10. Run `npm install` folled by `npm run build` (To build default Bot UI);
11. Enter the On the downloaded folder (../..);
12. Compile the bot server by `tsc`.

View file

@ -57,7 +57,7 @@ export class AdminDialog extends IGBDialog {
let deployer = new GBDeployer(min.core, importer);
await deployer.undeployPackageFromLocalPath(
min.instance,
UrlJoin("deploy", packageName)
UrlJoin("packages", packageName)
);
}

View file

@ -36,14 +36,17 @@ import { GuaribasAdmin } from "../models/AdminModel";
import { IGBCoreService } from "botlib";
import { AuthenticationContext, TokenResponse } from "adal-node";
const UrlJoin = require("url-join");
const ngrok = require("ngrok");
const msRestAzure = require("ms-rest-azure");
const PasswordGenerator = require("strict-password-generator").default;
export class GBAdminService {
static generateUuid(): string {
return msRestAzure.generateUuid();
}
static masterBotInstanceId = 0;
public static StrongRegex = new RegExp(
"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*\+_\-])(?=.{8,})"
"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*+_-])(?=.{8,})"
);
core: IGBCoreService;
@ -76,6 +79,37 @@ export class GBAdminService {
return Promise.resolve(obj.value);
}
public static async acquireMsGraphTokenFromUsername(username, password) {
return new Promise<string>(async (resolve, reject) => {
let resource = "https://graph.microsoft.com";
let authenticatorAuthorityHostUrl = "https://login.microsoftonline.com";
let authenticatorTenant = "pragmatismo.onmicrosoft.com";
let authenticatorClientId = "0ffice19-91d5-41ea-98a4-ceea1655cc0b";
let authorizationUrl = UrlJoin(
authenticatorAuthorityHostUrl,
authenticatorTenant,
"/oauth2/authorize"
);
var authenticationContext = new AuthenticationContext(authorizationUrl);
authenticationContext.acquireTokenWithUsernamePassword(
resource,
username,
password,
authenticatorClientId,
async (err, res) => {
if (err) {
reject(err);
} else {
let token = res as TokenResponse;
resolve(token.accessToken);
}
}
);
});
}
public async acquireElevatedToken(instanceId): Promise<string> {
return new Promise<string>(async (resolve, reject) => {
let instance = await this.core.loadInstanceById(instanceId);
@ -91,10 +125,9 @@ export class GBAdminService {
"/oauth2/authorize"
);
var authenticationContext = new AuthenticationContext(authorizationUrl);
let refreshToken = await this.getValue(instanceId, "refreshToken");
let resource = "https://graph.microsoft.com";
var authenticationContext = new AuthenticationContext(authorizationUrl);
authenticationContext.acquireTokenWithRefreshToken(
refreshToken,
instance.authenticatorClientId,
@ -104,27 +137,65 @@ export class GBAdminService {
if (err) {
reject(err);
} else {
let tokens = res as TokenResponse;
let token = res as TokenResponse;
await this.setValue(
instanceId,
"accessToken",
tokens.accessToken
token.accessToken
);
await this.setValue(
instanceId,
"refreshToken",
tokens.refreshToken
token.refreshToken
);
await this.setValue(
instanceId,
"expiresOn",
tokens.expiresOn.toString()
token.expiresOn.toString()
);
resolve(tokens.accessToken);
resolve(token.accessToken);
}
}
);
}
});
}
public static async getADALTokenFromUsername(
username: string,
password: string
) {
let credentials = await GBAdminService.getADALCredentialsFromUsername(
username,
password
);
let accessToken = credentials.tokenCache._entries[0].accessToken;
return accessToken;
}
public static async getADALCredentialsFromUsername(
username: string,
password: string
) {
let credentials = await msRestAzure.loginWithUsernamePassword(
username,
password
);
return credentials;
}
public static getRndPassword() {
const passwordGenerator = new PasswordGenerator();
const options = {
upperCaseAlpha: true,
lowerCaseAlpha: true,
number: true,
specialCharacter: true,
minimumLength: 12,
maximumLength: 14
};
let password = passwordGenerator.generatePassword(options);
password = password.replace(/[=:;\?]/g, "");
return password;
}
}

View file

@ -45,15 +45,14 @@ import { SearchManagementClient } from "azure-arm-search";
import { WebResource, ServiceClient, HttpMethods } from "ms-rest-js";
import * as simplegit from "simple-git/promise";
import { AppServicePlan } from "azure-arm-website/lib/models";
import { GBConfigService } from "../../../deploy/core.gbapp/services/GBConfigService";
import { GBConfigService } from "../../../packages/core.gbapp/services/GBConfigService";
import { GBAdminService } from "../../../packages/admin.gbapp/services/GBAdminService";
const Spinner = require("cli-spinner").Spinner;
const scanf = require("scanf");
const msRestAzure = require("ms-rest-azure");
const git = simplegit();
const logger = require("../../../src/logger");
const UrlJoin = require("url-join");
const PasswordGenerator = require("strict-password-generator").default;
const iconUrl =
"https://github.com/pragmatismo-io/BotServer/blob/master/docs/images/generalbots-logo-squared.png";
const publicIp = require("public-ip");
@ -92,6 +91,9 @@ export class AzureDeployerService extends GBService {
let keys: any;
let name = instance.botId;
instance.marketplacePassword = GBAdminService.getRndPassword();
await this.internalDeployApp(name, instance.marketplacePassword)
logger.info(`Deploying Deploy Group (It may take a few minutes)...`);
await this.createDeployGroup(name, instance.cloudLocation);
@ -108,8 +110,8 @@ export class AzureDeployerService extends GBService {
instance.cloudLocation
);
let administratorLogin = AzureDeployerService.getRndAdminAccount();
let administratorPassword = AzureDeployerService.getRndPassword();
let administratorLogin = `sa${GBAdminService.getRndPassword()}`;
let administratorPassword = GBAdminService.getRndPassword();
logger.info(`Deploying Bot Storage...`);
let storageServer = `${name}-storage-server`;
@ -193,7 +195,7 @@ export class AzureDeployerService extends GBService {
culture,
instance.nlpAuthoringKey
);
let appId = msRestAzure.generateUuid();
let appId = GBAdminService.generateUuid();
instance.nlpEndpoint = nlp.endpoint;
instance.nlpKey = keys.key1;
instance.nlpAppId = nlpAppId;
@ -218,19 +220,18 @@ export class AzureDeployerService extends GBService {
let password = GBConfigService.get("CLOUD_PASSWORD");
let subscriptionId = GBConfigService.get("CLOUD_SUBSCRIPTIONID");
let credentials = await msRestAzure.loginWithUsernamePassword(
let credentials = await GBAdminService.getADALCredentialsFromUsername(
username,
password
);
let storageClient = new SqlManagementClient(credentials, subscriptionId);
let ip = await publicIp.v4();
let params = {
startIpAddress: ip,
endIpAddress: ip
};
let storageClient = new SqlManagementClient(credentials, subscriptionId);
await storageClient.firewallRules.createOrUpdate(
groupName,
serverName,
@ -298,7 +299,7 @@ export class AzureDeployerService extends GBService {
// Connects to the cloud and retrives subscriptions.
let credentials = await msRestAzure.loginWithUsernamePassword(
let credentials = await GBAdminService.getADALCredentialsFromUsername(
username,
password
);
@ -342,7 +343,7 @@ export class AzureDeployerService extends GBService {
instance.cloudSubscriptionId = subscriptionId;
instance.cloudLocation = location;
instance.nlpAuthoringKey = authoringKey;
instance.adminPass = AzureDeployerService.getRndPassword();
instance.adminPass = GBAdminService.getRndPassword();
this.resourceClient = new ResourceManagementClient.default(
credentials,
@ -423,13 +424,46 @@ export class AzureDeployerService extends GBService {
req.headers = {};
req.headers["Content-Type"] = "application/json; charset=utf-8";
req.headers["accept-language"] = "*";
req.headers["x-ms-client-request-id"] = msRestAzure.generateUuid();
req.headers["x-ms-client-request-id"] = GBAdminService.generateUuid();
req.headers["Authorization"] = "Bearer " + accessToken;
let httpClient = new ServiceClient();
let res = await httpClient.sendRequest(req);
}
private async internalDeployApp(name, pass) {
let username = GBConfigService.get("CLOUD_USERNAME");
let password = GBConfigService.get("CLOUD_PASSWORD");
let accessToken = await GBAdminService.acquireMsGraphTokenFromUsername(username, password);
let graphUrl = "https://graph.microsoft.com";
let expiresOn = new Date().toISOString();
let parameters = {
displayName: name,
passwordCredentials: [
{
secretText: pass,
endDateTime: expiresOn
}
]
};
let req = new WebResource();
req.method = "POST";
req.url = `${graphUrl}/beta/applications`;
req.headers = {};
req.headers["Content-Type"] = "application/json; charset=utf-8";
req.headers["accept-language"] = "*";
req.headers["x-ms-client-request-id"] = GBAdminService.generateUuid();
req.headers["Authorization"] = "Bearer " + accessToken;
req.body = parameters;
let httpClient = new ServiceClient();
return await httpClient.sendRequest(req);
}
/**
* @see https://github.com/Azure/azure-rest-api-specs/blob/master/specification/botservice/resource-manager/Microsoft.BotService/preview/2017-12-01/botservice.json
*/
@ -451,7 +485,7 @@ export class AzureDeployerService extends GBService {
let baseUrl = `https://management.azure.com/`;
await this.registerProviders(subscriptionId, baseUrl, accessToken);
let appPassword = AzureDeployerService.getRndPassword();
let appPassword = GBAdminService.getRndPassword();
let parameters = {
location: location,
@ -459,7 +493,7 @@ export class AzureDeployerService extends GBService {
name: "F0"
},
name: botId,
kind: "sdk",
kind: "bot",
properties: {
description: description,
displayName: name,
@ -468,12 +502,13 @@ export class AzureDeployerService extends GBService {
luisAppIds: [nlpAppId],
luisKey: nlpKey,
msaAppId: appId,
msaAppPassword: appPassword
msaAppPassword: appPassword,
enabledChannels: ["webchat", "skype", "facebook"],
configuredChannels: ["webchat", "skype", "facebook"]
}
};
let httpClient = new ServiceClient();
let query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${
this.provider
}/botServices/${botId}?api-version=${AzureDeployerService.apiVersion}`;
@ -520,16 +555,14 @@ export class AzureDeployerService extends GBService {
});
}
public async updateBotProxy(botId, group, endpoint) {
public async updateBotProxy(botId, group, endpoint) {
let baseUrl = `https://management.azure.com/`;
let username = GBConfigService.get("CLOUD_USERNAME");
let password = GBConfigService.get("CLOUD_PASSWORD");
let subscriptionId = GBConfigService.get("CLOUD_SUBSCRIPTIONID");
let credentials = await msRestAzure.loginWithUsernamePassword(
username,
password
);
let accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
let httpClient = new ServiceClient();
let parameters = {
properties: {
@ -537,9 +570,6 @@ export class AzureDeployerService extends GBService {
}
};
let accessToken = credentials.tokenCache._entries[0].accessToken;
let httpClient = new ServiceClient();
let query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${
this.provider
}/botServices/${botId}?api-version=${AzureDeployerService.apiVersion}`;
@ -763,6 +793,9 @@ export class AzureDeployerService extends GBService {
numberOfWorkers: 1,
phpVersion: "5.5"
};
// TODO: Copy .env to app settings.
return this.webSiteClient.webApps.createOrUpdateConfiguration(
group,
name,
@ -770,41 +803,9 @@ export class AzureDeployerService extends GBService {
);
}
private deleteDeploy(name) {
return this.resourceClient.resourceGroups.deleteMethod(name);
}
async deployGeneralBotsToAzure() {
let status = await git.status();
}
private static getRndAdminAccount() {
const passwordGenerator = new PasswordGenerator();
const options = {
upperCaseAlpha: false,
lowerCaseAlpha: true,
number: true,
specialCharacter: false,
minimumLength: 8,
maximumLength: 8
};
let generated = passwordGenerator.generatePassword(options);
return `sa${generated}`;
}
private static getRndPassword() {
const passwordGenerator = new PasswordGenerator();
const options = {
upperCaseAlpha: true,
lowerCaseAlpha: true,
number: true,
specialCharacter: true,
minimumLength: 12,
maximumLength: 14
};
let password = passwordGenerator.generatePassword(options);
password = password.replace(/[=:;\?]/g, "");
return password;
// TODO: Copy github to webapp.
}
static getKBSearchSchema(indexName) {

View file

@ -52,12 +52,9 @@ import { AzureDeployerService } from "../../azuredeployer.gbapp/services/AzureDe
/** Deployer service for bots, themes, ai and more. */
export class GBDeployer {
core: IGBCoreService;
importer: GBImporter;
workDir: string = "./work";
static deployFolder = "deploy";
static deployFolder = "packages";
constructor(core: IGBCoreService, importer: GBImporter) {
this.core = core;
@ -123,7 +120,7 @@ export class GBDeployer {
gbappPackages.forEach(e => {
// Skips .gbapp inside deploy folder.
if (!e.startsWith("deploy")) {
if (!e.startsWith("packages")) {
logger.info(`Deploying app: ${e}...`);
import(e)
.then(m => {
@ -374,7 +371,7 @@ export class GBDeployer {
*
*/
async scanBootPackage() {
const deployFolder = "deploy";
const deployFolder = "packages";
let bootPackage = GBConfigService.get("BOOT_PACKAGE");
if (bootPackage === "none") {

View file

Before

Width:  |  Height:  |  Size: 693 B

After

Width:  |  Height:  |  Size: 693 B

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View file

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

@ -37,22 +37,22 @@ const logger = require("./logger");
const express = require("express");
const bodyParser = require("body-parser");
import { GBConfigService } from "../deploy/core.gbapp/services/GBConfigService";
import { GBConversationalService } from "../deploy/core.gbapp/services/GBConversationalService";
import { GBMinService } from "../deploy/core.gbapp/services/GBMinService";
import { GBDeployer } from "../deploy/core.gbapp/services/GBDeployer";
import { GBWhatsappPackage } from "./../deploy/whatsapp.gblib/index";
import { GBCoreService } from "../deploy/core.gbapp/services/GBCoreService";
import { GBImporter } from "../deploy/core.gbapp/services/GBImporter";
import { GBAnalyticsPackage } from "../deploy/analytics.gblib";
import { GBCorePackage } from "../deploy/core.gbapp";
import { GBKBPackage } from "../deploy/kb.gbapp";
import { GBSecurityPackage } from "../deploy/security.gblib";
import { GBAdminPackage } from "../deploy/admin.gbapp/index";
import { GBCustomerSatisfactionPackage } from "../deploy/customer-satisfaction.gbapp";
import { GBAdminService } from "../deploy/admin.gbapp/services/GBAdminService";
import { GuaribasInstance } from "../deploy/core.gbapp/models/GBModel";
import { AzureDeployerService } from "../deploy/azuredeployer.gbapp/services/AzureDeployerService";
import { GBConfigService } from "../packages/core.gbapp/services/GBConfigService";
import { GBConversationalService } from "../packages/core.gbapp/services/GBConversationalService";
import { GBMinService } from "../packages/core.gbapp/services/GBMinService";
import { GBDeployer } from "../packages/core.gbapp/services/GBDeployer";
import { GBWhatsappPackage } from "./../packages/whatsapp.gblib/index";
import { GBCoreService } from "../packages/core.gbapp/services/GBCoreService";
import { GBImporter } from "../packages/core.gbapp/services/GBImporter";
import { GBAnalyticsPackage } from "../packages/analytics.gblib";
import { GBCorePackage } from "../packages/core.gbapp";
import { GBKBPackage } from "../packages/kb.gbapp";
import { GBSecurityPackage } from "../packages/security.gblib";
import { GBAdminPackage } from "../packages/admin.gbapp/index";
import { GBCustomerSatisfactionPackage } from "../packages/customer-satisfaction.gbapp";
import { GBAdminService } from "../packages/admin.gbapp/services/GBAdminService";
import { GuaribasInstance } from "../packages/core.gbapp/models/GBModel";
import { AzureDeployerService } from "../packages/azuredeployer.gbapp/services/AzureDeployerService";
import { IGBPackage, IGBInstance } from "botlib";
let appPackages = new Array<IGBPackage>();

View file

@ -22,8 +22,8 @@
"include": [
"test/**/*",
"src/**/*",
"deploy/*.gbapp/**/*",
"deploy/*.gblib/**/*"
"packages/*.gbapp/**/*",
"packages/*.gblib/**/*"
],
"exclude": ["dist", "node_modules"]
}