Code coverage report for api/confidentiality_encryption/Confidential.js

Statements: 85.25% (52 / 61)      Branches: 70.59% (24 / 34)      Functions: 100% (6 / 6)      Lines: 85.25% (52 / 61)      Ignored: none     

All files » api/confidentiality_encryption/ » Confidential.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174                1 1 1   1 1 1 1           1 1                                                       1 173 173   173 173 2 2   173                   1   1                                 117     117 16 16   117 20 20   117       117 117 117   117                           20   20   20 20 20 20 20 6 6         20           409 3   409     143     143     143     143           3 3   3           1  
/* globals window */
// var node_cryptojs = require("node-cryptojs-aes");
// var CryptoJS = node_cryptojs.CryptoJS;
 
//>> Error: Error: ENOENT, no such file or directory '$HOME/dative/.tmp/scripts/core.js'
// var forcingCoreToLoadForRequireJS = require("node-cryptojs-aes/lib/core");
 
// var CryptoEncoding =  {};// require("crypto-js/enc-utf8");
var FieldDBObject = require("./../FieldDBObject").FieldDBObject;
var CryptoJS = require("./Crypto_AES").CryptoJS;
var CryptoEncoding = CryptoJS.enc.Utf8;
 
var ATOB;
var BTOA;
try {
  if (!window.atob) {
    console.log("ATOB is not defined, loading from npm");
  }
  ATOB = window.atob;
  BTOA = window.btoa;
} catch (e) {
  ATOB = require("atob");
  BTOA = require("btoa");
}
 
/**
 * @class Confidential
 * @name Confidential
 *
 * @description makes it possible to generate pass phrases (one per
 *        corpus) to encrypt and decrypt confidential data points. The
 *        confidential data is stored encrypted, and can only be decrypted
 *        if one has the corpus" secret key, or if one is logged into the
 *        system with their user name and password. This allows the corpus
 *        to be shared with anyone, with out worrying about confidential
 *        data or consultant stories being publically accessible. We are
 *        using the AES cipher algorithm.
 *
 * The Advanced Encryption Standard (AES) is a U.S. Federal Information
 * Processing Standard (FIPS). It was selected after a 5-year process where
 * 15 competing designs were evaluated.
 *
 * <a href="http://code.google.com/p/crypto-js/">More information on
 * CryptoJS</a>
 *
 * @extends Object
 *
 * @constructs
 *
 */
var Confidential = function Confidential(options) {
  Eif (!this._fieldDBtype) {
    this._fieldDBtype = "Confidential";
  }
  this.debug("Constructing Confidential: ", options);
  if (options && options.filledWithDefaults) {
    this.fillWithDefaults();
    delete options.filledWithDefaults;
  }
  FieldDBObject.apply(this, arguments);
};
 
/**
 * The secretkeygenerator uses a "GUID" like generation to create a string
 * for the secret key.
 *
 * @returns {String} a string which is likely unique, in the format of a
 *          Globally Unique ID (GUID)
 */
Confidential.secretKeyGenerator = FieldDBObject.uuidGenerator;
 
Confidential.prototype = Object.create(FieldDBObject.prototype, /** @lends Confidential.prototype */ {
  constructor: {
    value: Confidential
  },
 
  /**
   * Encrypt accepts a string (UTF8) and returns a CryptoJS object, in base64
   * encoding so that it looks like a string, and can be saved as a string in
   * the corpus.
   *
   * @param message
   *          A UTF8 string
   * @returns Returns a base64 string prefixed with "confidential" so that the
   *          views can choose to not display the entire string for the user.
   */
  encrypt: {
    value: function(value) {
      Iif (!value) {
        return value;
      }
      if (typeof value === "object") {
        value = JSON.stringify(value);
        this.debug("Converted object to string before encryption");
      }
      if (typeof value === "number") {
        value = value + "";
        this.debug("Converted object to string before encryption");
      }
      Iif (!this.secretkey) {
        throw new Error("This confidential wasnt set up properly, cant encrypt.");
      }
      // this.debugMode = true;
      this.debug("encrypting " + value);
      var result = CryptoJS.AES.encrypt(value, this.secretkey.toString("base64"));
      this.verbose(this.secretkey, result.toString(), BTOA(result.toString()));
      // return the base64 version to save it as a string in the corpus
      return "confidential:" + BTOA(result.toString());
    }
  },
 
  /**
   * Decrypt uses this object's secret key to decode its parameter using the
   * AES algorithm.
   *
   * @param encrypted
   *          A base64 string prefixed (or not) with the word "confidential"
   * @returns Returns the encrypted result as a UTF8 string.
   */
  decrypt: {
    value: function(encrypted) {
      var result = encrypted;
 
      encrypted = encrypted.replace("confidential:", "");
      // decode base64
      encrypted = ATOB(encrypted);
      this.verbose("Decrypting " + encrypted, this.secretkey.toString("base64"));
      result = CryptoJS.AES.decrypt(encrypted, this.secretkey.toString("base64")).toString(CryptoEncoding);
      try {
        if ((result[0] === "{" && result[result.length - 1] === "}") || (result[0] === "[" && result[result.length - 1] === "]")) {
          result = JSON.parse(result);
          this.debug("Decrypting an object");
        }
      } catch (e) {
        this.verbose("Decrypting a non-object");
      }
      return result;
    }
  },
 
  secretkey: {
    get: function() {
      if (!this._secretkey) {
        this._secretkey = "";
      }
      return this._secretkey;
    },
    set: function(value) {
      Iif (value === this._secretkey) {
        return;
      }
      Iif (this._secretkey && this._secretkey.length > 2) {
        throw new Error("Confidential key cant be changed once it was created. Please create another Confidential encrypter if you wish to change the key.");
      }
      Iif (!value) {
        value = "";
      }
      this._secretkey = value.trim();
    }
  },
 
  fillWithDefaults: {
    value: function() {
      Eif (!this.secretkey) {
        this.secretkey = Confidential.secretKeyGenerator();
      }
      return this;
    }
  }
 
});
 
exports.Confidential = Confidential;