<commit_before>import SparkPlugin from '@ciscospark/spark-core';
import JSZip from 'jszip';
import saveAs from 'file-saver';
import MimeBuilder from 'emailjs-mime-builder';

/**
 * @class ReportGenerator is used to compile, zip, and save an eDiscovery report to disk.
 *
 * Warning: This file is browser specific. It cannot function in a NodeJS server environment.
 */
const ReportGenerator = SparkPlugin.extend({
  namespace: 'Ediscovery',

  props: {
    spark: 'object',
    reportId: 'string',
    zip: 'object',
    folder: 'object',
    spaces: 'object'
  },

  /**
   * Create a new report-generator specific to one report.
   *
   * @param {Object} attrs reportId must be included.
   * @param {Object} options Additional options passed up to the parent.
   * @returns {Object} A report generator object.
   */
  initialize(attrs, options) {
    Reflect.apply(SparkPlugin.prototype.initialize, this, [attrs, options]);

    if (!attrs || !attrs.reportId) {
      throw new Error('Missing Required Argument reportId');
    }

    if (!attrs || !attrs.spark) {
      throw new Error('Missing Required Argument spark');
    }

    this.reportId = attrs.reportId;
    this.spark = attrs.spark;
  },

  /**
   * Map an activity to an MIME rfc822 formated string that can be saved as an eml file.
   * @param {Object} activity An activity object
   * @returns {String} A string that represents the data stored in an eml file.
   */
  map(activity) {
    if (!activity) {
      throw new Error('Invalid activity');
    }

    const mime = new MimeBuilder('multipart/mixed')
      .setHeader('From', 'Mr Todo <<EMAIL>>') // TODO: activity.actorId is now a UUID which cannot be parsed by MimeBuilder
      .setHeader('To', 'Foo Bar <<EMAIL>>')
      .setHeader('Subject', activity.activityId)
      .setHeader('Date', activity.timestamp);

    let content = activity.objectDisplayName;
    if (activity.verb !== 'post') {
      content = activity.verb;
      // Include the target of the event. e.g. Add Person
      if (activity.objectId) {
        content += ` ${activity.objectId}`;
      }
    }

    mime.createChild('text/plain')
      .setContent(content);

    return mime.build();
  },

  /**
   * Decrypt the messages found on the activities.
   * @param {Object[]} activities An array of activities with encrypted messages
   * @returns {Promise<[any]>} The activities with their messages decrypted
   */
  decrypt(activities) {
    const promises = [];
    for (let i = 0; i < activities.length; i += 1) {
      const activity = activities[i];
      if (activity.verb === 'post' && activity.encryptionKeyUrl) {
        const promise = this.spark.internal.encryption.decryptText(activity.encryptionKeyUrl, activity.objectDisplayName, activity.actorId)
          .then((decryptedMessage) => {
            // Replace encrypted message with the decrypted version
            activity.objectDisplayName = decryptedMessage;
            return activity;
          })
          .catch((error) => {
            this.logger.error(`Unable to decrypt message due to error: ${error}`);
            return activity;
          });
        promises.push(promise);
      }
      else {
        promises.push(Promise.resolve(activity));
      }
    }

    return Promise.all(promises);
  },

  /**
   * Add activities to the report.
   * @param {Object[]} activities Activities that are to form part of the report
   * @returns {Void}
   */
  add(activities) {
    if (!activities || !Array.isArray(activities) || !activities.length) {
      throw new Error('No supplied activities to add');
    }

    this.decrypt(activities).then((activities) => {
      if (!this.zip) {
        this.logger.info('Creating Zip');
        this.zip = new JSZip();
        // Top level zip folder is based on the report id
        this.folder = this.zip.folder(`${this.reportId}`);
        this.spaces = {};
      }

      for (let i = 0; i < activities.length; i += 1) {
        const activity = activities[i];

        // If there is no target id use the report id folder
        let space = this.folder;
        if (activity.targetId) {
          if (!(activity.targetId in this.spaces)) {
            // Create sub-folder for space id
            this.spaces[activity.targetId] = this.folder.folder(`${activity.targetId}`);
          }

          space = this.spaces[activity.targetId];
        }

        const data = this.map(activity);
        space.file(`${activity.activityId}.eml`, data);
      }
    });
  },

  /**
   * Once all the activities have been added create a report and save it to disk.
   * @returns {Promise} A promise on the generated report
   */
  saveAs() {
    if (!this.zip) {
      throw new Error('No activities added to report');
    }

    this.logger.info('Creating Zip File');
    return this.zip.generateAsync({type: 'blob'})
      .then((content) => {
        // Download to the user's browser
        this.logger.info('Downloading...');
        saveAs(content, `${this.reportId}.zip`);
      });
  }
});

