Przeglądaj źródła

Merge pull request #3883 from weseek/imprv/gw6231-add-url-validation-to-register-modal

Imprv/gw6231 add url validation to register modal
Yuki Takei 4 lat temu
rodzic
commit
92150c1409

+ 1 - 0
packages/slack/package.json

@@ -19,6 +19,7 @@
     "browser-bunyan": "^1.6.3",
     "browser-bunyan": "^1.6.3",
     "bunyan": "^1.8.15",
     "bunyan": "^1.8.15",
     "dotenv-flow": "^3.2.0",
     "dotenv-flow": "^3.2.0",
+    "extensible-custom-error": "^0.0.7",
     "universal-bunyan": "^0.9.2"
     "universal-bunyan": "^0.9.2"
   },
   },
   "devDependencies": {
   "devDependencies": {

+ 2 - 8
packages/slack/src/models/errors.ts

@@ -1,9 +1,3 @@
-export class InvalidGrowiCommandError extends Error {
+import ExtensibleCustomError from 'extensible-custom-error';
 
 
-  constructor(e?: string) {
-    super(e);
-    this.name = new.target.name;
-    Object.setPrototypeOf(this, new.target.prototype);
-  }
-
-}
+export class InvalidGrowiCommandError extends ExtensibleCustomError {}

+ 1 - 0
packages/slackbot-proxy/package.json

@@ -39,6 +39,7 @@
     "dotenv-flow": "^3.2.0",
     "dotenv-flow": "^3.2.0",
     "express-bunyan-logger": "^1.3.3",
     "express-bunyan-logger": "^1.3.3",
     "express-graceful-exit": "=0.5.0",
     "express-graceful-exit": "=0.5.0",
+    "extensible-custom-error": "^0.0.7",
     "helmet": "^4.6.0",
     "helmet": "^4.6.0",
     "method-override": "^3.0.0",
     "method-override": "^3.0.0",
     "mysql2": "^2.2.5",
     "mysql2": "^2.2.5",

+ 13 - 3
packages/slackbot-proxy/src/controllers/slack.ts

@@ -20,6 +20,7 @@ import { AuthorizeCommandMiddleware, AuthorizeInteractionMiddleware } from '~/mi
 import { InstallerService } from '~/services/InstallerService';
 import { InstallerService } from '~/services/InstallerService';
 import { RegisterService } from '~/services/RegisterService';
 import { RegisterService } from '~/services/RegisterService';
 import { UnregisterService } from '~/services/UnregisterService';
 import { UnregisterService } from '~/services/UnregisterService';
+import { InvalidUrlError } from '../models/errors';
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
 
 
@@ -186,10 +187,19 @@ export class SlackCtrl {
     const callBackId = payload?.view?.callback_id;
     const callBackId = payload?.view?.callback_id;
 
 
     // register
     // register
-    // response_urls is an array but the element included is only one.
     if (callBackId === 'register') {
     if (callBackId === 'register') {
-      await this.registerService.upsertOrderRecord(this.orderRepository, installation, payload);
-      await this.registerService.notifyServerUriToSlack(authorizeResult, payload);
+      try {
+        await this.registerService.insertOrderRecord(this.orderRepository, installation, authorizeResult.botToken, payload);
+      }
+      catch (err) {
+        if (err instanceof InvalidUrlError) {
+          logger.info(err.message);
+          return;
+        }
+        logger.error(err);
+      }
+
+      await this.registerService.notifyServerUriToSlack(authorizeResult.botToken, payload);
       return;
       return;
     }
     }
 
 

+ 9 - 0
packages/slackbot-proxy/src/models/errors.ts

@@ -0,0 +1,9 @@
+import ExtensibleCustomError from 'extensible-custom-error';
+
+export class InvalidUrlError extends ExtensibleCustomError {
+
+  constructor(url: string) {
+    super(`Invalid URL: ${url}`);
+  }
+
+}

+ 30 - 4
packages/slackbot-proxy/src/services/RegisterService.ts

@@ -5,6 +5,7 @@ import { AuthorizeResult } from '@slack/oauth';
 import { GrowiCommandProcessor } from '~/interfaces/slack-to-growi/growi-command-processor';
 import { GrowiCommandProcessor } from '~/interfaces/slack-to-growi/growi-command-processor';
 import { OrderRepository } from '~/repositories/order';
 import { OrderRepository } from '~/repositories/order';
 import { Installation } from '~/entities/installation';
 import { Installation } from '~/entities/installation';
+import { InvalidUrlError } from '../models/errors';
 
 
 const isProduction = process.env.NODE_ENV === 'production';
 const isProduction = process.env.NODE_ENV === 'production';
 
 
@@ -43,15 +44,41 @@ export class RegisterService implements GrowiCommandProcessor {
     });
     });
   }
   }
 
 
