slack-app-integration.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import crypto from 'crypto';
  2. import { defaultSupportedSlackEventActions } from '@growi/slack';
  3. import mongoose from 'mongoose';
  4. import { getModelSafely } from '../util/mongoose-utils';
  5. const schema = new mongoose.Schema({
  6. tokenGtoP: { type: String, required: true, unique: true },
  7. tokenPtoG: { type: String, required: true, unique: true },
  8. isPrimary: { type: Boolean, unique: true, sparse: true },
  9. permissionsForBroadcastUseCommands: Map,
  10. permissionsForSingleUseCommands: Map,
  11. permissionsForSlackEventActions: {
  12. type: Map,
  13. default: new Map(defaultSupportedSlackEventActions.map(action => [action, false])),
  14. },
  15. });
  16. class SlackAppIntegration {
  17. crowi;
  18. static generateAccessTokens(saltForGtoP, saltForPtoG) {
  19. const now = new Date().getTime();
  20. const hasher1 = crypto.createHash('sha512');
  21. const hasher2 = crypto.createHash('sha512');
  22. const tokenGtoP = hasher1.update(`gtop-${saltForGtoP}-${now.toString()}`).digest('base64');
  23. const tokenPtoG = hasher2.update(`ptog-${saltForPtoG}-${now.toString()}`).digest('base64');
  24. return [tokenGtoP, tokenPtoG];
  25. }
  26. static async generateUniqueAccessTokens() {
  27. let duplicateTokens;
  28. let tokenGtoP;
  29. let tokenPtoG;
  30. let generateTokens;
  31. // get salt strings
  32. /** @type {import('~/server/crowi').default} Crowi instance */
  33. const crowi = this.crowi;
  34. const saltForGtoP = crowi.configManager.getConfig('slackbot:withProxy:saltForGtoP');
  35. const saltForPtoG = crowi.configManager.getConfig('slackbot:withProxy:saltForPtoG');
  36. do {
  37. generateTokens = this.generateAccessTokens(saltForGtoP, saltForPtoG);
  38. tokenGtoP = generateTokens[0];
  39. tokenPtoG = generateTokens[1];
  40. // eslint-disable-next-line no-await-in-loop
  41. duplicateTokens = await this.findOne({ $or: [{ tokenGtoP }, { tokenPtoG }] });
  42. } while (duplicateTokens != null);
  43. return { tokenGtoP, tokenPtoG };
  44. }
  45. }
  46. /** @param {import('~/server/crowi').default} crowi Crowi instance */
  47. const factory = (crowi) => {
  48. const modelExists = getModelSafely('SlackAppIntegration');
  49. if (modelExists != null) {
  50. return modelExists;
  51. }
  52. SlackAppIntegration.crowi = crowi;
  53. schema.loadClass(SlackAppIntegration);
  54. return mongoose.model('SlackAppIntegration', schema);
  55. };
  56. export default factory;