export default ReportGenerator;<commit_msg>feat(ediscovery): removing decryption from report-generator<commit_after>import SparkPlugin from '@ciscospark/spark-core';
import JSZip from 'jszip';
import saveAs from 'file-saver';
import MimeBuilder from 'emailjs-mime-builder';

/**
 * @class ReportGenerator is used to compile, zip, and save an eDiscovery report to disk.
 *
 * Warning: This file is browser specific. It cannot function in a NodeJS server environment.
 */
const ReportGenerator = SparkPlugin.extend({
  namespace: 'Ediscovery',

  props: {
    spark: 'object',
    reportId: 'string',
    zip: 'object',
    folder: 'object',
    spaces: 'object'
  },

  /**
   * Create a new report-generator specific to one report.
   *
   * @param {Object} attrs reportId must be included.
   * @param {Object} options Additional options passed up to the parent.
   * @returns {Object} A report generator object.
   */
  initialize(attrs, options) {
    Reflect.apply(SparkPlugin.prototype.initialize, this, [attrs, options]);

    if (!attrs || !attrs.reportId) {
      throw new Error('Missing Required Argument reportId');
    }

    if (!attrs || !attrs.spark) {
      throw new Error('Missing Required Argument spark');
    }

    this.reportId = attrs.reportId;
    this.spark = attrs.spark;
  },

  /**
   * Map an activity to an MIME rfc822 formated string that can be saved as an eml file.
   * @param {Object} activity An activity object
   * @returns {String} A string that represents the data stored in an eml file.
   */
  map(activity) {
    if (!activity) {
      throw new Error('Invalid activity');
    }

    const mime = new MimeBuilder('multipart/mixed')
      .setHeader('From', 'Mr Todo <<EMAIL>>') // TODO: activity.actorId is now a UUID which cannot be parsed by MimeBuilder
      .setHeader('To', 'Foo Bar <<EMAIL>>')
      .setHeader('Subject', activity.activityId)
      .setHeader('Date', activity.timestamp);

    let content = activity.objectDisplayName;
    if (activity.verb !== 'post') {
      content = activity.verb;
      // Include the target of the event. e.g. Add Person
      if (activity.objectId) {
        content += ` ${activity.objectId}`;
      }
    }

    mime.createChild('text/plain')
      .setContent(content);

    return mime.build();
  },

  /**
   * Add activities to the report.
   * @param {Object[]} activities Activities that are to form part of the report
   * @returns {Void}
   */
  add(activities) {
    if (!activities || !Array.isArray(activities) || !activities.length) {
      throw new Error('No supplied activities to add');
    }


    if (!this.zip) {
      this.logger.info('Creating Zip');
      this.zip = new JSZip();
      // Top level zip folder is based on the report id
      this.folder = this.zip.folder(`${this.reportId}`);
      this.spaces = {};
    }

    for (let i = 0; i < activities.length; i += 1) {
      const activity = activities[i];

      // If there is no target id use the report id folder
      let space = this.folder;
      if (activity.targetId) {
        if (!(activity.targetId in this.spaces)) {
          // Create sub-folder for space id
          this.spaces[activity.targetId] = this.folder.folder(`${activity.targetId}`);
        }

        space = this.spaces[activity.targetId];
      }

      const data = this.map(activity);
      space.file(`${activity.activityId}.eml`, data);
    }
  },

  /**
   * Once all the activities have been added create a report and save it to disk.
   * @returns {Promise} A promise on the generated report
   */
  saveAs() {
    if (!this.zip) {
      throw new Error('No activities added to report');
    }

    this.logger.info('Creating Zip File');
    return this.zip.generateAsync({type: 'blob'})
      .then((content) => {
        // Download to the user's browser
        this.logger.info('Downloading...');
        saveAs(content, `${this.reportId}.zip`);
      });
  }
});

export default ReportGenerator;
{'fraction_non_alphanumeric': 0.12905021712504175, 'fraction_numerical': 0.0013361541031065582, 'mean_word_length': 2.6676194365046957, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5455571', 'n_tokens_mistral': 2652, 'n_tokens_neox': 2571, 'n_words': 808}