-  async upsertOrderRecord(
+  async insertOrderRecord(
+      orderRepository: OrderRepository, installation: Installation | undefined,
       // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
       // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-      orderRepository: OrderRepository, installation: Installation | undefined, payload: any,
+      botToken: string | undefined, payload: any,
   ): Promise<void> {
   ): Promise<void> {
     const inputValues = payload.view.state.values;
     const inputValues = payload.view.state.values;
     const growiUrl = inputValues.growiUrl.contents_input.value;
     const growiUrl = inputValues.growiUrl.contents_input.value;
     const tokenPtoG = inputValues.tokenPtoG.contents_input.value;
     const tokenPtoG = inputValues.tokenPtoG.contents_input.value;
     const tokenGtoP = inputValues.tokenGtoP.contents_input.value;
     const tokenGtoP = inputValues.tokenGtoP.contents_input.value;
 
 
+    const { channel } = JSON.parse(payload.view.private_metadata);
+
+    const client = new WebClient(botToken, { logLevel: isProduction ? LogLevel.DEBUG : LogLevel.INFO });
+
+    try {
+      // eslint-disable-next-line @typescript-eslint/no-unused-vars
+      const url = new URL(growiUrl);
+    }
+    catch (error) {
+      const invalidErrorMsg = 'Please enter a valid URL';
+
+      await client.chat.postEphemeral({
+        channel,
+        user: payload.user.id,
+        // Recommended including 'text' to provide a fallback when using blocks
+        // refer to https://api.slack.com/methods/chat.postEphemeral#text_usage
+        text: 'Invalid URL',
+        blocks: [
+          generateMarkdownSectionBlock(invalidErrorMsg),
+        ],
+      });
+
+      throw new InvalidUrlError(growiUrl);
+    }
+
     orderRepository.save({
     orderRepository.save({
       installation, growiUrl, tokenPtoG, tokenGtoP,
       installation, growiUrl, tokenPtoG, tokenGtoP,
     });
     });
@@ -59,10 +86,9 @@ export class RegisterService implements GrowiCommandProcessor {
 
 
   async notifyServerUriToSlack(
   async notifyServerUriToSlack(
       // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
       // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-      authorizeResult:AuthorizeResult, payload: any,
+      botToken: string | undefined, payload: any,
   ): Promise<void> {
   ): Promise<void> {
 
 
-    const { botToken } = authorizeResult;
     const { channel } = JSON.parse(payload.view.private_metadata);
     const { channel } = JSON.parse(payload.view.private_metadata);
 
 
     const serverUri = process.env.SERVER_URI;
     const serverUri = process.env.SERVER_URI;

+ 5 - 0
yarn.lock

@@ -8087,6 +8087,11 @@ extend@^3.0.2, extend@~3.0.2:
   version "3.0.2"
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
   resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
 
 
+extensible-custom-error@^0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/extensible-custom-error/-/extensible-custom-error-0.0.7.tgz#4d6cc86c71d60a0e11fa8d24972104720cd30305"
+  integrity sha512-1tgubPkgC+Qi2nUpulI7hGddHh0fA8hXu3P0LBUq2pamZL52KSJZqMu8Q3CiA6kf7Irn/CU1fJe6y4igHCwu4Q==
+
 external-editor@^3.0.3:
 external-editor@^3.0.3:
   version "3.0.3"
   version "3.0.3"
   resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27"
   resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27"