'use strict';

var crypto = require('crypto');

var InstanceResource = require('./InstanceResource');
var utils = require('../utils');

/**
 * @class ApiKey
 *
 * @extends {InstanceResource}
 *
 * @description
 *
 * Encapsulates an Api Key resource of an {@link Account}. For full
 * documentation of this resource, please see
 * [REST API Reference: Account API Keys](https://docs.stormpath.com/rest/product-guide/latest/reference.html?#account-api-keys).
 *
 * These keys can be used to authenticate requests to your web framework.
 * For a high-level overview of this feature, please read [Using Stormpath for
 * API Authentication](https://docs.stormpath.com/guides/api-key-management). If
 * you are using [Express-Stormath](http://docs.stormpath.com/nodejs/express/latest),
 * please read the [Authentication Section](http://docs.stormpath.com/nodejs/express/latest/authentication.html).
 *
 * This class should not be manually constructed. It should be obtained from one
 * of these methods:
 *
 * - {@link Account#getApiKeys Account.getApiKeys()}
 * - {@link Application#getApiKey Application.getApiKey()}
 *
 * @param {Object} apiKeyResource
 *
 * The JSON representation of this resource, retrieved the Stormpath REST API.
 */
function ApiKey() {
  ApiKey.super_.apply(this, arguments);
}

utils.inherits(ApiKey, InstanceResource);


ApiKey.prototype._getDecryptedSecret = function _getDecryptedSecret(callback) {
  var salt = this.apiKeyMetaData.encryptionKeySalt;
  var iterations = this.apiKeyMetaData.encryptionKeyIterations;
  var keyLengthBits = this.apiKeyMetaData.encryptionKeySize;
  var password = new Buffer(this.dataStore.requestExecutor.options.client.apiKey.secret);
  var encryptedSecret = new Buffer(this.secret,'base64');
  var iv = encryptedSecret.slice(0,16);
  var rawEncryptedValue = encryptedSecret.slice(16);
  crypto.pbkdf2(password,new Buffer(salt,'base64'),iterations,(keyLengthBits/8), 'sha1',function(err,key){
    if(err){
      return callback(err);
    }
    var decrypted;
    try{
      var algo = keyLengthBits === 128 ? 'aes-128-cbc':'aes-256-cbc';
      var decipher = crypto.createDecipheriv(algo, key, iv);
      decrypted = decipher.update(rawEncryptedValue,'binary','utf8');
      decrypted += decipher.final('utf8');
    }catch(e){
      return callback(e);
    }
    callback(null,decrypted);
  });
};

ApiKey.prototype._setApiKeyMetaData = function _setApiKeyMetaData(obj){
  this.apiKeyMetaData = obj && obj.encryptSecret ? obj : null;
};

ApiKey.prototype._decrypt = function _decrypt(callback) {
  var self = this;
  if(self.apiKeyMetaData){
    self._getDecryptedSecret(function(err,secret){
      if(err){
        return callback(err);
      }
      self.secret = secret;
      delete self.apiKeyMetaData;
      callback(null,self);
    });
  }else{
    process.nextTick(callback.bind(null,null,self));
  }
};

/**
 * Retrieves the account resource associated with the ApiKey.
 *
 * @param {ExpansionOptions} [options]
 * For retrieving linked resources of the {@link Account} during this request.
 *
 * @param {Function} Callback
 * Callback function, will be called with (err, {@link Account account}).
 */
ApiKey.prototype.getAccount = function () {
  var args = utils.resolveArgs(arguments, ['options', 'callback'], true);
  return this.dataStore.getResource(this.account.href, args.options, require('./Account'), args.callback);
};

module.exports = ApiKey;

@@ -1841,31 +1841,22 @@
 ;%0A  
-crypto.pbkdf2(password,
+var saltBuf = 
 new 
@@ -1880,46 +1880,70 @@
 64')
-,iterations,(keyLengthBits/8), 'sha1',
+;%0A  var keyLength = keyLengthBits / 8;%0A  var cryptoCallback = 
 func
@@ -1951,16 +1951,17 @@
 ion(err,
+ 
 key)%7B%0A  
@@ -2357,18 +2357,278 @@
 ed);%0A  %7D
-)
 ;
+%0A%0A  try %7B%0A    crypto.pbkdf2(password,saltBuf,iterations,keyLength,'sha1',cryptoCallback);%0A  %7D catch (e) %7B%0A    // Node 0.10.0 support - It does not take the digest parameter, and throws%0A    crypto.pbkdf2(password,saltBuf,iterations,keyLength,cryptoCallback);%0A  %7D
 %0A%7D;%0A%0AApi

Add try-catch to support node 0.10