From d44c12e71825590677a54036676c8b03ddfca11c Mon Sep 17 00:00:00 2001 From: Rafsanul Hasan Date: Sun, 9 Sep 2018 05:45:35 +0600 Subject: [PATCH] Code re-factorings and formatting for Basket.API project --- .../Auth/Client/enable-token-client.js | 46 +- .../Auth/Client/oidc-token-manager.js | 17711 ++++++++-------- .../Basket/Basket.API/Auth/Client/popup.html | 12 +- ...orizationHeaderParameterOperationFilter.cs | 46 +- .../Auth/Server/IdentitySecurityScheme.cs | 28 +- .../Basket/Basket.API/BasketSettings.cs | 10 +- .../Controllers/BasketController.cs | 164 +- .../Basket.API/Controllers/HomeController.cs | 14 +- .../InternalServerErrorObjectResult.cs | 14 +- .../Exceptions/BasketDomainException.cs | 28 +- .../FailingMiddlewareAppBuilderExtensions.cs | 26 +- .../Filters/AuthorizeCheckOperationFilter.cs | 38 +- .../Filters/HttpGlobalExceptionFilter.cs | 78 +- .../Filters/JsonErrorResponse.cs | 10 +- .../Filters/ValidateModelStateFilter.cs | 40 +- .../Middlewares/ByPassAuthMiddleware.cs | 121 +- .../Middlewares/FailingMiddleware.cs | 134 +- .../Middlewares/FailingOptions.cs | 10 +- .../Middlewares/FailingStartupFilter.cs | 32 +- .../FailingWebHostBuilderExtensions.cs | 22 +- .../OrderStartedIntegrationEventHandler.cs | 24 +- ...ductPriceChangedIntegrationEventHandler.cs | 82 +- .../Events/OrderStartedIntegrationEvent.cs | 18 +- .../ProductPriceChangedIntegrationEvent.cs | 30 +- .../UserCheckoutAcceptedIntegrationEvent.cs | 80 +- .../Basket/Basket.API/Model/BasketCheckout.cs | 30 +- .../Basket/Basket.API/Model/BasketItem.cs | 38 +- .../Basket/Basket.API/Model/CustomerBasket.cs | 20 +- .../Basket.API/Model/IBasketRepository.cs | 14 +- .../Basket.API/Model/RedisBasketRepository.cs | 94 +- src/Services/Basket/Basket.API/Program.cs | 92 +- .../Basket.API/Services/IIdentityService.cs | 8 +- .../Basket.API/Services/IdentityService.cs | 24 +- src/Services/Basket/Basket.API/Startup.cs | 548 +- .../Basket/Basket.API/appsettings.json | 44 +- src/Services/Basket/Basket.API/web.config | 14 +- 36 files changed, 9862 insertions(+), 9882 deletions(-) diff --git a/src/Services/Basket/Basket.API/Auth/Client/enable-token-client.js b/src/Services/Basket/Basket.API/Auth/Client/enable-token-client.js index 3c207e7ea..195f51ce8 100644 --- a/src/Services/Basket/Basket.API/Auth/Client/enable-token-client.js +++ b/src/Services/Basket/Basket.API/Auth/Client/enable-token-client.js @@ -1,28 +1,28 @@ (function ($, swaggerUi) { - $(function () { - var settings = { - authority: 'https://localhost:5105', - client_id: 'js', - popup_redirect_uri: window.location.protocol - + '//' - + window.location.host - + '/tokenclient/popup.html', + $(function () { + var settings = { + authority: 'https://localhost:5105', + client_id: 'js', + popup_redirect_uri: window.location.protocol + + '//' + + window.location.host + + '/tokenclient/popup.html', - response_type: 'id_token token', - scope: 'openid profile basket', + response_type: 'id_token token', + scope: 'openid profile basket', - filter_protocol_claims: true - }, - manager = new OidcTokenManager(settings), - $inputApiKey = $('#input_apiKey'); + filter_protocol_claims: true + }, + manager = new OidcTokenManager(settings), + $inputApiKey = $('#input_apiKey'); - $inputApiKey.on('dblclick', function () { - manager.openPopupForTokenAsync() - .then(function () { - $inputApiKey.val(manager.access_token).change(); - }, function (error) { - console.error(error); - }); - }); - }); + $inputApiKey.on('dblclick', function () { + manager.openPopupForTokenAsync() + .then(function () { + $inputApiKey.val(manager.access_token).change(); + }, function (error) { + console.error(error); + }); + }); + }); })(jQuery, window.swaggerUi); \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Auth/Client/oidc-token-manager.js b/src/Services/Basket/Basket.API/Auth/Client/oidc-token-manager.js index a6f3f29e5..e54ba48b9 100644 --- a/src/Services/Basket/Basket.API/Auth/Client/oidc-token-manager.js +++ b/src/Services/Basket/Basket.API/Auth/Client/oidc-token-manager.js @@ -1,8896 +1,8871 @@ (function () { - // globals - var _promiseFactory; - var _httpRequest; -/* -CryptoJS v3.1.2 -code.google.com/p/crypto-js -(c) 2009-2013 by Jeff Mott. All rights reserved. -code.google.com/p/crypto-js/wiki/License -*/ -/** - * CryptoJS core components. - */ -var CryptoJS = CryptoJS || (function (Math, undefined) { - /** - * CryptoJS namespace. - */ - var C = {}; - - /** - * Library namespace. - */ - var C_lib = C.lib = {}; - - /** - * Base object for prototypal inheritance. - */ - var Base = C_lib.Base = (function () { - function F() {} - - return { - /** - * Creates a new object that inherits from this object. - * - * @param {Object} overrides Properties to copy into the new object. - * - * @return {Object} The new object. - * - * @static - * - * @example - * - * var MyType = CryptoJS.lib.Base.extend({ - * field: 'value', - * - * method: function () { - * } - * }); - */ - extend: function (overrides) { - // Spawn - F.prototype = this; - var subtype = new F(); - - // Augment - if (overrides) { - subtype.mixIn(overrides); - } - - // Create default initializer - if (!subtype.hasOwnProperty('init')) { - subtype.init = function () { - subtype.$super.init.apply(this, arguments); - }; - } - - // Initializer's prototype is the subtype object - subtype.init.prototype = subtype; - - // Reference supertype - subtype.$super = this; - - return subtype; - }, - - /** - * Extends this object and runs the init method. - * Arguments to create() will be passed to init(). - * - * @return {Object} The new object. - * - * @static - * - * @example - * - * var instance = MyType.create(); - */ - create: function () { - var instance = this.extend(); - instance.init.apply(instance, arguments); - - return instance; - }, - - /** - * Initializes a newly created object. - * Override this method to add some logic when your objects are created. - * - * @example - * - * var MyType = CryptoJS.lib.Base.extend({ - * init: function () { - * // ... - * } - * }); - */ - init: function () { - }, - - /** - * Copies properties into this object. - * - * @param {Object} properties The properties to mix in. - * - * @example - * - * MyType.mixIn({ - * field: 'value' - * }); - */ - mixIn: function (properties) { - for (var propertyName in properties) { - if (properties.hasOwnProperty(propertyName)) { - this[propertyName] = properties[propertyName]; - } - } - - // IE won't copy toString using the loop above - if (properties.hasOwnProperty('toString')) { - this.toString = properties.toString; - } - }, - - /** - * Creates a copy of this object. - * - * @return {Object} The clone. - * - * @example - * - * var clone = instance.clone(); - */ - clone: function () { - return this.init.prototype.extend(this); - } - }; - }()); - - /** - * An array of 32-bit words. - * - * @property {Array} words The array of 32-bit words. - * @property {number} sigBytes The number of significant bytes in this word array. - */ - var WordArray = C_lib.WordArray = Base.extend({ - /** - * Initializes a newly created word array. - * - * @param {Array} words (Optional) An array of 32-bit words. - * @param {number} sigBytes (Optional) The number of significant bytes in the words. - * - * @example - * - * var wordArray = CryptoJS.lib.WordArray.create(); - * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); - * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); - */ - init: function (words, sigBytes) { - words = this.words = words || []; - - if (sigBytes != undefined) { - this.sigBytes = sigBytes; - } else { - this.sigBytes = words.length * 4; - } - }, - - /** - * Converts this word array to a string. - * - * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex - * - * @return {string} The stringified word array. - * - * @example - * - * var string = wordArray + ''; - * var string = wordArray.toString(); - * var string = wordArray.toString(CryptoJS.enc.Utf8); - */ - toString: function (encoder) { - return (encoder || Hex).stringify(this); - }, - - /** - * Concatenates a word array to this word array. - * - * @param {WordArray} wordArray The word array to append. - * - * @return {WordArray} This word array. - * - * @example - * - * wordArray1.concat(wordArray2); - */ - concat: function (wordArray) { - // Shortcuts - var thisWords = this.words; - var thatWords = wordArray.words; - var thisSigBytes = this.sigBytes; - var thatSigBytes = wordArray.sigBytes; - - // Clamp excess bits - this.clamp(); - - // Concat - if (thisSigBytes % 4) { - // Copy one byte at a time - for (var i = 0; i < thatSigBytes; i++) { - var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); - } - } else if (thatWords.length > 0xffff) { - // Copy one word at a time - for (var i = 0; i < thatSigBytes; i += 4) { - thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; - } - } else { - // Copy all words at once - thisWords.push.apply(thisWords, thatWords); - } - this.sigBytes += thatSigBytes; - - // Chainable - return this; - }, - - /** - * Removes insignificant bits. - * - * @example - * - * wordArray.clamp(); - */ - clamp: function () { - // Shortcuts - var words = this.words; - var sigBytes = this.sigBytes; - - // Clamp - words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); - words.length = Math.ceil(sigBytes / 4); - }, - - /** - * Creates a copy of this word array. - * - * @return {WordArray} The clone. - * - * @example - * - * var clone = wordArray.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - clone.words = this.words.slice(0); - - return clone; - }, - - /** - * Creates a word array filled with random bytes. - * - * @param {number} nBytes The number of random bytes to generate. - * - * @return {WordArray} The random word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.lib.WordArray.random(16); - */ - random: function (nBytes) { - var words = []; - for (var i = 0; i < nBytes; i += 4) { - words.push((Math.random() * 0x100000000) | 0); - } - - return new WordArray.init(words, nBytes); - } - }); - - /** - * Encoder namespace. - */ - var C_enc = C.enc = {}; - - /** - * Hex encoding strategy. - */ - var Hex = C_enc.Hex = { - /** - * Converts a word array to a hex string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The hex string. - * - * @static - * - * @example - * - * var hexString = CryptoJS.enc.Hex.stringify(wordArray); - */ - stringify: function (wordArray) { - // Shortcuts - var words = wordArray.words; - var sigBytes = wordArray.sigBytes; - - // Convert - var hexChars = []; - for (var i = 0; i < sigBytes; i++) { - var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - hexChars.push((bite >>> 4).toString(16)); - hexChars.push((bite & 0x0f).toString(16)); - } - - return hexChars.join(''); - }, - - /** - * Converts a hex string to a word array. - * - * @param {string} hexStr The hex string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Hex.parse(hexString); - */ - parse: function (hexStr) { - // Shortcut - var hexStrLength = hexStr.length; - - // Convert - var words = []; - for (var i = 0; i < hexStrLength; i += 2) { - words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); - } - - return new WordArray.init(words, hexStrLength / 2); - } - }; - - /** - * Latin1 encoding strategy. - */ - var Latin1 = C_enc.Latin1 = { - /** - * Converts a word array to a Latin1 string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The Latin1 string. - * - * @static - * - * @example - * - * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); - */ - stringify: function (wordArray) { - // Shortcuts - var words = wordArray.words; - var sigBytes = wordArray.sigBytes; - - // Convert - var latin1Chars = []; - for (var i = 0; i < sigBytes; i++) { - var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - latin1Chars.push(String.fromCharCode(bite)); - } - - return latin1Chars.join(''); - }, - - /** - * Converts a Latin1 string to a word array. - * - * @param {string} latin1Str The Latin1 string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); - */ - parse: function (latin1Str) { - // Shortcut - var latin1StrLength = latin1Str.length; - - // Convert - var words = []; - for (var i = 0; i < latin1StrLength; i++) { - words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); - } - - return new WordArray.init(words, latin1StrLength); - } - }; - - /** - * UTF-8 encoding strategy. - */ - var Utf8 = C_enc.Utf8 = { - /** - * Converts a word array to a UTF-8 string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The UTF-8 string. - * - * @static - * - * @example - * - * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); - */ - stringify: function (wordArray) { - try { - return decodeURIComponent(escape(Latin1.stringify(wordArray))); - } catch (e) { - throw new Error('Malformed UTF-8 data'); - } - }, - - /** - * Converts a UTF-8 string to a word array. - * - * @param {string} utf8Str The UTF-8 string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); - */ - parse: function (utf8Str) { - return Latin1.parse(unescape(encodeURIComponent(utf8Str))); - } - }; - - /** - * Abstract buffered block algorithm template. - * - * The property blockSize must be implemented in a concrete subtype. - * - * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 - */ - var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ - /** - * Resets this block algorithm's data buffer to its initial state. - * - * @example - * - * bufferedBlockAlgorithm.reset(); - */ - reset: function () { - // Initial values - this._data = new WordArray.init(); - this._nDataBytes = 0; - }, - - /** - * Adds new data to this block algorithm's buffer. - * - * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. - * - * @example - * - * bufferedBlockAlgorithm._append('data'); - * bufferedBlockAlgorithm._append(wordArray); - */ - _append: function (data) { - // Convert string to WordArray, else assume WordArray already - if (typeof data == 'string') { - data = Utf8.parse(data); - } - - // Append - this._data.concat(data); - this._nDataBytes += data.sigBytes; - }, - - /** - * Processes available data blocks. - * - * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. - * - * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. - * - * @return {WordArray} The processed data. - * - * @example - * - * var processedData = bufferedBlockAlgorithm._process(); - * var processedData = bufferedBlockAlgorithm._process(!!'flush'); - */ - _process: function (doFlush) { - // Shortcuts - var data = this._data; - var dataWords = data.words; - var dataSigBytes = data.sigBytes; - var blockSize = this.blockSize; - var blockSizeBytes = blockSize * 4; - - // Count blocks ready - var nBlocksReady = dataSigBytes / blockSizeBytes; - if (doFlush) { - // Round up to include partial blocks - nBlocksReady = Math.ceil(nBlocksReady); - } else { - // Round down to include only full blocks, - // less the number of blocks that must remain in the buffer - nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); - } - - // Count words ready - var nWordsReady = nBlocksReady * blockSize; - - // Count bytes ready - var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); - - // Process blocks - if (nWordsReady) { - for (var offset = 0; offset < nWordsReady; offset += blockSize) { - // Perform concrete-algorithm logic - this._doProcessBlock(dataWords, offset); - } - - // Remove processed words - var processedWords = dataWords.splice(0, nWordsReady); - data.sigBytes -= nBytesReady; - } - - // Return processed words - return new WordArray.init(processedWords, nBytesReady); - }, - - /** - * Creates a copy of this object. - * - * @return {Object} The clone. - * - * @example - * - * var clone = bufferedBlockAlgorithm.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - clone._data = this._data.clone(); - - return clone; - }, - - _minBufferSize: 0 - }); - - /** - * Abstract hasher template. - * - * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) - */ - var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ - /** - * Configuration options. - */ - cfg: Base.extend(), - - /** - * Initializes a newly created hasher. - * - * @param {Object} cfg (Optional) The configuration options to use for this hash computation. - * - * @example - * - * var hasher = CryptoJS.algo.SHA256.create(); - */ - init: function (cfg) { - // Apply config defaults - this.cfg = this.cfg.extend(cfg); - - // Set initial values - this.reset(); - }, - - /** - * Resets this hasher to its initial state. - * - * @example - * - * hasher.reset(); - */ - reset: function () { - // Reset data buffer - BufferedBlockAlgorithm.reset.call(this); - - // Perform concrete-hasher logic - this._doReset(); - }, - - /** - * Updates this hasher with a message. - * - * @param {WordArray|string} messageUpdate The message to append. - * - * @return {Hasher} This hasher. - * - * @example - * - * hasher.update('message'); - * hasher.update(wordArray); - */ - update: function (messageUpdate) { - // Append - this._append(messageUpdate); - - // Update the hash - this._process(); - - // Chainable - return this; - }, - - /** - * Finalizes the hash computation. - * Note that the finalize operation is effectively a destructive, read-once operation. - * - * @param {WordArray|string} messageUpdate (Optional) A final message update. - * - * @return {WordArray} The hash. - * - * @example - * - * var hash = hasher.finalize(); - * var hash = hasher.finalize('message'); - * var hash = hasher.finalize(wordArray); - */ - finalize: function (messageUpdate) { - // Final message update - if (messageUpdate) { - this._append(messageUpdate); - } - - // Perform concrete-hasher logic - var hash = this._doFinalize(); - - return hash; - }, - - blockSize: 512/32, - - /** - * Creates a shortcut function to a hasher's object interface. - * - * @param {Hasher} hasher The hasher to create a helper for. - * - * @return {Function} The shortcut function. - * - * @static - * - * @example - * - * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); - */ - _createHelper: function (hasher) { - return function (message, cfg) { - return new hasher.init(cfg).finalize(message); - }; - }, - - /** - * Creates a shortcut function to the HMAC's object interface. - * - * @param {Hasher} hasher The hasher to use in this HMAC helper. - * - * @return {Function} The shortcut function. - * - * @static - * - * @example - * - * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); - */ - _createHmacHelper: function (hasher) { - return function (message, key) { - return new C_algo.HMAC.init(hasher, key).finalize(message); - }; - } - }); - - /** - * Algorithm namespace. - */ - var C_algo = C.algo = {}; - - return C; -}(Math)); - -/* -CryptoJS v3.1.2 -code.google.com/p/crypto-js -(c) 2009-2013 by Jeff Mott. All rights reserved. -code.google.com/p/crypto-js/wiki/License -*/ -(function () { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var WordArray = C_lib.WordArray; - var Hasher = C_lib.Hasher; - var C_algo = C.algo; - - // Reusable object - var W = []; - - /** - * SHA-1 hash algorithm. - */ - var SHA1 = C_algo.SHA1 = Hasher.extend({ - _doReset: function () { - this._hash = new WordArray.init([ - 0x67452301, 0xefcdab89, - 0x98badcfe, 0x10325476, - 0xc3d2e1f0 - ]); - }, - - _doProcessBlock: function (M, offset) { - // Shortcut - var H = this._hash.words; - - // Working variables - var a = H[0]; - var b = H[1]; - var c = H[2]; - var d = H[3]; - var e = H[4]; - - // Computation - for (var i = 0; i < 80; i++) { - if (i < 16) { - W[i] = M[offset + i] | 0; - } else { - var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; - W[i] = (n << 1) | (n >>> 31); - } - - var t = ((a << 5) | (a >>> 27)) + e + W[i]; - if (i < 20) { - t += ((b & c) | (~b & d)) + 0x5a827999; - } else if (i < 40) { - t += (b ^ c ^ d) + 0x6ed9eba1; - } else if (i < 60) { - t += ((b & c) | (b & d) | (c & d)) - 0x70e44324; - } else /* if (i < 80) */ { - t += (b ^ c ^ d) - 0x359d3e2a; - } - - e = d; - d = c; - c = (b << 30) | (b >>> 2); - b = a; - a = t; - } - - // Intermediate hash value - H[0] = (H[0] + a) | 0; - H[1] = (H[1] + b) | 0; - H[2] = (H[2] + c) | 0; - H[3] = (H[3] + d) | 0; - H[4] = (H[4] + e) | 0; - }, - - _doFinalize: function () { - // Shortcuts - var data = this._data; - var dataWords = data.words; - - var nBitsTotal = this._nDataBytes * 8; - var nBitsLeft = data.sigBytes * 8; - - // Add padding - dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); - dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); - dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; - data.sigBytes = dataWords.length * 4; - - // Hash final blocks - this._process(); - - // Return final computed hash - return this._hash; - }, - - clone: function () { - var clone = Hasher.clone.call(this); - clone._hash = this._hash.clone(); - - return clone; - } - }); - - /** - * Shortcut function to the hasher's object interface. - * - * @param {WordArray|string} message The message to hash. - * - * @return {WordArray} The hash. - * - * @static - * - * @example - * - * var hash = CryptoJS.SHA1('message'); - * var hash = CryptoJS.SHA1(wordArray); - */ - C.SHA1 = Hasher._createHelper(SHA1); - - /** - * Shortcut function to the HMAC's object interface. - * - * @param {WordArray|string} message The message to hash. - * @param {WordArray|string} key The secret key. - * - * @return {WordArray} The HMAC. - * - * @static - * - * @example - * - * var hmac = CryptoJS.HmacSHA1(message, key); - */ - C.HmacSHA1 = Hasher._createHmacHelper(SHA1); -}()); - -/* -CryptoJS v3.1.2 -code.google.com/p/crypto-js -(c) 2009-2013 by Jeff Mott. All rights reserved. -code.google.com/p/crypto-js/wiki/License -*/ -(function (Math) { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var WordArray = C_lib.WordArray; - var Hasher = C_lib.Hasher; - var C_algo = C.algo; - - // Initialization and round constants tables - var H = []; - var K = []; - - // Compute constants - (function () { - function isPrime(n) { - var sqrtN = Math.sqrt(n); - for (var factor = 2; factor <= sqrtN; factor++) { - if (!(n % factor)) { - return false; - } - } - - return true; - } - - function getFractionalBits(n) { - return ((n - (n | 0)) * 0x100000000) | 0; - } - - var n = 2; - var nPrime = 0; - while (nPrime < 64) { - if (isPrime(n)) { - if (nPrime < 8) { - H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); - } - K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); - - nPrime++; - } - - n++; - } - }()); - - // Reusable object - var W = []; - - /** - * SHA-256 hash algorithm. - */ - var SHA256 = C_algo.SHA256 = Hasher.extend({ - _doReset: function () { - this._hash = new WordArray.init(H.slice(0)); - }, - - _doProcessBlock: function (M, offset) { - // Shortcut - var H = this._hash.words; - - // Working variables - var a = H[0]; - var b = H[1]; - var c = H[2]; - var d = H[3]; - var e = H[4]; - var f = H[5]; - var g = H[6]; - var h = H[7]; - - // Computation - for (var i = 0; i < 64; i++) { - if (i < 16) { - W[i] = M[offset + i] | 0; - } else { - var gamma0x = W[i - 15]; - var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ - ((gamma0x << 14) | (gamma0x >>> 18)) ^ - (gamma0x >>> 3); - - var gamma1x = W[i - 2]; - var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ - ((gamma1x << 13) | (gamma1x >>> 19)) ^ - (gamma1x >>> 10); - - W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; - } - - var ch = (e & f) ^ (~e & g); - var maj = (a & b) ^ (a & c) ^ (b & c); - - var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); - var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); - - var t1 = h + sigma1 + ch + K[i] + W[i]; - var t2 = sigma0 + maj; - - h = g; - g = f; - f = e; - e = (d + t1) | 0; - d = c; - c = b; - b = a; - a = (t1 + t2) | 0; - } - - // Intermediate hash value - H[0] = (H[0] + a) | 0; - H[1] = (H[1] + b) | 0; - H[2] = (H[2] + c) | 0; - H[3] = (H[3] + d) | 0; - H[4] = (H[4] + e) | 0; - H[5] = (H[5] + f) | 0; - H[6] = (H[6] + g) | 0; - H[7] = (H[7] + h) | 0; - }, - - _doFinalize: function () { - // Shortcuts - var data = this._data; - var dataWords = data.words; - - var nBitsTotal = this._nDataBytes * 8; - var nBitsLeft = data.sigBytes * 8; - - // Add padding - dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); - dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); - dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; - data.sigBytes = dataWords.length * 4; - - // Hash final blocks - this._process(); - - // Return final computed hash - return this._hash; - }, - - clone: function () { - var clone = Hasher.clone.call(this); - clone._hash = this._hash.clone(); - - return clone; - } - }); - - /** - * Shortcut function to the hasher's object interface. - * - * @param {WordArray|string} message The message to hash. - * - * @return {WordArray} The hash. - * - * @static - * - * @example - * - * var hash = CryptoJS.SHA256('message'); - * var hash = CryptoJS.SHA256(wordArray); - */ - C.SHA256 = Hasher._createHelper(SHA256); - - /** - * Shortcut function to the HMAC's object interface. - * - * @param {WordArray|string} message The message to hash. - * @param {WordArray|string} key The secret key. - * - * @return {WordArray} The HMAC. - * - * @static - * - * @example - * - * var hmac = CryptoJS.HmacSHA256(message, key); - */ - C.HmacSHA256 = Hasher._createHmacHelper(SHA256); -}(Math)); - -/* -CryptoJS v3.1.2 -code.google.com/p/crypto-js -(c) 2009-2013 by Jeff Mott. All rights reserved. -code.google.com/p/crypto-js/wiki/License -*/ -(function (undefined) { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var Base = C_lib.Base; - var X32WordArray = C_lib.WordArray; - - /** - * x64 namespace. - */ - var C_x64 = C.x64 = {}; - - /** - * A 64-bit word. - */ - var X64Word = C_x64.Word = Base.extend({ - /** - * Initializes a newly created 64-bit word. - * - * @param {number} high The high 32 bits. - * @param {number} low The low 32 bits. - * - * @example - * - * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607); - */ - init: function (high, low) { - this.high = high; - this.low = low; - } - - /** - * Bitwise NOTs this word. - * - * @return {X64Word} A new x64-Word object after negating. - * - * @example - * - * var negated = x64Word.not(); - */ - // not: function () { - // var high = ~this.high; - // var low = ~this.low; - - // return X64Word.create(high, low); - // }, - - /** - * Bitwise ANDs this word with the passed word. - * - * @param {X64Word} word The x64-Word to AND with this word. - * - * @return {X64Word} A new x64-Word object after ANDing. - * - * @example - * - * var anded = x64Word.and(anotherX64Word); - */ - // and: function (word) { - // var high = this.high & word.high; - // var low = this.low & word.low; - - // return X64Word.create(high, low); - // }, - - /** - * Bitwise ORs this word with the passed word. - * - * @param {X64Word} word The x64-Word to OR with this word. - * - * @return {X64Word} A new x64-Word object after ORing. - * - * @example - * - * var ored = x64Word.or(anotherX64Word); - */ - // or: function (word) { - // var high = this.high | word.high; - // var low = this.low | word.low; - - // return X64Word.create(high, low); - // }, - - /** - * Bitwise XORs this word with the passed word. - * - * @param {X64Word} word The x64-Word to XOR with this word. - * - * @return {X64Word} A new x64-Word object after XORing. - * - * @example - * - * var xored = x64Word.xor(anotherX64Word); - */ - // xor: function (word) { - // var high = this.high ^ word.high; - // var low = this.low ^ word.low; - - // return X64Word.create(high, low); - // }, - - /** - * Shifts this word n bits to the left. - * - * @param {number} n The number of bits to shift. - * - * @return {X64Word} A new x64-Word object after shifting. - * - * @example - * - * var shifted = x64Word.shiftL(25); - */ - // shiftL: function (n) { - // if (n < 32) { - // var high = (this.high << n) | (this.low >>> (32 - n)); - // var low = this.low << n; - // } else { - // var high = this.low << (n - 32); - // var low = 0; - // } - - // return X64Word.create(high, low); - // }, - - /** - * Shifts this word n bits to the right. - * - * @param {number} n The number of bits to shift. - * - * @return {X64Word} A new x64-Word object after shifting. - * - * @example - * - * var shifted = x64Word.shiftR(7); - */ - // shiftR: function (n) { - // if (n < 32) { - // var low = (this.low >>> n) | (this.high << (32 - n)); - // var high = this.high >>> n; - // } else { - // var low = this.high >>> (n - 32); - // var high = 0; - // } - - // return X64Word.create(high, low); - // }, - - /** - * Rotates this word n bits to the left. - * - * @param {number} n The number of bits to rotate. - * - * @return {X64Word} A new x64-Word object after rotating. - * - * @example - * - * var rotated = x64Word.rotL(25); - */ - // rotL: function (n) { - // return this.shiftL(n).or(this.shiftR(64 - n)); - // }, - - /** - * Rotates this word n bits to the right. - * - * @param {number} n The number of bits to rotate. - * - * @return {X64Word} A new x64-Word object after rotating. - * - * @example - * - * var rotated = x64Word.rotR(7); - */ - // rotR: function (n) { - // return this.shiftR(n).or(this.shiftL(64 - n)); - // }, - - /** - * Adds this word with the passed word. - * - * @param {X64Word} word The x64-Word to add with this word. - * - * @return {X64Word} A new x64-Word object after adding. - * - * @example - * - * var added = x64Word.add(anotherX64Word); - */ - // add: function (word) { - // var low = (this.low + word.low) | 0; - // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0; - // var high = (this.high + word.high + carry) | 0; - - // return X64Word.create(high, low); - // } - }); - - /** - * An array of 64-bit words. - * - * @property {Array} words The array of CryptoJS.x64.Word objects. - * @property {number} sigBytes The number of significant bytes in this word array. - */ - var X64WordArray = C_x64.WordArray = Base.extend({ - /** - * Initializes a newly created word array. - * - * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects. - * @param {number} sigBytes (Optional) The number of significant bytes in the words. - * - * @example - * - * var wordArray = CryptoJS.x64.WordArray.create(); - * - * var wordArray = CryptoJS.x64.WordArray.create([ - * CryptoJS.x64.Word.create(0x00010203, 0x04050607), - * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) - * ]); - * - * var wordArray = CryptoJS.x64.WordArray.create([ - * CryptoJS.x64.Word.create(0x00010203, 0x04050607), - * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) - * ], 10); - */ - init: function (words, sigBytes) { - words = this.words = words || []; - - if (sigBytes != undefined) { - this.sigBytes = sigBytes; - } else { - this.sigBytes = words.length * 8; - } - }, - - /** - * Converts this 64-bit word array to a 32-bit word array. - * - * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array. - * - * @example - * - * var x32WordArray = x64WordArray.toX32(); - */ - toX32: function () { - // Shortcuts - var x64Words = this.words; - var x64WordsLength = x64Words.length; - - // Convert - var x32Words = []; - for (var i = 0; i < x64WordsLength; i++) { - var x64Word = x64Words[i]; - x32Words.push(x64Word.high); - x32Words.push(x64Word.low); - } - - return X32WordArray.create(x32Words, this.sigBytes); - }, - - /** - * Creates a copy of this word array. - * - * @return {X64WordArray} The clone. - * - * @example - * - * var clone = x64WordArray.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - - // Clone "words" array - var words = clone.words = this.words.slice(0); - - // Clone each X64Word object - var wordsLength = words.length; - for (var i = 0; i < wordsLength; i++) { - words[i] = words[i].clone(); - } - - return clone; - } - }); -}()); -/* -CryptoJS v3.1.2 -code.google.com/p/crypto-js -(c) 2009-2013 by Jeff Mott. All rights reserved. -code.google.com/p/crypto-js/wiki/License -*/ -(function () { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var Hasher = C_lib.Hasher; - var C_x64 = C.x64; - var X64Word = C_x64.Word; - var X64WordArray = C_x64.WordArray; - var C_algo = C.algo; - - function X64Word_create() { - return X64Word.create.apply(X64Word, arguments); - } - - // Constants - var K = [ - X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd), - X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc), - X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019), - X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118), - X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe), - X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2), - X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1), - X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694), - X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3), - X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65), - X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483), - X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5), - X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210), - X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4), - X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725), - X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70), - X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926), - X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df), - X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8), - X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b), - X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001), - X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30), - X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910), - X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8), - X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53), - X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8), - X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb), - X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3), - X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60), - X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec), - X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9), - X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b), - X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207), - X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178), - X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6), - X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b), - X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493), - X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c), - X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a), - X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817) - ]; - - // Reusable objects - var W = []; - (function () { - for (var i = 0; i < 80; i++) { - W[i] = X64Word_create(); - } - }()); - - /** - * SHA-512 hash algorithm. - */ - var SHA512 = C_algo.SHA512 = Hasher.extend({ - _doReset: function () { - this._hash = new X64WordArray.init([ - new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b), - new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1), - new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f), - new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179) - ]); - }, - - _doProcessBlock: function (M, offset) { - // Shortcuts - var H = this._hash.words; - - var H0 = H[0]; - var H1 = H[1]; - var H2 = H[2]; - var H3 = H[3]; - var H4 = H[4]; - var H5 = H[5]; - var H6 = H[6]; - var H7 = H[7]; - - var H0h = H0.high; - var H0l = H0.low; - var H1h = H1.high; - var H1l = H1.low; - var H2h = H2.high; - var H2l = H2.low; - var H3h = H3.high; - var H3l = H3.low; - var H4h = H4.high; - var H4l = H4.low; - var H5h = H5.high; - var H5l = H5.low; - var H6h = H6.high; - var H6l = H6.low; - var H7h = H7.high; - var H7l = H7.low; - - // Working variables - var ah = H0h; - var al = H0l; - var bh = H1h; - var bl = H1l; - var ch = H2h; - var cl = H2l; - var dh = H3h; - var dl = H3l; - var eh = H4h; - var el = H4l; - var fh = H5h; - var fl = H5l; - var gh = H6h; - var gl = H6l; - var hh = H7h; - var hl = H7l; - - // Rounds - for (var i = 0; i < 80; i++) { - // Shortcut - var Wi = W[i]; - - // Extend message - if (i < 16) { - var Wih = Wi.high = M[offset + i * 2] | 0; - var Wil = Wi.low = M[offset + i * 2 + 1] | 0; - } else { - // Gamma0 - var gamma0x = W[i - 15]; - var gamma0xh = gamma0x.high; - var gamma0xl = gamma0x.low; - var gamma0h = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7); - var gamma0l = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25)); - - // Gamma1 - var gamma1x = W[i - 2]; - var gamma1xh = gamma1x.high; - var gamma1xl = gamma1x.low; - var gamma1h = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6); - var gamma1l = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26)); - - // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] - var Wi7 = W[i - 7]; - var Wi7h = Wi7.high; - var Wi7l = Wi7.low; - - var Wi16 = W[i - 16]; - var Wi16h = Wi16.high; - var Wi16l = Wi16.low; - - var Wil = gamma0l + Wi7l; - var Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); - var Wil = Wil + gamma1l; - var Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); - var Wil = Wil + Wi16l; - var Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); - - Wi.high = Wih; - Wi.low = Wil; - } - - var chh = (eh & fh) ^ (~eh & gh); - var chl = (el & fl) ^ (~el & gl); - var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch); - var majl = (al & bl) ^ (al & cl) ^ (bl & cl); - - var sigma0h = ((ah >>> 28) | (al << 4)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7)); - var sigma0l = ((al >>> 28) | (ah << 4)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7)); - var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9)); - var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9)); - - // t1 = h + sigma1 + ch + K[i] + W[i] - var Ki = K[i]; - var Kih = Ki.high; - var Kil = Ki.low; - - var t1l = hl + sigma1l; - var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0); - var t1l = t1l + chl; - var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0); - var t1l = t1l + Kil; - var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0); - var t1l = t1l + Wil; - var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0); - - // t2 = sigma0 + maj - var t2l = sigma0l + majl; - var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0); - - // Update working variables - hh = gh; - hl = gl; - gh = fh; - gl = fl; - fh = eh; - fl = el; - el = (dl + t1l) | 0; - eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; - dh = ch; - dl = cl; - ch = bh; - cl = bl; - bh = ah; - bl = al; - al = (t1l + t2l) | 0; - ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0; - } - - // Intermediate hash value - H0l = H0.low = (H0l + al); - H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0)); - H1l = H1.low = (H1l + bl); - H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0)); - H2l = H2.low = (H2l + cl); - H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0)); - H3l = H3.low = (H3l + dl); - H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0)); - H4l = H4.low = (H4l + el); - H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0)); - H5l = H5.low = (H5l + fl); - H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0)); - H6l = H6.low = (H6l + gl); - H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0)); - H7l = H7.low = (H7l + hl); - H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0)); - }, - - _doFinalize: function () { - // Shortcuts - var data = this._data; - var dataWords = data.words; - - var nBitsTotal = this._nDataBytes * 8; - var nBitsLeft = data.sigBytes * 8; - - // Add padding - dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); - dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000); - dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal; - data.sigBytes = dataWords.length * 4; - - // Hash final blocks - this._process(); - - // Convert hash to 32-bit word array before returning - var hash = this._hash.toX32(); - - // Return final computed hash - return hash; - }, - - clone: function () { - var clone = Hasher.clone.call(this); - clone._hash = this._hash.clone(); - - return clone; - }, - - blockSize: 1024/32 - }); - - /** - * Shortcut function to the hasher's object interface. - * - * @param {WordArray|string} message The message to hash. - * - * @return {WordArray} The hash. - * - * @static - * - * @example - * - * var hash = CryptoJS.SHA512('message'); - * var hash = CryptoJS.SHA512(wordArray); - */ - C.SHA512 = Hasher._createHelper(SHA512); - - /** - * Shortcut function to the HMAC's object interface. - * - * @param {WordArray|string} message The message to hash. - * @param {WordArray|string} key The secret key. - * - * @return {WordArray} The HMAC. - * - * @static - * - * @example - * - * var hmac = CryptoJS.HmacSHA512(message, key); - */ - C.HmacSHA512 = Hasher._createHmacHelper(SHA512); -}()); - - -/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ - */ -var b64map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -var b64pad="="; - -function hex2b64(h) { - var i; - var c; - var ret = ""; - for(i = 0; i+3 <= h.length; i+=3) { - c = parseInt(h.substring(i,i+3),16); - ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63); - } - if(i+1 == h.length) { - c = parseInt(h.substring(i,i+1),16); - ret += b64map.charAt(c << 2); - } - else if(i+2 == h.length) { - c = parseInt(h.substring(i,i+2),16); - ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4); - } - if (b64pad) while((ret.length & 3) > 0) ret += b64pad; - return ret; -} - -// convert a base64 string to hex -function b64tohex(s) { - var ret = "" - var i; - var k = 0; // b64 state, 0-3 - var slop; - var v; - for(i = 0; i < s.length; ++i) { - if(s.charAt(i) == b64pad) break; - v = b64map.indexOf(s.charAt(i)); - if(v < 0) continue; - if(k == 0) { - ret += int2char(v >> 2); - slop = v & 3; - k = 1; - } - else if(k == 1) { - ret += int2char((slop << 2) | (v >> 4)); - slop = v & 0xf; - k = 2; - } - else if(k == 2) { - ret += int2char(slop); - ret += int2char(v >> 2); - slop = v & 3; - k = 3; - } - else { - ret += int2char((slop << 2) | (v >> 4)); - ret += int2char(v & 0xf); - k = 0; - } - } - if(k == 1) - ret += int2char(slop << 2); - return ret; -} - -// convert a base64 string to a byte/number array -function b64toBA(s) { - //piggyback on b64tohex for now, optimize later - var h = b64tohex(s); - var i; - var a = new Array(); - for(i = 0; 2*i < h.length; ++i) { - a[i] = parseInt(h.substring(2*i,2*i+2),16); - } - return a; -} -/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ - */ -// Copyright (c) 2005 Tom Wu -// All Rights Reserved. -// See "LICENSE" for details. - -// Basic JavaScript BN library - subset useful for RSA encryption. - -// Bits per digit -var dbits; - -// JavaScript engine analysis -var canary = 0xdeadbeefcafe; -var j_lm = ((canary&0xffffff)==0xefcafe); - -// (public) Constructor -function BigInteger(a,b,c) { - if(a != null) - if("number" == typeof a) this.fromNumber(a,b,c); - else if(b == null && "string" != typeof a) this.fromString(a,256); - else this.fromString(a,b); -} - -// return new, unset BigInteger -function nbi() { return new BigInteger(null); } - -// am: Compute w_j += (x*this_i), propagate carries, -// c is initial carry, returns final carry. -// c < 3*dvalue, x < 2*dvalue, this_i < dvalue -// We need to select the fastest one that works in this environment. - -// am1: use a single mult and divide to get the high bits, -// max digit bits should be 26 because -// max internal value = 2*dvalue^2-2*dvalue (< 2^53) -function am1(i,x,w,j,c,n) { - while(--n >= 0) { - var v = x*this[i++]+w[j]+c; - c = Math.floor(v/0x4000000); - w[j++] = v&0x3ffffff; - } - return c; -} -// am2 avoids a big mult-and-extract completely. -// Max digit bits should be <= 30 because we do bitwise ops -// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) -function am2(i,x,w,j,c,n) { - var xl = x&0x7fff, xh = x>>15; - while(--n >= 0) { - var l = this[i]&0x7fff; - var h = this[i++]>>15; - var m = xh*l+h*xl; - l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff); - c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); - w[j++] = l&0x3fffffff; - } - return c; -} -// Alternately, set max digit bits to 28 since some -// browsers slow down when dealing with 32-bit numbers. -function am3(i,x,w,j,c,n) { - var xl = x&0x3fff, xh = x>>14; - while(--n >= 0) { - var l = this[i]&0x3fff; - var h = this[i++]>>14; - var m = xh*l+h*xl; - l = xl*l+((m&0x3fff)<<14)+w[j]+c; - c = (l>>28)+(m>>14)+xh*h; - w[j++] = l&0xfffffff; - } - return c; -} -if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) { - BigInteger.prototype.am = am2; - dbits = 30; -} -else if(j_lm && (navigator.appName != "Netscape")) { - BigInteger.prototype.am = am1; - dbits = 26; -} -else { // Mozilla/Netscape seems to prefer am3 - BigInteger.prototype.am = am3; - dbits = 28; -} - -BigInteger.prototype.DB = dbits; -BigInteger.prototype.DM = ((1<= 0; --i) r[i] = this[i]; - r.t = this.t; - r.s = this.s; -} - -// (protected) set from integer value x, -DV <= x < DV -function bnpFromInt(x) { - this.t = 1; - this.s = (x<0)?-1:0; - if(x > 0) this[0] = x; - else if(x < -1) this[0] = x+this.DV; - else this.t = 0; -} - -// return bigint initialized to value -function nbv(i) { var r = nbi(); r.fromInt(i); return r; } - -// (protected) set from string and radix -function bnpFromString(s,b) { - var k; - if(b == 16) k = 4; - else if(b == 8) k = 3; - else if(b == 256) k = 8; // byte array - else if(b == 2) k = 1; - else if(b == 32) k = 5; - else if(b == 4) k = 2; - else { this.fromRadix(s,b); return; } - this.t = 0; - this.s = 0; - var i = s.length, mi = false, sh = 0; - while(--i >= 0) { - var x = (k==8)?s[i]&0xff:intAt(s,i); - if(x < 0) { - if(s.charAt(i) == "-") mi = true; - continue; - } - mi = false; - if(sh == 0) - this[this.t++] = x; - else if(sh+k > this.DB) { - this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh)); - } - else - this[this.t-1] |= x<= this.DB) sh -= this.DB; - } - if(k == 8 && (s[0]&0x80) != 0) { - this.s = -1; - if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this[this.t-1] == c) --this.t; -} - -// (public) return string representation in given radix -function bnToString(b) { - if(this.s < 0) return "-"+this.negate().toString(b); - var k; - if(b == 16) k = 4; - else if(b == 8) k = 3; - else if(b == 2) k = 1; - else if(b == 32) k = 5; - else if(b == 4) k = 2; - else return this.toRadix(b); - var km = (1< 0) { - if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); } - while(i >= 0) { - if(p < k) { - d = (this[i]&((1<>(p+=this.DB-k); - } - else { - d = (this[i]>>(p-=k))&km; - if(p <= 0) { p += this.DB; --i; } - } - if(d > 0) m = true; - if(m) r += int2char(d); - } - } - return m?r:"0"; -} - -// (public) -this -function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } - -// (public) |this| -function bnAbs() { return (this.s<0)?this.negate():this; } - -// (public) return + if this > a, - if this < a, 0 if equal -function bnCompareTo(a) { - var r = this.s-a.s; - if(r != 0) return r; - var i = this.t; - r = i-a.t; - if(r != 0) return (this.s<0)?-r:r; - while(--i >= 0) if((r=this[i]-a[i]) != 0) return r; - return 0; -} - -// returns bit length of the integer x -function nbits(x) { - var r = 1, t; - if((t=x>>>16) != 0) { x = t; r += 16; } - if((t=x>>8) != 0) { x = t; r += 8; } - if((t=x>>4) != 0) { x = t; r += 4; } - if((t=x>>2) != 0) { x = t; r += 2; } - if((t=x>>1) != 0) { x = t; r += 1; } - return r; -} - -// (public) return the number of bits in "this" -function bnBitLength() { - if(this.t <= 0) return 0; - return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM)); -} - -// (protected) r = this << n*DB -function bnpDLShiftTo(n,r) { - var i; - for(i = this.t-1; i >= 0; --i) r[i+n] = this[i]; - for(i = n-1; i >= 0; --i) r[i] = 0; - r.t = this.t+n; - r.s = this.s; -} - -// (protected) r = this >> n*DB -function bnpDRShiftTo(n,r) { - for(var i = n; i < this.t; ++i) r[i-n] = this[i]; - r.t = Math.max(this.t-n,0); - r.s = this.s; -} - -// (protected) r = this << n -function bnpLShiftTo(n,r) { - var bs = n%this.DB; - var cbs = this.DB-bs; - var bm = (1<= 0; --i) { - r[i+ds+1] = (this[i]>>cbs)|c; - c = (this[i]&bm)<= 0; --i) r[i] = 0; - r[ds] = c; - r.t = this.t+ds+1; - r.s = this.s; - r.clamp(); -} - -// (protected) r = this >> n -function bnpRShiftTo(n,r) { - r.s = this.s; - var ds = Math.floor(n/this.DB); - if(ds >= this.t) { r.t = 0; return; } - var bs = n%this.DB; - var cbs = this.DB-bs; - var bm = (1<>bs; - for(var i = ds+1; i < this.t; ++i) { - r[i-ds-1] |= (this[i]&bm)<>bs; - } - if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<>= this.DB; - } - if(a.t < this.t) { - c -= a.s; - while(i < this.t) { - c += this[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - c += this.s; - } - else { - c += this.s; - while(i < a.t) { - c -= a[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - c -= a.s; - } - r.s = (c<0)?-1:0; - if(c < -1) r[i++] = this.DV+c; - else if(c > 0) r[i++] = c; - r.t = i; - r.clamp(); -} - -// (protected) r = this * a, r != this,a (HAC 14.12) -// "this" should be the larger one if appropriate. -function bnpMultiplyTo(a,r) { - var x = this.abs(), y = a.abs(); - var i = x.t; - r.t = i+y.t; - while(--i >= 0) r[i] = 0; - for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t); - r.s = 0; - r.clamp(); - if(this.s != a.s) BigInteger.ZERO.subTo(r,r); -} - -// (protected) r = this^2, r != this (HAC 14.16) -function bnpSquareTo(r) { - var x = this.abs(); - var i = r.t = 2*x.t; - while(--i >= 0) r[i] = 0; - for(i = 0; i < x.t-1; ++i) { - var c = x.am(i,x[i],r,2*i,0,1); - if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { - r[i+x.t] -= x.DV; - r[i+x.t+1] = 1; - } - } - if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1); - r.s = 0; - r.clamp(); -} - -// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) -// r != q, this != m. q or r may be null. -function bnpDivRemTo(m,q,r) { - var pm = m.abs(); - if(pm.t <= 0) return; - var pt = this.abs(); - if(pt.t < pm.t) { - if(q != null) q.fromInt(0); - if(r != null) this.copyTo(r); - return; - } - if(r == null) r = nbi(); - var y = nbi(), ts = this.s, ms = m.s; - var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus - if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } - else { pm.copyTo(y); pt.copyTo(r); } - var ys = y.t; - var y0 = y[ys-1]; - if(y0 == 0) return; - var yt = y0*(1<1)?y[ys-2]>>this.F2:0); - var d1 = this.FV/yt, d2 = (1<= 0) { - r[r.t++] = 1; - r.subTo(t,r); - } - BigInteger.ONE.dlShiftTo(ys,t); - t.subTo(y,y); // "negative" y so we can replace sub with am later - while(y.t < ys) y[y.t++] = 0; - while(--j >= 0) { - // Estimate quotient digit - var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2); - if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out - y.dlShiftTo(j,t); - r.subTo(t,r); - while(r[i] < --qd) r.subTo(t,r); - } - } - if(q != null) { - r.drShiftTo(ys,q); - if(ts != ms) BigInteger.ZERO.subTo(q,q); - } - r.t = ys; - r.clamp(); - if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder - if(ts < 0) BigInteger.ZERO.subTo(r,r); -} - -// (public) this mod a -function bnMod(a) { - var r = nbi(); - this.abs().divRemTo(a,null,r); - if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); - return r; -} - -// Modular reduction using "classic" algorithm -function Classic(m) { this.m = m; } -function cConvert(x) { - if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); - else return x; -} -function cRevert(x) { return x; } -function cReduce(x) { x.divRemTo(this.m,null,x); } -function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } -function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - -Classic.prototype.convert = cConvert; -Classic.prototype.revert = cRevert; -Classic.prototype.reduce = cReduce; -Classic.prototype.mulTo = cMulTo; -Classic.prototype.sqrTo = cSqrTo; - -// (protected) return "-1/this % 2^DB"; useful for Mont. reduction -// justification: -// xy == 1 (mod m) -// xy = 1+km -// xy(2-xy) = (1+km)(1-km) -// x[y(2-xy)] = 1-k^2m^2 -// x[y(2-xy)] == 1 (mod m^2) -// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 -// should reduce x and y(2-xy) by m^2 at each step to keep size bounded. -// JS multiply "overflows" differently from C/C++, so care is needed here. -function bnpInvDigit() { - if(this.t < 1) return 0; - var x = this[0]; - if((x&1) == 0) return 0; - var y = x&3; // y == 1/x mod 2^2 - y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 - y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 - y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 - // last step - calculate inverse mod DV directly; - // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints - y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits - // we really want the negative inverse, and -DV < y < DV - return (y>0)?this.DV-y:-y; -} - -// Montgomery reduction -function Montgomery(m) { - this.m = m; - this.mp = m.invDigit(); - this.mpl = this.mp&0x7fff; - this.mph = this.mp>>15; - this.um = (1<<(m.DB-15))-1; - this.mt2 = 2*m.t; -} - -// xR mod m -function montConvert(x) { - var r = nbi(); - x.abs().dlShiftTo(this.m.t,r); - r.divRemTo(this.m,null,r); - if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); - return r; -} - -// x/R mod m -function montRevert(x) { - var r = nbi(); - x.copyTo(r); - this.reduce(r); - return r; -} - -// x = x/R mod m (HAC 14.32) -function montReduce(x) { - while(x.t <= this.mt2) // pad x so am has enough room later - x[x.t++] = 0; - for(var i = 0; i < this.m.t; ++i) { - // faster way of calculating u0 = x[i]*mp mod DV - var j = x[i]&0x7fff; - var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM; - // use am to combine the multiply-shift-add into one call - j = i+this.m.t; - x[j] += this.m.am(0,u0,x,i,0,this.m.t); - // propagate carry - while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } - } - x.clamp(); - x.drShiftTo(this.m.t,x); - if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); -} - -// r = "x^2/R mod m"; x != r -function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - -// r = "xy/R mod m"; x,y != r -function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } - -Montgomery.prototype.convert = montConvert; -Montgomery.prototype.revert = montRevert; -Montgomery.prototype.reduce = montReduce; -Montgomery.prototype.mulTo = montMulTo; -Montgomery.prototype.sqrTo = montSqrTo; - -// (protected) true iff this is even -function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; } - -// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) -function bnpExp(e,z) { - if(e > 0xffffffff || e < 1) return BigInteger.ONE; - var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; - g.copyTo(r); - while(--i >= 0) { - z.sqrTo(r,r2); - if((e&(1< 0) z.mulTo(r2,g,r); - else { var t = r; r = r2; r2 = t; } - } - return z.revert(r); -} - -// (public) this^e % m, 0 <= e < 2^32 -function bnModPowInt(e,m) { - var z; - if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); - return this.exp(e,z); -} - -// protected -BigInteger.prototype.copyTo = bnpCopyTo; -BigInteger.prototype.fromInt = bnpFromInt; -BigInteger.prototype.fromString = bnpFromString; -BigInteger.prototype.clamp = bnpClamp; -BigInteger.prototype.dlShiftTo = bnpDLShiftTo; -BigInteger.prototype.drShiftTo = bnpDRShiftTo; -BigInteger.prototype.lShiftTo = bnpLShiftTo; -BigInteger.prototype.rShiftTo = bnpRShiftTo; -BigInteger.prototype.subTo = bnpSubTo; -BigInteger.prototype.multiplyTo = bnpMultiplyTo; -BigInteger.prototype.squareTo = bnpSquareTo; -BigInteger.prototype.divRemTo = bnpDivRemTo; -BigInteger.prototype.invDigit = bnpInvDigit; -BigInteger.prototype.isEven = bnpIsEven; -BigInteger.prototype.exp = bnpExp; - -// public -BigInteger.prototype.toString = bnToString; -BigInteger.prototype.negate = bnNegate; -BigInteger.prototype.abs = bnAbs; -BigInteger.prototype.compareTo = bnCompareTo; -BigInteger.prototype.bitLength = bnBitLength; -BigInteger.prototype.mod = bnMod; -BigInteger.prototype.modPowInt = bnModPowInt; - -// "constants" -BigInteger.ZERO = nbv(0); -BigInteger.ONE = nbv(1); -/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ - */ -// Copyright (c) 2005-2009 Tom Wu -// All Rights Reserved. -// See "LICENSE" for details. - -// Extended JavaScript BN functions, required for RSA private ops. - -// Version 1.1: new BigInteger("0", 10) returns "proper" zero -// Version 1.2: square() API, isProbablePrime fix - -// (public) -function bnClone() { var r = nbi(); this.copyTo(r); return r; } - -// (public) return value as integer -function bnIntValue() { - if(this.s < 0) { - if(this.t == 1) return this[0]-this.DV; - else if(this.t == 0) return -1; - } - else if(this.t == 1) return this[0]; - else if(this.t == 0) return 0; - // assumes 16 < DB < 32 - return ((this[1]&((1<<(32-this.DB))-1))<>24; } - -// (public) return value as short (assumes DB>=16) -function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; } - -// (protected) return x s.t. r^x < DV -function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); } - -// (public) 0 if this == 0, 1 if this > 0 -function bnSigNum() { - if(this.s < 0) return -1; - else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; - else return 1; -} - -// (protected) convert to radix string -function bnpToRadix(b) { - if(b == null) b = 10; - if(this.signum() == 0 || b < 2 || b > 36) return "0"; - var cs = this.chunkSize(b); - var a = Math.pow(b,cs); - var d = nbv(a), y = nbi(), z = nbi(), r = ""; - this.divRemTo(d,y,z); - while(y.signum() > 0) { - r = (a+z.intValue()).toString(b).substr(1) + r; - y.divRemTo(d,y,z); - } - return z.intValue().toString(b) + r; -} - -// (protected) convert from radix string -function bnpFromRadix(s,b) { - this.fromInt(0); - if(b == null) b = 10; - var cs = this.chunkSize(b); - var d = Math.pow(b,cs), mi = false, j = 0, w = 0; - for(var i = 0; i < s.length; ++i) { - var x = intAt(s,i); - if(x < 0) { - if(s.charAt(i) == "-" && this.signum() == 0) mi = true; - continue; - } - w = b*w+x; - if(++j >= cs) { - this.dMultiply(d); - this.dAddOffset(w,0); - j = 0; - w = 0; - } - } - if(j > 0) { - this.dMultiply(Math.pow(b,j)); - this.dAddOffset(w,0); - } - if(mi) BigInteger.ZERO.subTo(this,this); -} - -// (protected) alternate constructor -function bnpFromNumber(a,b,c) { - if("number" == typeof b) { - // new BigInteger(int,int,RNG) - if(a < 2) this.fromInt(1); - else { - this.fromNumber(a,c); - if(!this.testBit(a-1)) // force MSB set - this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this); - if(this.isEven()) this.dAddOffset(1,0); // force odd - while(!this.isProbablePrime(b)) { - this.dAddOffset(2,0); - if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this); - } - } - } - else { - // new BigInteger(int,RNG) - var x = new Array(), t = a&7; - x.length = (a>>3)+1; - b.nextBytes(x); - if(t > 0) x[0] &= ((1< 0) { - if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p) - r[k++] = d|(this.s<<(this.DB-p)); - while(i >= 0) { - if(p < 8) { - d = (this[i]&((1<>(p+=this.DB-8); - } - else { - d = (this[i]>>(p-=8))&0xff; - if(p <= 0) { p += this.DB; --i; } - } - if((d&0x80) != 0) d |= -256; - if(k == 0 && (this.s&0x80) != (d&0x80)) ++k; - if(k > 0 || d != this.s) r[k++] = d; - } - } - return r; -} - -function bnEquals(a) { return(this.compareTo(a)==0); } -function bnMin(a) { return(this.compareTo(a)<0)?this:a; } -function bnMax(a) { return(this.compareTo(a)>0)?this:a; } - -// (protected) r = this op a (bitwise) -function bnpBitwiseTo(a,op,r) { - var i, f, m = Math.min(a.t,this.t); - for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]); - if(a.t < this.t) { - f = a.s&this.DM; - for(i = m; i < this.t; ++i) r[i] = op(this[i],f); - r.t = this.t; - } - else { - f = this.s&this.DM; - for(i = m; i < a.t; ++i) r[i] = op(f,a[i]); - r.t = a.t; - } - r.s = op(this.s,a.s); - r.clamp(); -} - -// (public) this & a -function op_and(x,y) { return x&y; } -function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; } - -// (public) this | a -function op_or(x,y) { return x|y; } -function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; } - -// (public) this ^ a -function op_xor(x,y) { return x^y; } -function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; } - -// (public) this & ~a -function op_andnot(x,y) { return x&~y; } -function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; } - -// (public) ~this -function bnNot() { - var r = nbi(); - for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i]; - r.t = this.t; - r.s = ~this.s; - return r; -} - -// (public) this << n -function bnShiftLeft(n) { - var r = nbi(); - if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r); - return r; -} - -// (public) this >> n -function bnShiftRight(n) { - var r = nbi(); - if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r); - return r; -} - -// return index of lowest 1-bit in x, x < 2^31 -function lbit(x) { - if(x == 0) return -1; - var r = 0; - if((x&0xffff) == 0) { x >>= 16; r += 16; } - if((x&0xff) == 0) { x >>= 8; r += 8; } - if((x&0xf) == 0) { x >>= 4; r += 4; } - if((x&3) == 0) { x >>= 2; r += 2; } - if((x&1) == 0) ++r; - return r; -} - -// (public) returns index of lowest 1-bit (or -1 if none) -function bnGetLowestSetBit() { - for(var i = 0; i < this.t; ++i) - if(this[i] != 0) return i*this.DB+lbit(this[i]); - if(this.s < 0) return this.t*this.DB; - return -1; -} - -// return number of 1 bits in x -function cbit(x) { - var r = 0; - while(x != 0) { x &= x-1; ++r; } - return r; -} - -// (public) return number of set bits -function bnBitCount() { - var r = 0, x = this.s&this.DM; - for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x); - return r; -} - -// (public) true iff nth bit is set -function bnTestBit(n) { - var j = Math.floor(n/this.DB); - if(j >= this.t) return(this.s!=0); - return((this[j]&(1<<(n%this.DB)))!=0); -} - -// (protected) this op (1<>= this.DB; - } - if(a.t < this.t) { - c += a.s; - while(i < this.t) { - c += this[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - c += this.s; - } - else { - c += this.s; - while(i < a.t) { - c += a[i]; - r[i++] = c&this.DM; - c >>= this.DB; - } - c += a.s; - } - r.s = (c<0)?-1:0; - if(c > 0) r[i++] = c; - else if(c < -1) r[i++] = this.DV+c; - r.t = i; - r.clamp(); -} - -// (public) this + a -function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; } - -// (public) this - a -function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; } - -// (public) this * a -function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; } - -// (public) this^2 -function bnSquare() { var r = nbi(); this.squareTo(r); return r; } - -// (public) this / a -function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; } - -// (public) this % a -function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; } - -// (public) [this/a,this%a] -function bnDivideAndRemainder(a) { - var q = nbi(), r = nbi(); - this.divRemTo(a,q,r); - return new Array(q,r); -} - -// (protected) this *= n, this >= 0, 1 < n < DV -function bnpDMultiply(n) { - this[this.t] = this.am(0,n-1,this,0,0,this.t); - ++this.t; - this.clamp(); -} - -// (protected) this += n << w words, this >= 0 -function bnpDAddOffset(n,w) { - if(n == 0) return; - while(this.t <= w) this[this.t++] = 0; - this[w] += n; - while(this[w] >= this.DV) { - this[w] -= this.DV; - if(++w >= this.t) this[this.t++] = 0; - ++this[w]; - } -} - -// A "null" reducer -function NullExp() {} -function nNop(x) { return x; } -function nMulTo(x,y,r) { x.multiplyTo(y,r); } -function nSqrTo(x,r) { x.squareTo(r); } - -NullExp.prototype.convert = nNop; -NullExp.prototype.revert = nNop; -NullExp.prototype.mulTo = nMulTo; -NullExp.prototype.sqrTo = nSqrTo; - -// (public) this^e -function bnPow(e) { return this.exp(e,new NullExp()); } - -// (protected) r = lower n words of "this * a", a.t <= n -// "this" should be the larger one if appropriate. -function bnpMultiplyLowerTo(a,n,r) { - var i = Math.min(this.t+a.t,n); - r.s = 0; // assumes a,this >= 0 - r.t = i; - while(i > 0) r[--i] = 0; - var j; - for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t); - for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i); - r.clamp(); -} - -// (protected) r = "this * a" without lower n words, n > 0 -// "this" should be the larger one if appropriate. -function bnpMultiplyUpperTo(a,n,r) { - --n; - var i = r.t = this.t+a.t-n; - r.s = 0; // assumes a,this >= 0 - while(--i >= 0) r[i] = 0; - for(i = Math.max(n-this.t,0); i < a.t; ++i) - r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n); - r.clamp(); - r.drShiftTo(1,r); -} - -// Barrett modular reduction -function Barrett(m) { - // setup Barrett - this.r2 = nbi(); - this.q3 = nbi(); - BigInteger.ONE.dlShiftTo(2*m.t,this.r2); - this.mu = this.r2.divide(m); - this.m = m; -} - -function barrettConvert(x) { - if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m); - else if(x.compareTo(this.m) < 0) return x; - else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } -} - -function barrettRevert(x) { return x; } - -// x = x mod m (HAC 14.42) -function barrettReduce(x) { - x.drShiftTo(this.m.t-1,this.r2); - if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); } - this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3); - this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2); - while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1); - x.subTo(this.r2,x); - while(x.compareTo(this.m) >= 0) x.subTo(this.m,x); -} - -// r = x^2 mod m; x != r -function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); } - -// r = x*y mod m; x,y != r -function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } - -Barrett.prototype.convert = barrettConvert; -Barrett.prototype.revert = barrettRevert; -Barrett.prototype.reduce = barrettReduce; -Barrett.prototype.mulTo = barrettMulTo; -Barrett.prototype.sqrTo = barrettSqrTo; - -// (public) this^e % m (HAC 14.85) -function bnModPow(e,m) { - var i = e.bitLength(), k, r = nbv(1), z; - if(i <= 0) return r; - else if(i < 18) k = 1; - else if(i < 48) k = 3; - else if(i < 144) k = 4; - else if(i < 768) k = 5; - else k = 6; - if(i < 8) - z = new Classic(m); - else if(m.isEven()) - z = new Barrett(m); - else - z = new Montgomery(m); - - // precomputation - var g = new Array(), n = 3, k1 = k-1, km = (1< 1) { - var g2 = nbi(); - z.sqrTo(g[1],g2); - while(n <= km) { - g[n] = nbi(); - z.mulTo(g2,g[n-2],g[n]); - n += 2; - } - } - - var j = e.t-1, w, is1 = true, r2 = nbi(), t; - i = nbits(e[j])-1; - while(j >= 0) { - if(i >= k1) w = (e[j]>>(i-k1))&km; - else { - w = (e[j]&((1<<(i+1))-1))<<(k1-i); - if(j > 0) w |= e[j-1]>>(this.DB+i-k1); - } - - n = k; - while((w&1) == 0) { w >>= 1; --n; } - if((i -= n) < 0) { i += this.DB; --j; } - if(is1) { // ret == 1, don't bother squaring or multiplying it - g[w].copyTo(r); - is1 = false; - } - else { - while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; } - if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; } - z.mulTo(r2,g[w],r); - } - - while(j >= 0 && (e[j]&(1< 0) { - x.rShiftTo(g,x); - y.rShiftTo(g,y); - } - while(x.signum() > 0) { - if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x); - if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y); - if(x.compareTo(y) >= 0) { - x.subTo(y,x); - x.rShiftTo(1,x); - } - else { - y.subTo(x,y); - y.rShiftTo(1,y); - } - } - if(g > 0) y.lShiftTo(g,y); - return y; -} - -// (protected) this % n, n < 2^26 -function bnpModInt(n) { - if(n <= 0) return 0; - var d = this.DV%n, r = (this.s<0)?n-1:0; - if(this.t > 0) - if(d == 0) r = this[0]%n; - else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n; - return r; -} - -// (public) 1/this % m (HAC 14.61) -function bnModInverse(m) { - var ac = m.isEven(); - if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; - var u = m.clone(), v = this.clone(); - var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); - while(u.signum() != 0) { - while(u.isEven()) { - u.rShiftTo(1,u); - if(ac) { - if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); } - a.rShiftTo(1,a); - } - else if(!b.isEven()) b.subTo(m,b); - b.rShiftTo(1,b); - } - while(v.isEven()) { - v.rShiftTo(1,v); - if(ac) { - if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); } - c.rShiftTo(1,c); - } - else if(!d.isEven()) d.subTo(m,d); - d.rShiftTo(1,d); - } - if(u.compareTo(v) >= 0) { - u.subTo(v,u); - if(ac) a.subTo(c,a); - b.subTo(d,b); - } - else { - v.subTo(u,v); - if(ac) c.subTo(a,c); - d.subTo(b,d); - } - } - if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; - if(d.compareTo(m) >= 0) return d.subtract(m); - if(d.signum() < 0) d.addTo(m,d); else return d; - if(d.signum() < 0) return d.add(m); else return d; -} - -var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997]; -var lplim = (1<<26)/lowprimes[lowprimes.length-1]; - -// (public) test primality with certainty >= 1-.5^t -function bnIsProbablePrime(t) { - var i, x = this.abs(); - if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) { - for(i = 0; i < lowprimes.length; ++i) - if(x[0] == lowprimes[i]) return true; - return false; - } - if(x.isEven()) return false; - i = 1; - while(i < lowprimes.length) { - var m = lowprimes[i], j = i+1; - while(j < lowprimes.length && m < lplim) m *= lowprimes[j++]; - m = x.modInt(m); - while(i < j) if(m%lowprimes[i++] == 0) return false; - } - return x.millerRabin(t); -} - -// (protected) true if probably prime (HAC 4.24, Miller-Rabin) -function bnpMillerRabin(t) { - var n1 = this.subtract(BigInteger.ONE); - var k = n1.getLowestSetBit(); - if(k <= 0) return false; - var r = n1.shiftRight(k); - t = (t+1)>>1; - if(t > lowprimes.length) t = lowprimes.length; - var a = nbi(); - for(var i = 0; i < t; ++i) { - //Pick bases at random, instead of starting at 2 - a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]); - var y = a.modPow(r,this); - if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { - var j = 1; - while(j++ < k && y.compareTo(n1) != 0) { - y = y.modPowInt(2,this); - if(y.compareTo(BigInteger.ONE) == 0) return false; - } - if(y.compareTo(n1) != 0) return false; - } - } - return true; -} - -// protected -BigInteger.prototype.chunkSize = bnpChunkSize; -BigInteger.prototype.toRadix = bnpToRadix; -BigInteger.prototype.fromRadix = bnpFromRadix; -BigInteger.prototype.fromNumber = bnpFromNumber; -BigInteger.prototype.bitwiseTo = bnpBitwiseTo; -BigInteger.prototype.changeBit = bnpChangeBit; -BigInteger.prototype.addTo = bnpAddTo; -BigInteger.prototype.dMultiply = bnpDMultiply; -BigInteger.prototype.dAddOffset = bnpDAddOffset; -BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo; -BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo; -BigInteger.prototype.modInt = bnpModInt; -BigInteger.prototype.millerRabin = bnpMillerRabin; - -// public -BigInteger.prototype.clone = bnClone; -BigInteger.prototype.intValue = bnIntValue; -BigInteger.prototype.byteValue = bnByteValue; -BigInteger.prototype.shortValue = bnShortValue; -BigInteger.prototype.signum = bnSigNum; -BigInteger.prototype.toByteArray = bnToByteArray; -BigInteger.prototype.equals = bnEquals; -BigInteger.prototype.min = bnMin; -BigInteger.prototype.max = bnMax; -BigInteger.prototype.and = bnAnd; -BigInteger.prototype.or = bnOr; -BigInteger.prototype.xor = bnXor; -BigInteger.prototype.andNot = bnAndNot; -BigInteger.prototype.not = bnNot; -BigInteger.prototype.shiftLeft = bnShiftLeft; -BigInteger.prototype.shiftRight = bnShiftRight; -BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit; -BigInteger.prototype.bitCount = bnBitCount; -BigInteger.prototype.testBit = bnTestBit; -BigInteger.prototype.setBit = bnSetBit; -BigInteger.prototype.clearBit = bnClearBit; -BigInteger.prototype.flipBit = bnFlipBit; -BigInteger.prototype.add = bnAdd; -BigInteger.prototype.subtract = bnSubtract; -BigInteger.prototype.multiply = bnMultiply; -BigInteger.prototype.divide = bnDivide; -BigInteger.prototype.remainder = bnRemainder; -BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder; -BigInteger.prototype.modPow = bnModPow; -BigInteger.prototype.modInverse = bnModInverse; -BigInteger.prototype.pow = bnPow; -BigInteger.prototype.gcd = bnGCD; -BigInteger.prototype.isProbablePrime = bnIsProbablePrime; - -// JSBN-specific extension -BigInteger.prototype.square = bnSquare; - -// BigInteger interfaces not implemented in jsbn: - -// BigInteger(int signum, byte[] magnitude) -// double doubleValue() -// float floatValue() -// int hashCode() -// long longValue() -// static BigInteger valueOf(long val) -/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ - */ -// Depends on jsbn.js and rng.js - -// Version 1.1: support utf-8 encoding in pkcs1pad2 - -// convert a (hex) string to a bignum object -function parseBigInt(str,r) { - return new BigInteger(str,r); -} - -function linebrk(s,n) { - var ret = ""; - var i = 0; - while(i + n < s.length) { - ret += s.substring(i,i+n) + "\n"; - i += n; - } - return ret + s.substring(i,s.length); -} - -function byte2Hex(b) { - if(b < 0x10) - return "0" + b.toString(16); - else - return b.toString(16); -} - -// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint -function pkcs1pad2(s,n) { - if(n < s.length + 11) { // TODO: fix for utf-8 - alert("Message too long for RSA"); - return null; - } - var ba = new Array(); - var i = s.length - 1; - while(i >= 0 && n > 0) { - var c = s.charCodeAt(i--); - if(c < 128) { // encode using utf-8 - ba[--n] = c; - } - else if((c > 127) && (c < 2048)) { - ba[--n] = (c & 63) | 128; - ba[--n] = (c >> 6) | 192; - } - else { - ba[--n] = (c & 63) | 128; - ba[--n] = ((c >> 6) & 63) | 128; - ba[--n] = (c >> 12) | 224; - } - } - ba[--n] = 0; - var rng = new SecureRandom(); - var x = new Array(); - while(n > 2) { // random non-zero pad - x[0] = 0; - while(x[0] == 0) rng.nextBytes(x); - ba[--n] = x[0]; - } - ba[--n] = 2; - ba[--n] = 0; - return new BigInteger(ba); -} - -// PKCS#1 (OAEP) mask generation function -function oaep_mgf1_arr(seed, len, hash) -{ - var mask = '', i = 0; - - while (mask.length < len) - { - mask += hash(String.fromCharCode.apply(String, seed.concat([ - (i & 0xff000000) >> 24, - (i & 0x00ff0000) >> 16, - (i & 0x0000ff00) >> 8, - i & 0x000000ff]))); - i += 1; - } - - return mask; -} - -var SHA1_SIZE = 20; - -// PKCS#1 (OAEP) pad input string s to n bytes, and return a bigint -function oaep_pad(s, n, hash) -{ - if (s.length + 2 * SHA1_SIZE + 2 > n) - { - throw "Message too long for RSA"; - } - - var PS = '', i; - - for (i = 0; i < n - s.length - 2 * SHA1_SIZE - 2; i += 1) - { - PS += '\x00'; - } - - var DB = rstr_sha1('') + PS + '\x01' + s; - var seed = new Array(SHA1_SIZE); - new SecureRandom().nextBytes(seed); - - var dbMask = oaep_mgf1_arr(seed, DB.length, hash || rstr_sha1); - var maskedDB = []; - - for (i = 0; i < DB.length; i += 1) - { - maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i); - } - - var seedMask = oaep_mgf1_arr(maskedDB, seed.length, rstr_sha1); - var maskedSeed = [0]; - - for (i = 0; i < seed.length; i += 1) - { - maskedSeed[i + 1] = seed[i] ^ seedMask.charCodeAt(i); - } - - return new BigInteger(maskedSeed.concat(maskedDB)); -} - -// "empty" RSA key constructor -function RSAKey() { - this.n = null; - this.e = 0; - this.d = null; - this.p = null; - this.q = null; - this.dmp1 = null; - this.dmq1 = null; - this.coeff = null; -} - -// Set the public key fields N and e from hex strings -function RSASetPublic(N,E) { - this.isPublic = true; - if (typeof N !== "string") - { - this.n = N; - this.e = E; - } - else if(N != null && E != null && N.length > 0 && E.length > 0) { - this.n = parseBigInt(N,16); - this.e = parseInt(E,16); - } - else - alert("Invalid RSA public key"); -} - -// Perform raw public operation on "x": return x^e (mod n) -function RSADoPublic(x) { - return x.modPowInt(this.e, this.n); -} - -// Return the PKCS#1 RSA encryption of "text" as an even-length hex string -function RSAEncrypt(text) { - var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3); - if(m == null) return null; - var c = this.doPublic(m); - if(c == null) return null; - var h = c.toString(16); - if((h.length & 1) == 0) return h; else return "0" + h; -} - -// Return the PKCS#1 OAEP RSA encryption of "text" as an even-length hex string -function RSAEncryptOAEP(text, hash) { - var m = oaep_pad(text, (this.n.bitLength()+7)>>3, hash); - if(m == null) return null; - var c = this.doPublic(m); - if(c == null) return null; - var h = c.toString(16); - if((h.length & 1) == 0) return h; else return "0" + h; -} - -// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string -//function RSAEncryptB64(text) { -// var h = this.encrypt(text); -// if(h) return hex2b64(h); else return null; -//} - -// protected -RSAKey.prototype.doPublic = RSADoPublic; - -// public -RSAKey.prototype.setPublic = RSASetPublic; -RSAKey.prototype.encrypt = RSAEncrypt; -RSAKey.prototype.encryptOAEP = RSAEncryptOAEP; -//RSAKey.prototype.encrypt_b64 = RSAEncryptB64; - -RSAKey.prototype.type = "RSA"; -/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ - */ -// Depends on rsa.js and jsbn2.js - -// Version 1.1: support utf-8 decoding in pkcs1unpad2 - -// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext -function pkcs1unpad2(d,n) { - var b = d.toByteArray(); - var i = 0; - while(i < b.length && b[i] == 0) ++i; - if(b.length-i != n-1 || b[i] != 2) - return null; - ++i; - while(b[i] != 0) - if(++i >= b.length) return null; - var ret = ""; - while(++i < b.length) { - var c = b[i] & 255; - if(c < 128) { // utf-8 decode - ret += String.fromCharCode(c); - } - else if((c > 191) && (c < 224)) { - ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63)); - ++i; - } - else { - ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63)); - i += 2; - } - } - return ret; -} - -// PKCS#1 (OAEP) mask generation function -function oaep_mgf1_str(seed, len, hash) -{ - var mask = '', i = 0; - - while (mask.length < len) - { - mask += hash(seed + String.fromCharCode.apply(String, [ - (i & 0xff000000) >> 24, - (i & 0x00ff0000) >> 16, - (i & 0x0000ff00) >> 8, - i & 0x000000ff])); - i += 1; - } - - return mask; -} - -var SHA1_SIZE = 20; - -// Undo PKCS#1 (OAEP) padding and, if valid, return the plaintext -function oaep_unpad(d, n, hash) -{ - d = d.toByteArray(); - - var i; - - for (i = 0; i < d.length; i += 1) - { - d[i] &= 0xff; - } - - while (d.length < n) - { - d.unshift(0); - } - - d = String.fromCharCode.apply(String, d); - - if (d.length < 2 * SHA1_SIZE + 2) - { - throw "Cipher too short"; - } - - var maskedSeed = d.substr(1, SHA1_SIZE) - var maskedDB = d.substr(SHA1_SIZE + 1); - - var seedMask = oaep_mgf1_str(maskedDB, SHA1_SIZE, hash || rstr_sha1); - var seed = [], i; - - for (i = 0; i < maskedSeed.length; i += 1) - { - seed[i] = maskedSeed.charCodeAt(i) ^ seedMask.charCodeAt(i); - } - - var dbMask = oaep_mgf1_str(String.fromCharCode.apply(String, seed), - d.length - SHA1_SIZE, rstr_sha1); - - var DB = []; - - for (i = 0; i < maskedDB.length; i += 1) - { - DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i); - } - - DB = String.fromCharCode.apply(String, DB); - - if (DB.substr(0, SHA1_SIZE) !== rstr_sha1('')) - { - throw "Hash mismatch"; - } - - DB = DB.substr(SHA1_SIZE); - - var first_one = DB.indexOf('\x01'); - var last_zero = (first_one != -1) ? DB.substr(0, first_one).lastIndexOf('\x00') : -1; - - if (last_zero + 1 != first_one) - { - throw "Malformed data"; - } - - return DB.substr(first_one + 1); -} - -// Set the private key fields N, e, and d from hex strings -function RSASetPrivate(N,E,D) { - this.isPrivate = true; - if (typeof N !== "string") - { - this.n = N; - this.e = E; - this.d = D; - } - else if(N != null && E != null && N.length > 0 && E.length > 0) { - this.n = parseBigInt(N,16); - this.e = parseInt(E,16); - this.d = parseBigInt(D,16); - } - else - alert("Invalid RSA private key"); -} - -// Set the private key fields N, e, d and CRT params from hex strings -function RSASetPrivateEx(N,E,D,P,Q,DP,DQ,C) { - this.isPrivate = true; - if (N == null) throw "RSASetPrivateEx N == null"; - if (E == null) throw "RSASetPrivateEx E == null"; - if (N.length == 0) throw "RSASetPrivateEx N.length == 0"; - if (E.length == 0) throw "RSASetPrivateEx E.length == 0"; - - if (N != null && E != null && N.length > 0 && E.length > 0) { - this.n = parseBigInt(N,16); - this.e = parseInt(E,16); - this.d = parseBigInt(D,16); - this.p = parseBigInt(P,16); - this.q = parseBigInt(Q,16); - this.dmp1 = parseBigInt(DP,16); - this.dmq1 = parseBigInt(DQ,16); - this.coeff = parseBigInt(C,16); - } else { - alert("Invalid RSA private key in RSASetPrivateEx"); - } -} - -// Generate a new random private key B bits long, using public expt E -function RSAGenerate(B,E) { - var rng = new SecureRandom(); - var qs = B>>1; - this.e = parseInt(E,16); - var ee = new BigInteger(E,16); - for(;;) { - for(;;) { - this.p = new BigInteger(B-qs,1,rng); - if(this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break; - } - for(;;) { - this.q = new BigInteger(qs,1,rng); - if(this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break; - } - if(this.p.compareTo(this.q) <= 0) { - var t = this.p; - this.p = this.q; - this.q = t; - } - var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1 - var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1 - var phi = p1.multiply(q1); - if(phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { - this.n = this.p.multiply(this.q); // this.n = p * q - this.d = ee.modInverse(phi); // this.d = - this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1) - this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1) - this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p - break; - } - } - this.isPrivate = true; -} - -// Perform raw private operation on "x": return x^d (mod n) -function RSADoPrivate(x) { - if(this.p == null || this.q == null) - return x.modPow(this.d, this.n); - - // TODO: re-calculate any missing CRT params - var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp? - var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq? - - while(xp.compareTo(xq) < 0) - xp = xp.add(this.p); - // NOTE: - // xp.subtract(xq) => cp -cq - // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h - // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M - return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq); -} - -// Return the PKCS#1 RSA decryption of "ctext". -// "ctext" is an even-length hex string and the output is a plain string. -function RSADecrypt(ctext) { - var c = parseBigInt(ctext, 16); - var m = this.doPrivate(c); - if(m == null) return null; - return pkcs1unpad2(m, (this.n.bitLength()+7)>>3); -} - -// Return the PKCS#1 OAEP RSA decryption of "ctext". -// "ctext" is an even-length hex string and the output is a plain string. -function RSADecryptOAEP(ctext, hash) { - var c = parseBigInt(ctext, 16); - var m = this.doPrivate(c); - if(m == null) return null; - return oaep_unpad(m, (this.n.bitLength()+7)>>3, hash); -} - -// Return the PKCS#1 RSA decryption of "ctext". -// "ctext" is a Base64-encoded string and the output is a plain string. -//function RSAB64Decrypt(ctext) { -// var h = b64tohex(ctext); -// if(h) return this.decrypt(h); else return null; -//} - -// protected -RSAKey.prototype.doPrivate = RSADoPrivate; - -// public -RSAKey.prototype.setPrivate = RSASetPrivate; -RSAKey.prototype.setPrivateEx = RSASetPrivateEx; -RSAKey.prototype.generate = RSAGenerate; -RSAKey.prototype.decrypt = RSADecrypt; -RSAKey.prototype.decryptOAEP = RSADecryptOAEP; -//RSAKey.prototype.b64_decrypt = RSAB64Decrypt; -/*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license - */ -// -// rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key -// to RSAKey class. -// -// version: 1.1.1 (2013-Apr-12) -// -// Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com) -// -// This software is licensed under the terms of the MIT License. -// http://kjur.github.com/jsrsasign/license/ -// -// The above copyright and license notice shall be -// included in all copies or substantial portions of the Software. -// -// -// Depends on: -// -// -// -// _RSApem_pemToBase64(sPEM) -// -// removing PEM header, PEM footer and space characters including -// new lines from PEM formatted RSA private key string. -// - -/** - * @fileOverview - * @name rsapem-1.1.js - * @author Kenji Urushima kenji.urushima@gmail.com - * @version 1.1 - * @license MIT License - */ -function _rsapem_pemToBase64(sPEMPrivateKey) { - var s = sPEMPrivateKey; - s = s.replace("-----BEGIN RSA PRIVATE KEY-----", ""); - s = s.replace("-----END RSA PRIVATE KEY-----", ""); - s = s.replace(/[ \n]+/g, ""); - return s; -} - -function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) { - var a = new Array(); - var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0); - var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1); - var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1); - var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1); - var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1); - var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1); - var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1); - var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1); - var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1); - a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1); - return a; -} - -function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) { - var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey); - var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]); - var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]); - var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]); - var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]); - var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]); - var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]); - var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]); - var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]); - var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]); - var a = new Array(); - a.push(v, n, e, d, p, q, dp, dq, co); - return a; -} - -/** - * read RSA private key from a ASN.1 hexadecimal string - * @name readPrivateKeyFromASN1HexString - * @memberOf RSAKey# - * @function - * @param {String} keyHex ASN.1 hexadecimal string of PKCS#1 private key. - * @since 1.1.1 - */ -function _rsapem_readPrivateKeyFromASN1HexString(keyHex) { - var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex); - this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]); -} - -/** - * read PKCS#1 private key from a string - * @name readPrivateKeyFromPEMString - * @memberOf RSAKey# - * @function - * @param {String} keyPEM string of PKCS#1 private key. - */ -function _rsapem_readPrivateKeyFromPEMString(keyPEM) { - var keyB64 = _rsapem_pemToBase64(keyPEM); - var keyHex = b64tohex(keyB64) // depends base64.js - var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex); - this.setPrivateEx(a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8]); -} - -RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString; -RSAKey.prototype.readPrivateKeyFromASN1HexString = _rsapem_readPrivateKeyFromASN1HexString; -/*! rsasign-1.2.7.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license - */ -var _RE_HEXDECONLY=new RegExp("");_RE_HEXDECONLY.compile("[^0-9a-f]","gi");function _rsasign_getHexPaddedDigestInfoForString(d,e,a){var b=function(f){return KJUR.crypto.Util.hashString(f,a)};var c=b(d);return KJUR.crypto.Util.getPaddedDigestInfoHex(c,a,e)}function _zeroPaddingOfSignature(e,d){var c="";var a=d/4-e.length;for(var b=0;b>24,(d&16711680)>>16,(d&65280)>>8,d&255]))));d+=1}return b}function _rsasign_signStringPSS(e,a,d){var c=function(f){return KJUR.crypto.Util.hashHex(f,a)};var b=c(rstrtohex(e));if(d===undefined){d=-1}return this.signWithMessageHashPSS(b,a,d)}function _rsasign_signWithMessageHashPSS(l,a,k){var b=hextorstr(l);var g=b.length;var m=this.n.bitLength()-1;var c=Math.ceil(m/8);var d;var o=function(i){return KJUR.crypto.Util.hashHex(i,a)};if(k===-1||k===undefined){k=g}else{if(k===-2){k=c-g-2}else{if(k<-2){throw"invalid salt length"}}}if(c<(g+k+2)){throw"data too long"}var f="";if(k>0){f=new Array(k);new SecureRandom().nextBytes(f);f=String.fromCharCode.apply(String,f)}var n=hextorstr(o(rstrtohex("\x00\x00\x00\x00\x00\x00\x00\x00"+b+f)));var j=[];for(d=0;d>(8*c-m))&255;q[0]&=~p;for(d=0;dthis.n.bitLength()){return 0}var i=this.doPublic(b);var e=i.toString(16).replace(/^1f+00/,"");var g=_rsasign_getAlgNameAndHashFromHexDisgestInfo(e);if(g.length==0){return false}var d=g[0];var h=g[1];var a=function(k){return KJUR.crypto.Util.hashString(k,d)};var c=a(f);return(h==c)}function _rsasign_verifyWithMessageHash(e,a){a=a.replace(_RE_HEXDECONLY,"");a=a.replace(/[ \n]+/g,"");var b=parseBigInt(a,16);if(b.bitLength()>this.n.bitLength()){return 0}var h=this.doPublic(b);var g=h.toString(16).replace(/^1f+00/,"");var c=_rsasign_getAlgNameAndHashFromHexDisgestInfo(g);if(c.length==0){return false}var d=c[0];var f=c[1];return(f==e)}function _rsasign_verifyStringPSS(c,b,a,f){var e=function(g){return KJUR.crypto.Util.hashHex(g,a)};var d=e(rstrtohex(c));if(f===undefined){f=-1}return this.verifyWithMessageHashPSS(d,b,a,f)}function _rsasign_verifyWithMessageHashPSS(f,s,l,c){var k=new BigInteger(s,16);if(k.bitLength()>this.n.bitLength()){return false}var r=function(i){return KJUR.crypto.Util.hashHex(i,l)};var j=hextorstr(f);var h=j.length;var g=this.n.bitLength()-1;var m=Math.ceil(g/8);var q;if(c===-1||c===undefined){c=h}else{if(c===-2){c=m-h-2}else{if(c<-2){throw"invalid salt length"}}}if(m<(h+c+2)){throw"data too long"}var a=this.doPublic(k).toByteArray();for(q=0;q>(8*m-g))&255;if((d.charCodeAt(0)&p)!==0){throw"bits beyond keysize not zero"}var n=pss_mgf1_str(e,d.length,r);var o=[];for(q=0;qMIT License - */ - -/* - * MEMO: - * f('3082025b02...', 2) ... 82025b ... 3bytes - * f('020100', 2) ... 01 ... 1byte - * f('0203001...', 2) ... 03 ... 1byte - * f('02818003...', 2) ... 8180 ... 2bytes - * f('3080....0000', 2) ... 80 ... -1 - * - * Requirements: - * - ASN.1 type octet length MUST be 1. - * (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...) - */ - -/** - * ASN.1 DER encoded hexadecimal string utility class - * @name ASN1HEX - * @class ASN.1 DER encoded hexadecimal string utility class - * @since jsrsasign 1.1 - */ -var ASN1HEX = new function() { - /** - * get byte length for ASN.1 L(length) bytes - * @name getByteLengthOfL_AtObj - * @memberOf ASN1HEX - * @function - * @param {String} s hexadecimal string of ASN.1 DER encoded data - * @param {Number} pos string index - * @return byte length for ASN.1 L(length) bytes - */ - this.getByteLengthOfL_AtObj = function(s, pos) { - if (s.substring(pos + 2, pos + 3) != '8') return 1; - var i = parseInt(s.substring(pos + 3, pos + 4)); - if (i == 0) return -1; // length octet '80' indefinite length - if (0 < i && i < 10) return i + 1; // including '8?' octet; - return -2; // malformed format - }; - - /** - * get hexadecimal string for ASN.1 L(length) bytes - * @name getHexOfL_AtObj - * @memberOf ASN1HEX - * @function - * @param {String} s hexadecimal string of ASN.1 DER encoded data - * @param {Number} pos string index - * @return {String} hexadecimal string for ASN.1 L(length) bytes - */ - this.getHexOfL_AtObj = function(s, pos) { - var len = this.getByteLengthOfL_AtObj(s, pos); - if (len < 1) return ''; - return s.substring(pos + 2, pos + 2 + len * 2); - }; - - // getting ASN.1 length value at the position 'idx' of - // hexa decimal string 's'. - // - // f('3082025b02...', 0) ... 82025b ... ??? - // f('020100', 0) ... 01 ... 1 - // f('0203001...', 0) ... 03 ... 3 - // f('02818003...', 0) ... 8180 ... 128 - /** - * get integer value of ASN.1 length for ASN.1 data - * @name getIntOfL_AtObj - * @memberOf ASN1HEX - * @function - * @param {String} s hexadecimal string of ASN.1 DER encoded data - * @param {Number} pos string index - * @return ASN.1 L(length) integer value - */ - this.getIntOfL_AtObj = function(s, pos) { - var hLength = this.getHexOfL_AtObj(s, pos); - if (hLength == '') return -1; - var bi; - if (parseInt(hLength.substring(0, 1)) < 8) { - bi = new BigInteger(hLength, 16); - } else { - bi = new BigInteger(hLength.substring(2), 16); - } - return bi.intValue(); - }; - - /** - * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'. - * @name getStartPosOfV_AtObj - * @memberOf ASN1HEX - * @function - * @param {String} s hexadecimal string of ASN.1 DER encoded data - * @param {Number} pos string index - */ - this.getStartPosOfV_AtObj = function(s, pos) { - var l_len = this.getByteLengthOfL_AtObj(s, pos); - if (l_len < 0) return l_len; - return pos + (l_len + 1) * 2; - }; - - /** - * get hexadecimal string of ASN.1 V(value) - * @name getHexOfV_AtObj - * @memberOf ASN1HEX - * @function - * @param {String} s hexadecimal string of ASN.1 DER encoded data - * @param {Number} pos string index - * @return {String} hexadecimal string of ASN.1 value. - */ - this.getHexOfV_AtObj = function(s, pos) { - var pos1 = this.getStartPosOfV_AtObj(s, pos); - var len = this.getIntOfL_AtObj(s, pos); - return s.substring(pos1, pos1 + len * 2); - }; - - /** - * get hexadecimal string of ASN.1 TLV at - * @name getHexOfTLV_AtObj - * @memberOf ASN1HEX - * @function - * @param {String} s hexadecimal string of ASN.1 DER encoded data - * @param {Number} pos string index - * @return {String} hexadecimal string of ASN.1 TLV. - * @since 1.1 - */ - this.getHexOfTLV_AtObj = function(s, pos) { - var hT = s.substr(pos, 2); - var hL = this.getHexOfL_AtObj(s, pos); - var hV = this.getHexOfV_AtObj(s, pos); - return hT + hL + hV; - }; - - /** - * get next sibling starting index for ASN.1 object string - * @name getPosOfNextSibling_AtObj - * @memberOf ASN1HEX - * @function - * @param {String} s hexadecimal string of ASN.1 DER encoded data - * @param {Number} pos string index - * @return next sibling starting index for ASN.1 object string - */ - this.getPosOfNextSibling_AtObj = function(s, pos) { - var pos1 = this.getStartPosOfV_AtObj(s, pos); - var len = this.getIntOfL_AtObj(s, pos); - return pos1 + len * 2; - }; - - /** - * get array of indexes of child ASN.1 objects - * @name getPosArrayOfChildren_AtObj - * @memberOf ASN1HEX - * @function - * @param {String} s hexadecimal string of ASN.1 DER encoded data - * @param {Number} start string index of ASN.1 object - * @return {Array of Number} array of indexes for childen of ASN.1 objects - */ - this.getPosArrayOfChildren_AtObj = function(h, pos) { - var a = new Array(); - var p0 = this.getStartPosOfV_AtObj(h, pos); - a.push(p0); - - var len = this.getIntOfL_AtObj(h, pos); - var p = p0; - var k = 0; - while (1) { - var pNext = this.getPosOfNextSibling_AtObj(h, p); - if (pNext == null || (pNext - p0 >= (len * 2))) break; - if (k >= 200) break; - - a.push(pNext); - p = pNext; - - k++; - } - - return a; - }; - - /** - * get string index of nth child object of ASN.1 object refered by h, idx - * @name getNthChildIndex_AtObj - * @memberOf ASN1HEX - * @function - * @param {String} h hexadecimal string of ASN.1 DER encoded data - * @param {Number} idx start string index of ASN.1 object - * @param {Number} nth for child - * @return {Number} string index of nth child. - * @since 1.1 - */ - this.getNthChildIndex_AtObj = function(h, idx, nth) { - var a = this.getPosArrayOfChildren_AtObj(h, idx); - return a[nth]; - }; - - // ========== decendant methods ============================== - /** - * get string index of nth child object of ASN.1 object refered by h, idx - * @name getDecendantIndexByNthList - * @memberOf ASN1HEX - * @function - * @param {String} h hexadecimal string of ASN.1 DER encoded data - * @param {Number} currentIndex start string index of ASN.1 object - * @param {Array of Number} nthList array list of nth - * @return {Number} string index refered by nthList - * @since 1.1 - * @example - * The "nthList" is a index list of structured ASN.1 object - * reference. Here is a sample structure and "nthList"s which - * refers each objects. - * - * SQUENCE - - * SEQUENCE - [0] - * IA5STRING 000 - [0, 0] - * UTF8STRING 001 - [0, 1] - * SET - [1] - * IA5STRING 010 - [1, 0] - * UTF8STRING 011 - [1, 1] - */ - this.getDecendantIndexByNthList = function(h, currentIndex, nthList) { - if (nthList.length == 0) { - return currentIndex; - } - var firstNth = nthList.shift(); - var a = this.getPosArrayOfChildren_AtObj(h, currentIndex); - return this.getDecendantIndexByNthList(h, a[firstNth], nthList); - }; - - /** - * get hexadecimal string of ASN.1 TLV refered by current index and nth index list. - * @name getDecendantHexTLVByNthList - * @memberOf ASN1HEX - * @function - * @param {String} h hexadecimal string of ASN.1 DER encoded data - * @param {Number} currentIndex start string index of ASN.1 object - * @param {Array of Number} nthList array list of nth - * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList - * @since 1.1 - */ - this.getDecendantHexTLVByNthList = function(h, currentIndex, nthList) { - var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); - return this.getHexOfTLV_AtObj(h, idx); - }; - - /** - * get hexadecimal string of ASN.1 V refered by current index and nth index list. - * @name getDecendantHexVByNthList - * @memberOf ASN1HEX - * @function - * @param {String} h hexadecimal string of ASN.1 DER encoded data - * @param {Number} currentIndex start string index of ASN.1 object - * @param {Array of Number} nthList array list of nth - * @return {Number} hexadecimal string of ASN.1 V refered by nthList - * @since 1.1 - */ - this.getDecendantHexVByNthList = function(h, currentIndex, nthList) { - var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); - return this.getHexOfV_AtObj(h, idx); - }; -}; - -/* - * @since asn1hex 1.1.4 - */ -ASN1HEX.getVbyList = function(h, currentIndex, nthList, checkingTag) { - var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); - if (idx === undefined) { - throw "can't find nthList object"; - } - if (checkingTag !== undefined) { - if (h.substr(idx, 2) != checkingTag) { - throw "checking tag doesn't match: " + - h.substr(idx,2) + "!=" + checkingTag; - } - } - return this.getHexOfV_AtObj(h, idx); -}; - -/** - * get OID string from hexadecimal encoded value - * @name hextooidstr - * @memberOf ASN1HEX - * @function - * @param {String} hex hexadecmal string of ASN.1 DER encoded OID value - * @return {String} OID string (ex. '1.2.3.4.567') - * @since asn1hex 1.1.5 - */ -ASN1HEX.hextooidstr = function(hex) { - var zeroPadding = function(s, len) { - if (s.length >= len) return s; - return new Array(len - s.length + 1).join('0') + s; - }; - - var a = []; - - // a[0], a[1] - var hex0 = hex.substr(0, 2); - var i0 = parseInt(hex0, 16); - a[0] = new String(Math.floor(i0 / 40)); - a[1] = new String(i0 % 40); - - // a[2]..a[n] - var hex1 = hex.substr(2); - var b = []; - for (var i = 0; i < hex1.length / 2; i++) { - b.push(parseInt(hex1.substr(i * 2, 2), 16)); - } - var c = []; - var cbin = ""; - for (var i = 0; i < b.length; i++) { - if (b[i] & 0x80) { - cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7); - } else { - cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7); - c.push(new String(parseInt(cbin, 2))); - cbin = ""; - } - } - - var s = a.join("."); - if (c.length > 0) s = s + "." + c.join("."); - return s; -}; - -/*! x509-1.1.3.js (c) 2012-2014 Kenji Urushima | kjur.github.com/jsrsasign/license - */ -/* - * x509.js - X509 class to read subject public key from certificate. - * - * Copyright (c) 2010-2014 Kenji Urushima (kenji.urushima@gmail.com) - * - * This software is licensed under the terms of the MIT License. - * http://kjur.github.com/jsrsasign/license - * - * The above copyright and license notice shall be - * included in all copies or substantial portions of the Software. - */ - -/** - * @fileOverview - * @name x509-1.1.js - * @author Kenji Urushima kenji.urushima@gmail.com - * @version x509 1.1.3 (2014-May-17) - * @since jsrsasign 1.x.x - * @license MIT License - */ - -/* - * Depends: - * base64.js - * rsa.js - * asn1hex.js - */ - -/** - * X.509 certificate class.
- * @class X.509 certificate class - * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object - * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key - * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key - * @property {String} hex hexacedimal string for X.509 certificate. - * @author Kenji Urushima - * @version 1.0.1 (08 May 2012) - * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ - */ -function X509() { - this.subjectPublicKeyRSA = null; - this.subjectPublicKeyRSA_hN = null; - this.subjectPublicKeyRSA_hE = null; - this.hex = null; - - // ===== get basic fields from hex ===================================== - - /** - * get hexadecimal string of serialNumber field of certificate.
- * @name getSerialNumberHex - * @memberOf X509# - * @function - */ - this.getSerialNumberHex = function() { - return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]); - }; - - /** - * get hexadecimal string of issuer field TLV of certificate.
- * @name getIssuerHex - * @memberOf X509# - * @function - */ - this.getIssuerHex = function() { - return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]); - }; - - /** - * get string of issuer field of certificate.
- * @name getIssuerString - * @memberOf X509# - * @function - */ - this.getIssuerString = function() { - return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3])); - }; - - /** - * get hexadecimal string of subject field of certificate.
- * @name getSubjectHex - * @memberOf X509# - * @function - */ - this.getSubjectHex = function() { - return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]); - }; - - /** - * get string of subject field of certificate.
- * @name getSubjectString - * @memberOf X509# - * @function - */ - this.getSubjectString = function() { - return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5])); - }; - - /** - * get notBefore field string of certificate.
- * @name getNotBefore - * @memberOf X509# - * @function - */ - this.getNotBefore = function() { - var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]); - s = s.replace(/(..)/g, "%$1"); - s = decodeURIComponent(s); - return s; - }; - - /** - * get notAfter field string of certificate.
- * @name getNotAfter - * @memberOf X509# - * @function - */ - this.getNotAfter = function() { - var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]); - s = s.replace(/(..)/g, "%$1"); - s = decodeURIComponent(s); - return s; - }; - - // ===== read certificate public key ========================== - - // ===== read certificate ===================================== - /** - * read PEM formatted X.509 certificate from string.
- * @name readCertPEM - * @memberOf X509# - * @function - * @param {String} sCertPEM string for PEM formatted X.509 certificate - */ - this.readCertPEM = function(sCertPEM) { - var hCert = X509.pemToHex(sCertPEM); - var a = X509.getPublicKeyHexArrayFromCertHex(hCert); - var rsa = new RSAKey(); - rsa.setPublic(a[0], a[1]); - this.subjectPublicKeyRSA = rsa; - this.subjectPublicKeyRSA_hN = a[0]; - this.subjectPublicKeyRSA_hE = a[1]; - this.hex = hCert; - }; - - this.readCertPEMWithoutRSAInit = function(sCertPEM) { - var hCert = X509.pemToHex(sCertPEM); - var a = X509.getPublicKeyHexArrayFromCertHex(hCert); - this.subjectPublicKeyRSA.setPublic(a[0], a[1]); - this.subjectPublicKeyRSA_hN = a[0]; - this.subjectPublicKeyRSA_hE = a[1]; - this.hex = hCert; - }; -}; - -X509.pemToBase64 = function(sCertPEM) { - var s = sCertPEM; - s = s.replace("-----BEGIN CERTIFICATE-----", ""); - s = s.replace("-----END CERTIFICATE-----", ""); - s = s.replace(/[ \n]+/g, ""); - return s; -}; - -X509.pemToHex = function(sCertPEM) { - var b64Cert = X509.pemToBase64(sCertPEM); - var hCert = b64tohex(b64Cert); - return hCert; -}; - -// NOTE: Without BITSTRING encapsulation. -X509.getSubjectPublicKeyPosFromCertHex = function(hCert) { - var pInfo = X509.getSubjectPublicKeyInfoPosFromCertHex(hCert); - if (pInfo == -1) return -1; - var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo); - if (a.length != 2) return -1; - var pBitString = a[1]; - if (hCert.substring(pBitString, pBitString + 2) != '03') return -1; - var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString); - - if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1; - return pBitStringV + 2; -}; - -// NOTE: privateKeyUsagePeriod field of X509v2 not supported. -// NOTE: v1 and v3 supported -X509.getSubjectPublicKeyInfoPosFromCertHex = function(hCert) { - var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0); - var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert); - if (a.length < 1) return -1; - if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3 - if (a.length < 6) return -1; - return a[6]; - } else { - if (a.length < 5) return -1; - return a[5]; - } -}; - -X509.getPublicKeyHexArrayFromCertHex = function(hCert) { - var p = X509.getSubjectPublicKeyPosFromCertHex(hCert); - var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p); - if (a.length != 2) return []; - var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]); - var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]); - if (hN != null && hE != null) { - return [hN, hE]; - } else { - return []; - } -}; - -X509.getHexTbsCertificateFromCert = function(hCert) { - var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0); - return pTbsCert; -}; - -X509.getPublicKeyHexArrayFromCertPEM = function(sCertPEM) { - var hCert = X509.pemToHex(sCertPEM); - var a = X509.getPublicKeyHexArrayFromCertHex(hCert); - return a; -}; - -X509.hex2dn = function(hDN) { - var s = ""; - var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0); - for (var i = 0; i < a.length; i++) { - var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]); - s = s + "/" + X509.hex2rdn(hRDN); - } - return s; -}; - -X509.hex2rdn = function(hRDN) { - var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]); - var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]); - var type = ""; - try { type = X509.DN_ATTRHEX[hType]; } catch (ex) { type = hType; } - hValue = hValue.replace(/(..)/g, "%$1"); - var value = decodeURIComponent(hValue); - return type + "=" + value; -}; - -X509.DN_ATTRHEX = { - "0603550406": "C", - "060355040a": "O", - "060355040b": "OU", - "0603550403": "CN", - "0603550405": "SN", - "0603550408": "ST", - "0603550407": "L", -}; - -/** - * get RSAKey/ECDSA public key object from PEM certificate string - * @name getPublicKeyFromCertPEM - * @memberOf X509 - * @function - * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate - * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key - * @since x509 1.1.1 - * @description - * NOTE: DSA is also supported since x509 1.1.2. - */ -X509.getPublicKeyFromCertPEM = function(sCertPEM) { - var info = X509.getPublicKeyInfoPropOfCertPEM(sCertPEM); - - if (info.algoid == "2a864886f70d010101") { // RSA - var aRSA = KEYUTIL.parsePublicRawRSAKeyHex(info.keyhex); - var key = new RSAKey(); - key.setPublic(aRSA.n, aRSA.e); - return key; - } else if (info.algoid == "2a8648ce3d0201") { // ECC - var curveName = KJUR.crypto.OID.oidhex2name[info.algparam]; - var key = new KJUR.crypto.ECDSA({'curve': curveName, 'info': info.keyhex}); - key.setPublicKeyHex(info.keyhex); - return key; - } else if (info.algoid == "2a8648ce380401") { // DSA 1.2.840.10040.4.1 - var p = ASN1HEX.getVbyList(info.algparam, 0, [0], "02"); - var q = ASN1HEX.getVbyList(info.algparam, 0, [1], "02"); - var g = ASN1HEX.getVbyList(info.algparam, 0, [2], "02"); - var y = ASN1HEX.getHexOfV_AtObj(info.keyhex, 0); - y = y.substr(2); - var key = new KJUR.crypto.DSA(); - key.setPublic(new BigInteger(p, 16), - new BigInteger(q, 16), - new BigInteger(g, 16), - new BigInteger(y, 16)); - return key; - } else { - throw "unsupported key"; - } -}; - -/** - * get public key information from PEM certificate - * @name getPublicKeyInfoPropOfCertPEM - * @memberOf X509 - * @function - * @param {String} sCertPEM string of PEM formatted certificate - * @return {Hash} hash of information for public key - * @since x509 1.1.1 - * @description - * Resulted associative array has following properties: - *
    - *
  • algoid - hexadecimal string of OID of asymmetric key algorithm
  • - *
  • algparam - hexadecimal string of OID of ECC curve name or null
  • - *
  • keyhex - hexadecimal string of key in the certificate
  • - *
- * @since x509 1.1.1 - */ -X509.getPublicKeyInfoPropOfCertPEM = function(sCertPEM) { - var result = {}; - result.algparam = null; - var hCert = X509.pemToHex(sCertPEM); - - // 1. Certificate ASN.1 - var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0); - if (a1.length != 3) - throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert - - // 2. tbsCertificate - if (hCert.substr(a1[0], 2) != "30") - throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq - - var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]); - - // 3. subjectPublicKeyInfo - if (a2.length < 7) - throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo - - var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[6]); - - if (a3.length != 2) - throw "malformed X.509 certificate PEM (code:004)"; // not AlgId and PubKey - - // 4. AlgId - var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]); - - if (a4.length != 2) - throw "malformed X.509 certificate PEM (code:005)"; // not 2 item in AlgId - - result.algoid = ASN1HEX.getHexOfV_AtObj(hCert, a4[0]); - - if (hCert.substr(a4[1], 2) == "06") { // EC - result.algparam = ASN1HEX.getHexOfV_AtObj(hCert, a4[1]); - } else if (hCert.substr(a4[1], 2) == "30") { // DSA - result.algparam = ASN1HEX.getHexOfTLV_AtObj(hCert, a4[1]); - } - - // 5. Public Key Hex - if (hCert.substr(a3[1], 2) != "03") - throw "malformed X.509 certificate PEM (code:006)"; // not bitstring - - var unusedBitAndKeyHex = ASN1HEX.getHexOfV_AtObj(hCert, a3[1]); - result.keyhex = unusedBitAndKeyHex.substr(2); - - return result; -}; - -/* - X509.prototype.readCertPEM = _x509_readCertPEM; - X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit; - X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex; - X509.prototype.getIssuerHex = _x509_getIssuerHex; - X509.prototype.getSubjectHex = _x509_getSubjectHex; - X509.prototype.getIssuerString = _x509_getIssuerString; - X509.prototype.getSubjectString = _x509_getSubjectString; - X509.prototype.getNotBefore = _x509_getNotBefore; - X509.prototype.getNotAfter = _x509_getNotAfter; -*/ -/*! crypto-1.1.5.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license - */ -/* - * crypto.js - Cryptographic Algorithm Provider class - * - * Copyright (c) 2013 Kenji Urushima (kenji.urushima@gmail.com) - * - * This software is licensed under the terms of the MIT License. - * http://kjur.github.com/jsrsasign/license - * - * The above copyright and license notice shall be - * included in all copies or substantial portions of the Software. - */ - -/** - * @fileOverview - * @name crypto-1.1.js - * @author Kenji Urushima kenji.urushima@gmail.com - * @version 1.1.5 (2013-Oct-06) - * @since jsrsasign 2.2 - * @license MIT License - */ - -/** - * kjur's class library name space - * @name KJUR - * @namespace kjur's class library name space - */ -if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; -/** - * kjur's cryptographic algorithm provider library name space - *

- * This namespace privides following crytpgrahic classes. - *

    - *
  • {@link KJUR.crypto.MessageDigest} - Java JCE(cryptograhic extension) style MessageDigest class
  • - *
  • {@link KJUR.crypto.Signature} - Java JCE(cryptograhic extension) style Signature class
  • - *
  • {@link KJUR.crypto.Util} - cryptographic utility functions and properties
  • - *
- * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2. - *

- * @name KJUR.crypto - * @namespace - */ -if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {}; - -/** - * static object for cryptographic function utilities - * @name KJUR.crypto.Util - * @class static object for cryptographic function utilities - * @property {Array} DIGESTINFOHEAD PKCS#1 DigestInfo heading hexadecimal bytes for each hash algorithms - * @property {Array} DEFAULTPROVIDER associative array of default provider name for each hash and signature algorithms - * @description - */ -KJUR.crypto.Util = new function() { - this.DIGESTINFOHEAD = { - 'sha1': "3021300906052b0e03021a05000414", - 'sha224': "302d300d06096086480165030402040500041c", - 'sha256': "3031300d060960864801650304020105000420", - 'sha384': "3041300d060960864801650304020205000430", - 'sha512': "3051300d060960864801650304020305000440", - 'md2': "3020300c06082a864886f70d020205000410", - 'md5': "3020300c06082a864886f70d020505000410", - 'ripemd160': "3021300906052b2403020105000414", - }; - - /* - * @since crypto 1.1.1 - */ - this.DEFAULTPROVIDER = { - 'md5': 'cryptojs', - 'sha1': 'cryptojs', - 'sha224': 'cryptojs', - 'sha256': 'cryptojs', - 'sha384': 'cryptojs', - 'sha512': 'cryptojs', - 'ripemd160': 'cryptojs', - 'hmacmd5': 'cryptojs', - 'hmacsha1': 'cryptojs', - 'hmacsha224': 'cryptojs', - 'hmacsha256': 'cryptojs', - 'hmacsha384': 'cryptojs', - 'hmacsha512': 'cryptojs', - 'hmacripemd160': 'cryptojs', - - 'MD5withRSA': 'cryptojs/jsrsa', - 'SHA1withRSA': 'cryptojs/jsrsa', - 'SHA224withRSA': 'cryptojs/jsrsa', - 'SHA256withRSA': 'cryptojs/jsrsa', - 'SHA384withRSA': 'cryptojs/jsrsa', - 'SHA512withRSA': 'cryptojs/jsrsa', - 'RIPEMD160withRSA': 'cryptojs/jsrsa', - - 'MD5withECDSA': 'cryptojs/jsrsa', - 'SHA1withECDSA': 'cryptojs/jsrsa', - 'SHA224withECDSA': 'cryptojs/jsrsa', - 'SHA256withECDSA': 'cryptojs/jsrsa', - 'SHA384withECDSA': 'cryptojs/jsrsa', - 'SHA512withECDSA': 'cryptojs/jsrsa', - 'RIPEMD160withECDSA': 'cryptojs/jsrsa', - - 'SHA1withDSA': 'cryptojs/jsrsa', - 'SHA224withDSA': 'cryptojs/jsrsa', - 'SHA256withDSA': 'cryptojs/jsrsa', - - 'MD5withRSAandMGF1': 'cryptojs/jsrsa', - 'SHA1withRSAandMGF1': 'cryptojs/jsrsa', - 'SHA224withRSAandMGF1': 'cryptojs/jsrsa', - 'SHA256withRSAandMGF1': 'cryptojs/jsrsa', - 'SHA384withRSAandMGF1': 'cryptojs/jsrsa', - 'SHA512withRSAandMGF1': 'cryptojs/jsrsa', - 'RIPEMD160withRSAandMGF1': 'cryptojs/jsrsa', - }; - - /* - * @since crypto 1.1.2 - */ - this.CRYPTOJSMESSAGEDIGESTNAME = { - 'md5': 'CryptoJS.algo.MD5', - 'sha1': 'CryptoJS.algo.SHA1', - 'sha224': 'CryptoJS.algo.SHA224', - 'sha256': 'CryptoJS.algo.SHA256', - 'sha384': 'CryptoJS.algo.SHA384', - 'sha512': 'CryptoJS.algo.SHA512', - 'ripemd160': 'CryptoJS.algo.RIPEMD160' - }; - - /** - * get hexadecimal DigestInfo - * @name getDigestInfoHex - * @memberOf KJUR.crypto.Util - * @function - * @param {String} hHash hexadecimal hash value - * @param {String} alg hash algorithm name (ex. 'sha1') - * @return {String} hexadecimal string DigestInfo ASN.1 structure - */ - this.getDigestInfoHex = function(hHash, alg) { - if (typeof this.DIGESTINFOHEAD[alg] == "undefined") - throw "alg not supported in Util.DIGESTINFOHEAD: " + alg; - return this.DIGESTINFOHEAD[alg] + hHash; - }; - - /** - * get PKCS#1 padded hexadecimal DigestInfo - * @name getPaddedDigestInfoHex - * @memberOf KJUR.crypto.Util - * @function - * @param {String} hHash hexadecimal hash value of message to be signed - * @param {String} alg hash algorithm name (ex. 'sha1') - * @param {Integer} keySize key bit length (ex. 1024) - * @return {String} hexadecimal string of PKCS#1 padded DigestInfo - */ - this.getPaddedDigestInfoHex = function(hHash, alg, keySize) { - var hDigestInfo = this.getDigestInfoHex(hHash, alg); - var pmStrLen = keySize / 4; // minimum PM length - - if (hDigestInfo.length + 22 > pmStrLen) // len(0001+ff(*8)+00+hDigestInfo)=22 - throw "key is too short for SigAlg: keylen=" + keySize + "," + alg; - - var hHead = "0001"; - var hTail = "00" + hDigestInfo; - var hMid = ""; - var fLen = pmStrLen - hHead.length - hTail.length; - for (var i = 0; i < fLen; i += 2) { - hMid += "ff"; - } - var hPaddedMessage = hHead + hMid + hTail; - return hPaddedMessage; - }; - - /** - * get hexadecimal hash of string with specified algorithm - * @name hashString - * @memberOf KJUR.crypto.Util - * @function - * @param {String} s input string to be hashed - * @param {String} alg hash algorithm name - * @return {String} hexadecimal string of hash value - * @since 1.1.1 - */ - this.hashString = function(s, alg) { - var md = new KJUR.crypto.MessageDigest({'alg': alg}); - return md.digestString(s); - }; - - /** - * get hexadecimal hash of hexadecimal string with specified algorithm - * @name hashHex - * @memberOf KJUR.crypto.Util - * @function - * @param {String} sHex input hexadecimal string to be hashed - * @param {String} alg hash algorithm name - * @return {String} hexadecimal string of hash value - * @since 1.1.1 - */ - this.hashHex = function(sHex, alg) { - var md = new KJUR.crypto.MessageDigest({'alg': alg}); - return md.digestHex(sHex); - }; - - /** - * get hexadecimal SHA1 hash of string - * @name sha1 - * @memberOf KJUR.crypto.Util - * @function - * @param {String} s input string to be hashed - * @return {String} hexadecimal string of hash value - * @since 1.0.3 - */ - this.sha1 = function(s) { - var md = new KJUR.crypto.MessageDigest({'alg':'sha1', 'prov':'cryptojs'}); - return md.digestString(s); - }; - - /** - * get hexadecimal SHA256 hash of string - * @name sha256 - * @memberOf KJUR.crypto.Util - * @function - * @param {String} s input string to be hashed - * @return {String} hexadecimal string of hash value - * @since 1.0.3 - */ - this.sha256 = function(s) { - var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'}); - return md.digestString(s); - }; - - this.sha256Hex = function(s) { - var md = new KJUR.crypto.MessageDigest({'alg':'sha256', 'prov':'cryptojs'}); - return md.digestHex(s); - }; - - /** - * get hexadecimal SHA512 hash of string - * @name sha512 - * @memberOf KJUR.crypto.Util - * @function - * @param {String} s input string to be hashed - * @return {String} hexadecimal string of hash value - * @since 1.0.3 - */ - this.sha512 = function(s) { - var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'}); - return md.digestString(s); - }; - - this.sha512Hex = function(s) { - var md = new KJUR.crypto.MessageDigest({'alg':'sha512', 'prov':'cryptojs'}); - return md.digestHex(s); - }; - - /** - * get hexadecimal MD5 hash of string - * @name md5 - * @memberOf KJUR.crypto.Util - * @function - * @param {String} s input string to be hashed - * @return {String} hexadecimal string of hash value - * @since 1.0.3 - */ - this.md5 = function(s) { - var md = new KJUR.crypto.MessageDigest({'alg':'md5', 'prov':'cryptojs'}); - return md.digestString(s); - }; - - /** - * get hexadecimal RIPEMD160 hash of string - * @name ripemd160 - * @memberOf KJUR.crypto.Util - * @function - * @param {String} s input string to be hashed - * @return {String} hexadecimal string of hash value - * @since 1.0.3 - */ - this.ripemd160 = function(s) { - var md = new KJUR.crypto.MessageDigest({'alg':'ripemd160', 'prov':'cryptojs'}); - return md.digestString(s); - }; - - /* - * @since 1.1.2 - */ - this.getCryptoJSMDByName = function(s) { - - }; -}; - -/** - * MessageDigest class which is very similar to java.security.MessageDigest class - * @name KJUR.crypto.MessageDigest - * @class MessageDigest class which is very similar to java.security.MessageDigest class - * @param {Array} params parameters for constructor - * @description - *
- * Currently this supports following algorithm and providers combination: - *
    - *
  • md5 - cryptojs
  • - *
  • sha1 - cryptojs
  • - *
  • sha224 - cryptojs
  • - *
  • sha256 - cryptojs
  • - *
  • sha384 - cryptojs
  • - *
  • sha512 - cryptojs
  • - *
  • ripemd160 - cryptojs
  • - *
  • sha256 - sjcl (NEW from crypto.js 1.0.4)
  • - *
- * @example - * // CryptoJS provider sample - * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/core.js"></script> - * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/sha1.js"></script> - * <script src="crypto-1.0.js"></script> - * var md = new KJUR.crypto.MessageDigest({alg: "sha1", prov: "cryptojs"}); - * md.updateString('aaa') - * var mdHex = md.digest() - * - * // SJCL(Stanford JavaScript Crypto Library) provider sample - * <script src="http://bitwiseshiftleft.github.io/sjcl/sjcl.js"></script> - * <script src="crypto-1.0.js"></script> - * var md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "sjcl"}); // sjcl supports sha256 only - * md.updateString('aaa') - * var mdHex = md.digest() - */ -KJUR.crypto.MessageDigest = function(params) { - var md = null; - var algName = null; - var provName = null; - - /** - * set hash algorithm and provider - * @name setAlgAndProvider - * @memberOf KJUR.crypto.MessageDigest - * @function - * @param {String} alg hash algorithm name - * @param {String} prov provider name - * @description - * @example - * // for SHA1 - * md.setAlgAndProvider('sha1', 'cryptojs'); - * // for RIPEMD160 - * md.setAlgAndProvider('ripemd160', 'cryptojs'); - */ - this.setAlgAndProvider = function(alg, prov) { - if (alg != null && prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg]; - - // for cryptojs - if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(alg) != -1 && - prov == 'cryptojs') { - try { - this.md = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[alg]).create(); - } catch (ex) { - throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; - } - this.updateString = function(str) { - this.md.update(str); - }; - this.updateHex = function(hex) { - var wHex = CryptoJS.enc.Hex.parse(hex); - this.md.update(wHex); - }; - this.digest = function() { - var hash = this.md.finalize(); - return hash.toString(CryptoJS.enc.Hex); - }; - this.digestString = function(str) { - this.updateString(str); - return this.digest(); - }; - this.digestHex = function(hex) { - this.updateHex(hex); - return this.digest(); - }; - } - if (':sha256:'.indexOf(alg) != -1 && - prov == 'sjcl') { - try { - this.md = new sjcl.hash.sha256(); - } catch (ex) { - throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; - } - this.updateString = function(str) { - this.md.update(str); - }; - this.updateHex = function(hex) { - var baHex = sjcl.codec.hex.toBits(hex); - this.md.update(baHex); - }; - this.digest = function() { - var hash = this.md.finalize(); - return sjcl.codec.hex.fromBits(hash); - }; - this.digestString = function(str) { - this.updateString(str); - return this.digest(); - }; - this.digestHex = function(hex) { - this.updateHex(hex); - return this.digest(); - }; - } - }; - - /** - * update digest by specified string - * @name updateString - * @memberOf KJUR.crypto.MessageDigest - * @function - * @param {String} str string to update - * @description - * @example - * md.updateString('New York'); - */ - this.updateString = function(str) { - throw "updateString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; - }; - - /** - * update digest by specified hexadecimal string - * @name updateHex - * @memberOf KJUR.crypto.MessageDigest - * @function - * @param {String} hex hexadecimal string to update - * @description - * @example - * md.updateHex('0afe36'); - */ - this.updateHex = function(hex) { - throw "updateHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; - }; - - /** - * completes hash calculation and returns hash result - * @name digest - * @memberOf KJUR.crypto.MessageDigest - * @function - * @description - * @example - * md.digest() - */ - this.digest = function() { - throw "digest() not supported for this alg/prov: " + this.algName + "/" + this.provName; - }; - - /** - * performs final update on the digest using string, then completes the digest computation - * @name digestString - * @memberOf KJUR.crypto.MessageDigest - * @function - * @param {String} str string to final update - * @description - * @example - * md.digestString('aaa') - */ - this.digestString = function(str) { - throw "digestString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; - }; - - /** - * performs final update on the digest using hexadecimal string, then completes the digest computation - * @name digestHex - * @memberOf KJUR.crypto.MessageDigest - * @function - * @param {String} hex hexadecimal string to final update - * @description - * @example - * md.digestHex('0f2abd') - */ - this.digestHex = function(hex) { - throw "digestHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; - }; - - if (params !== undefined) { - if (params['alg'] !== undefined) { - this.algName = params['alg']; - if (params['prov'] === undefined) - this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; - this.setAlgAndProvider(this.algName, this.provName); - } - } -}; - -/** - * Mac(Message Authentication Code) class which is very similar to java.security.Mac class - * @name KJUR.crypto.Mac - * @class Mac class which is very similar to java.security.Mac class - * @param {Array} params parameters for constructor - * @description - *
- * Currently this supports following algorithm and providers combination: - *
    - *
  • hmacmd5 - cryptojs
  • - *
  • hmacsha1 - cryptojs
  • - *
  • hmacsha224 - cryptojs
  • - *
  • hmacsha256 - cryptojs
  • - *
  • hmacsha384 - cryptojs
  • - *
  • hmacsha512 - cryptojs
  • - *
- * NOTE: HmacSHA224 and HmacSHA384 issue was fixed since jsrsasign 4.1.4. - * Please use 'ext/cryptojs-312-core-fix*.js' instead of 'core.js' of original CryptoJS - * to avoid those issue. - * @example - * var mac = new KJUR.crypto.Mac({alg: "HmacSHA1", prov: "cryptojs", "pass": "pass"}); - * mac.updateString('aaa') - * var macHex = md.doFinal() - */ -KJUR.crypto.Mac = function(params) { - var mac = null; - var pass = null; - var algName = null; - var provName = null; - var algProv = null; - - this.setAlgAndProvider = function(alg, prov) { - if (alg == null) alg = "hmacsha1"; - - alg = alg.toLowerCase(); - if (alg.substr(0, 4) != "hmac") { - throw "setAlgAndProvider unsupported HMAC alg: " + alg; - } - - if (prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg]; - this.algProv = alg + "/" + prov; - - var hashAlg = alg.substr(4); - - // for cryptojs - if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(hashAlg) != -1 && - prov == 'cryptojs') { - try { - var mdObj = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[hashAlg]); - this.mac = CryptoJS.algo.HMAC.create(mdObj, this.pass); - } catch (ex) { - throw "setAlgAndProvider hash alg set fail hashAlg=" + hashAlg + "/" + ex; - } - this.updateString = function(str) { - this.mac.update(str); - }; - this.updateHex = function(hex) { - var wHex = CryptoJS.enc.Hex.parse(hex); - this.mac.update(wHex); - }; - this.doFinal = function() { - var hash = this.mac.finalize(); - return hash.toString(CryptoJS.enc.Hex); - }; - this.doFinalString = function(str) { - this.updateString(str); - return this.doFinal(); - }; - this.doFinalHex = function(hex) { - this.updateHex(hex); - return this.doFinal(); - }; - } - }; - - /** - * update digest by specified string - * @name updateString - * @memberOf KJUR.crypto.Mac - * @function - * @param {String} str string to update - * @description - * @example - * md.updateString('New York'); - */ - this.updateString = function(str) { - throw "updateString(str) not supported for this alg/prov: " + this.algProv; - }; - - /** - * update digest by specified hexadecimal string - * @name updateHex - * @memberOf KJUR.crypto.Mac - * @function - * @param {String} hex hexadecimal string to update - * @description - * @example - * md.updateHex('0afe36'); - */ - this.updateHex = function(hex) { - throw "updateHex(hex) not supported for this alg/prov: " + this.algProv; - }; - - /** - * completes hash calculation and returns hash result - * @name doFinal - * @memberOf KJUR.crypto.Mac - * @function - * @description - * @example - * md.digest() - */ - this.doFinal = function() { - throw "digest() not supported for this alg/prov: " + this.algProv; - }; - - /** - * performs final update on the digest using string, then completes the digest computation - * @name doFinalString - * @memberOf KJUR.crypto.Mac - * @function - * @param {String} str string to final update - * @description - * @example - * md.digestString('aaa') - */ - this.doFinalString = function(str) { - throw "digestString(str) not supported for this alg/prov: " + this.algProv; - }; - - /** - * performs final update on the digest using hexadecimal string, - * then completes the digest computation - * @name doFinalHex - * @memberOf KJUR.crypto.Mac - * @function - * @param {String} hex hexadecimal string to final update - * @description - * @example - * md.digestHex('0f2abd') - */ - this.doFinalHex = function(hex) { - throw "digestHex(hex) not supported for this alg/prov: " + this.algProv; - }; - - if (params !== undefined) { - if (params['pass'] !== undefined) { - this.pass = params['pass']; - } - if (params['alg'] !== undefined) { - this.algName = params['alg']; - if (params['prov'] === undefined) - this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; - this.setAlgAndProvider(this.algName, this.provName); - } - } -}; - -/** - * Signature class which is very similar to java.security.Signature class - * @name KJUR.crypto.Signature - * @class Signature class which is very similar to java.security.Signature class - * @param {Array} params parameters for constructor - * @property {String} state Current state of this signature object whether 'SIGN', 'VERIFY' or null - * @description - *
- * As for params of constructor's argument, it can be specify following attributes: - *
    - *
  • alg - signature algorithm name (ex. {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160}with{RSA,ECDSA,DSA})
  • - *
  • provider - currently 'cryptojs/jsrsa' only
  • - *
- *

SUPPORTED ALGORITHMS AND PROVIDERS

- * This Signature class supports following signature algorithm and provider names: - *
    - *
  • MD5withRSA - cryptojs/jsrsa
  • - *
  • SHA1withRSA - cryptojs/jsrsa
  • - *
  • SHA224withRSA - cryptojs/jsrsa
  • - *
  • SHA256withRSA - cryptojs/jsrsa
  • - *
  • SHA384withRSA - cryptojs/jsrsa
  • - *
  • SHA512withRSA - cryptojs/jsrsa
  • - *
  • RIPEMD160withRSA - cryptojs/jsrsa
  • - *
  • MD5withECDSA - cryptojs/jsrsa
  • - *
  • SHA1withECDSA - cryptojs/jsrsa
  • - *
  • SHA224withECDSA - cryptojs/jsrsa
  • - *
  • SHA256withECDSA - cryptojs/jsrsa
  • - *
  • SHA384withECDSA - cryptojs/jsrsa
  • - *
  • SHA512withECDSA - cryptojs/jsrsa
  • - *
  • RIPEMD160withECDSA - cryptojs/jsrsa
  • - *
  • MD5withRSAandMGF1 - cryptojs/jsrsa
  • - *
  • SHA1withRSAandMGF1 - cryptojs/jsrsa
  • - *
  • SHA224withRSAandMGF1 - cryptojs/jsrsa
  • - *
  • SHA256withRSAandMGF1 - cryptojs/jsrsa
  • - *
  • SHA384withRSAandMGF1 - cryptojs/jsrsa
  • - *
  • SHA512withRSAandMGF1 - cryptojs/jsrsa
  • - *
  • RIPEMD160withRSAandMGF1 - cryptojs/jsrsa
  • - *
  • SHA1withDSA - cryptojs/jsrsa
  • - *
  • SHA224withDSA - cryptojs/jsrsa
  • - *
  • SHA256withDSA - cryptojs/jsrsa
  • - *
- * Here are supported elliptic cryptographic curve names and their aliases for ECDSA: - *
    - *
  • secp256k1
  • - *
  • secp256r1, NIST P-256, P-256, prime256v1
  • - *
  • secp384r1, NIST P-384, P-384
  • - *
- * NOTE1: DSA signing algorithm is also supported since crypto 1.1.5. - *

EXAMPLES

- * @example - * // RSA signature generation - * var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA"}); - * sig.init(prvKeyPEM); - * sig.updateString('aaa'); - * var hSigVal = sig.sign(); - * - * // DSA signature validation - * var sig2 = new KJUR.crypto.Signature({"alg": "SHA1withDSA"}); - * sig2.init(certPEM); - * sig.updateString('aaa'); - * var isValid = sig2.verify(hSigVal); - * - * // ECDSA signing - * var sig = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'}); - * sig.init(prvKeyPEM); - * sig.updateString('aaa'); - * var sigValueHex = sig.sign(); - * - * // ECDSA verifying - * var sig2 = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'}); - * sig.init(certPEM); - * sig.updateString('aaa'); - * var isValid = sig.verify(sigValueHex); - */ -KJUR.crypto.Signature = function(params) { - var prvKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for signing - var pubKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for verifying - - var md = null; // KJUR.crypto.MessageDigest object - var sig = null; - var algName = null; - var provName = null; - var algProvName = null; - var mdAlgName = null; - var pubkeyAlgName = null; // rsa,ecdsa,rsaandmgf1(=rsapss) - var state = null; - var pssSaltLen = -1; - var initParams = null; - - var sHashHex = null; // hex hash value for hex - var hDigestInfo = null; - var hPaddedDigestInfo = null; - var hSign = null; - - this._setAlgNames = function() { - if (this.algName.match(/^(.+)with(.+)$/)) { - this.mdAlgName = RegExp.$1.toLowerCase(); - this.pubkeyAlgName = RegExp.$2.toLowerCase(); - } - }; - - this._zeroPaddingOfSignature = function(hex, bitLength) { - var s = ""; - var nZero = bitLength / 4 - hex.length; - for (var i = 0; i < nZero; i++) { - s = s + "0"; - } - return s + hex; - }; - - /** - * set signature algorithm and provider - * @name setAlgAndProvider - * @memberOf KJUR.crypto.Signature - * @function - * @param {String} alg signature algorithm name - * @param {String} prov provider name - * @description - * @example - * md.setAlgAndProvider('SHA1withRSA', 'cryptojs/jsrsa'); - */ - this.setAlgAndProvider = function(alg, prov) { - this._setAlgNames(); - if (prov != 'cryptojs/jsrsa') - throw "provider not supported: " + prov; - - if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(this.mdAlgName) != -1) { - try { - this.md = new KJUR.crypto.MessageDigest({'alg':this.mdAlgName}); - } catch (ex) { - throw "setAlgAndProvider hash alg set fail alg=" + - this.mdAlgName + "/" + ex; - } - - this.init = function(keyparam, pass) { - var keyObj = null; + // globals + var _promiseFactory; + var _httpRequest; + /* + CryptoJS v3.1.2 + code.google.com/p/crypto-js + (c) 2009-2013 by Jeff Mott. All rights reserved. + code.google.com/p/crypto-js/wiki/License + */ + /** + * CryptoJS core components. + */ + var CryptoJS = CryptoJS || (function (Math, undefined) { + /** + * CryptoJS namespace. + */ + var C = {}; + + /** + * Library namespace. + */ + var C_lib = C.lib = {}; + + /** + * Base object for prototypal inheritance. + */ + var Base = C_lib.Base = (function () { + function F() { } + + return { + /** + * Creates a new object that inherits from this object. + * + * @param {Object} overrides Properties to copy into the new object. + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * field: 'value', + * + * method: function () { + * } + * }); + */ + extend: function (overrides) { + // Spawn + F.prototype = this; + var subtype = new F(); + + // Augment + if (overrides) { + subtype.mixIn(overrides); + } + + // Create default initializer + if (!subtype.hasOwnProperty('init')) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } + + // Initializer's prototype is the subtype object + subtype.init.prototype = subtype; + + // Reference supertype + subtype.$super = this; + + return subtype; + }, + + /** + * Extends this object and runs the init method. + * Arguments to create() will be passed to init(). + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var instance = MyType.create(); + */ + create: function () { + var instance = this.extend(); + instance.init.apply(instance, arguments); + + return instance; + }, + + /** + * Initializes a newly created object. + * Override this method to add some logic when your objects are created. + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * init: function () { + * // ... + * } + * }); + */ + init: function () { + }, + + /** + * Copies properties into this object. + * + * @param {Object} properties The properties to mix in. + * + * @example + * + * MyType.mixIn({ + * field: 'value' + * }); + */ + mixIn: function (properties) { + for (var propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } + } + + // IE won't copy toString using the loop above + if (properties.hasOwnProperty('toString')) { + this.toString = properties.toString; + } + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = instance.clone(); + */ + clone: function () { + return this.init.prototype.extend(this); + } + }; + }()); + + /** + * An array of 32-bit words. + * + * @property {Array} words The array of 32-bit words. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var WordArray = C_lib.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of 32-bit words. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.create(); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; + } + }, + + /** + * Converts this word array to a string. + * + * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex + * + * @return {string} The stringified word array. + * + * @example + * + * var string = wordArray + ''; + * var string = wordArray.toString(); + * var string = wordArray.toString(CryptoJS.enc.Utf8); + */ + toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, + + /** + * Concatenates a word array to this word array. + * + * @param {WordArray} wordArray The word array to append. + * + * @return {WordArray} This word array. + * + * @example + * + * wordArray1.concat(wordArray2); + */ + concat: function (wordArray) { + // Shortcuts + var thisWords = this.words; + var thatWords = wordArray.words; + var thisSigBytes = this.sigBytes; + var thatSigBytes = wordArray.sigBytes; + + // Clamp excess bits + this.clamp(); + + // Concat + if (thisSigBytes % 4) { + // Copy one byte at a time + for (var i = 0; i < thatSigBytes; i++) { + var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); + } + } else if (thatWords.length > 0xffff) { + // Copy one word at a time + for (var i = 0; i < thatSigBytes; i += 4) { + thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; + } + } else { + // Copy all words at once + thisWords.push.apply(thisWords, thatWords); + } + this.sigBytes += thatSigBytes; + + // Chainable + return this; + }, + + /** + * Removes insignificant bits. + * + * @example + * + * wordArray.clamp(); + */ + clamp: function () { + // Shortcuts + var words = this.words; + var sigBytes = this.sigBytes; + + // Clamp + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, + + /** + * Creates a copy of this word array. + * + * @return {WordArray} The clone. + * + * @example + * + * var clone = wordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone.words = this.words.slice(0); + + return clone; + }, + + /** + * Creates a word array filled with random bytes. + * + * @param {number} nBytes The number of random bytes to generate. + * + * @return {WordArray} The random word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.random(16); + */ + random: function (nBytes) { + var words = []; + for (var i = 0; i < nBytes; i += 4) { + words.push((Math.random() * 0x100000000) | 0); + } + + return new WordArray.init(words, nBytes); + } + }); + + /** + * Encoder namespace. + */ + var C_enc = C.enc = {}; + + /** + * Hex encoding strategy. + */ + var Hex = C_enc.Hex = { + /** + * Converts a word array to a hex string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The hex string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.enc.Hex.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var hexChars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } + + return hexChars.join(''); + }, + + /** + * Converts a hex string to a word array. + * + * @param {string} hexStr The hex string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Hex.parse(hexString); + */ + parse: function (hexStr) { + // Shortcut + var hexStrLength = hexStr.length; + + // Convert + var words = []; + for (var i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } + + return new WordArray.init(words, hexStrLength / 2); + } + }; + + /** + * Latin1 encoding strategy. + */ + var Latin1 = C_enc.Latin1 = { + /** + * Converts a word array to a Latin1 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Latin1 string. + * + * @static + * + * @example + * + * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var latin1Chars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } + + return latin1Chars.join(''); + }, + + /** + * Converts a Latin1 string to a word array. + * + * @param {string} latin1Str The Latin1 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); + */ + parse: function (latin1Str) { + // Shortcut + var latin1StrLength = latin1Str.length; + + // Convert + var words = []; + for (var i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } + + return new WordArray.init(words, latin1StrLength); + } + }; + + /** + * UTF-8 encoding strategy. + */ + var Utf8 = C_enc.Utf8 = { + /** + * Converts a word array to a UTF-8 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-8 string. + * + * @static + * + * @example + * + * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); + */ + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error('Malformed UTF-8 data'); + } + }, + + /** + * Converts a UTF-8 string to a word array. + * + * @param {string} utf8Str The UTF-8 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); + */ + parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + } + }; + + /** + * Abstract buffered block algorithm template. + * + * The property blockSize must be implemented in a concrete subtype. + * + * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 + */ + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ + /** + * Resets this block algorithm's data buffer to its initial state. + * + * @example + * + * bufferedBlockAlgorithm.reset(); + */ + reset: function () { + // Initial values + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, + + /** + * Adds new data to this block algorithm's buffer. + * + * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. + * + * @example + * + * bufferedBlockAlgorithm._append('data'); + * bufferedBlockAlgorithm._append(wordArray); + */ + _append: function (data) { + // Convert string to WordArray, else assume WordArray already + if (typeof data == 'string') { + data = Utf8.parse(data); + } + + // Append + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, + + /** + * Processes available data blocks. + * + * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. + * + * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. + * + * @return {WordArray} The processed data. + * + * @example + * + * var processedData = bufferedBlockAlgorithm._process(); + * var processedData = bufferedBlockAlgorithm._process(!!'flush'); + */ + _process: function (doFlush) { + // Shortcuts + var data = this._data; + var dataWords = data.words; + var dataSigBytes = data.sigBytes; + var blockSize = this.blockSize; + var blockSizeBytes = blockSize * 4; + + // Count blocks ready + var nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + // Round up to include partial blocks + nBlocksReady = Math.ceil(nBlocksReady); + } else { + // Round down to include only full blocks, + // less the number of blocks that must remain in the buffer + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } + + // Count words ready + var nWordsReady = nBlocksReady * blockSize; + + // Count bytes ready + var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + + // Process blocks + if (nWordsReady) { + for (var offset = 0; offset < nWordsReady; offset += blockSize) { + // Perform concrete-algorithm logic + this._doProcessBlock(dataWords, offset); + } + + // Remove processed words + var processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; + } + + // Return processed words + return new WordArray.init(processedWords, nBytesReady); + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = bufferedBlockAlgorithm.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone._data = this._data.clone(); + + return clone; + }, + + _minBufferSize: 0 + }); + + /** + * Abstract hasher template. + * + * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) + */ + var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + */ + cfg: Base.extend(), + + /** + * Initializes a newly created hasher. + * + * @param {Object} cfg (Optional) The configuration options to use for this hash computation. + * + * @example + * + * var hasher = CryptoJS.algo.SHA256.create(); + */ + init: function (cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Set initial values + this.reset(); + }, + + /** + * Resets this hasher to its initial state. + * + * @example + * + * hasher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-hasher logic + this._doReset(); + }, + + /** + * Updates this hasher with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {Hasher} This hasher. + * + * @example + * + * hasher.update('message'); + * hasher.update(wordArray); + */ + update: function (messageUpdate) { + // Append + this._append(messageUpdate); + + // Update the hash + this._process(); + + // Chainable + return this; + }, + + /** + * Finalizes the hash computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The hash. + * + * @example + * + * var hash = hasher.finalize(); + * var hash = hasher.finalize('message'); + * var hash = hasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Final message update + if (messageUpdate) { + this._append(messageUpdate); + } + + // Perform concrete-hasher logic + var hash = this._doFinalize(); + + return hash; + }, + + blockSize: 512 / 32, + + /** + * Creates a shortcut function to a hasher's object interface. + * + * @param {Hasher} hasher The hasher to create a helper for. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); + */ + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, + + /** + * Creates a shortcut function to the HMAC's object interface. + * + * @param {Hasher} hasher The hasher to use in this HMAC helper. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); + */ + _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + } + }); + + /** + * Algorithm namespace. + */ + var C_algo = C.algo = {}; + + return C; + }(Math)); + + /* + CryptoJS v3.1.2 + code.google.com/p/crypto-js + (c) 2009-2013 by Jeff Mott. All rights reserved. + code.google.com/p/crypto-js/wiki/License + */ + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Reusable object + var W = []; + + /** + * SHA-1 hash algorithm. + */ + var SHA1 = C_algo.SHA1 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476, + 0xc3d2e1f0 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + + // Computation + for (var i = 0; i < 80; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; + W[i] = (n << 1) | (n >>> 31); + } + + var t = ((a << 5) | (a >>> 27)) + e + W[i]; + if (i < 20) { + t += ((b & c) | (~b & d)) + 0x5a827999; + } else if (i < 40) { + t += (b ^ c ^ d) + 0x6ed9eba1; + } else if (i < 60) { + t += ((b & c) | (b & d) | (c & d)) - 0x70e44324; + } else /* if (i < 80) */ { + t += (b ^ c ^ d) - 0x359d3e2a; + } + + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA1('message'); + * var hash = CryptoJS.SHA1(wordArray); + */ + C.SHA1 = Hasher._createHelper(SHA1); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA1(message, key); + */ + C.HmacSHA1 = Hasher._createHmacHelper(SHA1); + }()); + + /* + CryptoJS v3.1.2 + code.google.com/p/crypto-js + (c) 2009-2013 by Jeff Mott. All rights reserved. + code.google.com/p/crypto-js/wiki/License + */ + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Initialization and round constants tables + var H = []; + var K = []; + + // Compute constants + (function () { + function isPrime(n) { + var sqrtN = Math.sqrt(n); + for (var factor = 2; factor <= sqrtN; factor++) { + if (!(n % factor)) { + return false; + } + } + + return true; + } + + function getFractionalBits(n) { + return ((n - (n | 0)) * 0x100000000) | 0; + } + + var n = 2; + var nPrime = 0; + while (nPrime < 64) { + if (isPrime(n)) { + if (nPrime < 8) { + H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); + } + K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); + + nPrime++; + } + + n++; + } + }()); + + // Reusable object + var W = []; + + /** + * SHA-256 hash algorithm. + */ + var SHA256 = C_algo.SHA256 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init(H.slice(0)); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + var f = H[5]; + var g = H[6]; + var h = H[7]; + + // Computation + for (var i = 0; i < 64; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var gamma0x = W[i - 15]; + var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ + ((gamma0x << 14) | (gamma0x >>> 18)) ^ + (gamma0x >>> 3); + + var gamma1x = W[i - 2]; + var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ + ((gamma1x << 13) | (gamma1x >>> 19)) ^ + (gamma1x >>> 10); + + W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; + } + + var ch = (e & f) ^ (~e & g); + var maj = (a & b) ^ (a & c) ^ (b & c); + + var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); + var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); + + var t1 = h + sigma1 + ch + K[i] + W[i]; + var t2 = sigma0 + maj; + + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + H[5] = (H[5] + f) | 0; + H[6] = (H[6] + g) | 0; + H[7] = (H[7] + h) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA256('message'); + * var hash = CryptoJS.SHA256(wordArray); + */ + C.SHA256 = Hasher._createHelper(SHA256); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA256(message, key); + */ + C.HmacSHA256 = Hasher._createHmacHelper(SHA256); + }(Math)); + + /* + CryptoJS v3.1.2 + code.google.com/p/crypto-js + (c) 2009-2013 by Jeff Mott. All rights reserved. + code.google.com/p/crypto-js/wiki/License + */ + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var X32WordArray = C_lib.WordArray; + + /** + * x64 namespace. + */ + var C_x64 = C.x64 = {}; + + /** + * A 64-bit word. + */ + var X64Word = C_x64.Word = Base.extend({ + /** + * Initializes a newly created 64-bit word. + * + * @param {number} high The high 32 bits. + * @param {number} low The low 32 bits. + * + * @example + * + * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607); + */ + init: function (high, low) { + this.high = high; + this.low = low; + } + + /** + * Bitwise NOTs this word. + * + * @return {X64Word} A new x64-Word object after negating. + * + * @example + * + * var negated = x64Word.not(); + */ + // not: function () { + // var high = ~this.high; + // var low = ~this.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ANDs this word with the passed word. + * + * @param {X64Word} word The x64-Word to AND with this word. + * + * @return {X64Word} A new x64-Word object after ANDing. + * + * @example + * + * var anded = x64Word.and(anotherX64Word); + */ + // and: function (word) { + // var high = this.high & word.high; + // var low = this.low & word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to OR with this word. + * + * @return {X64Word} A new x64-Word object after ORing. + * + * @example + * + * var ored = x64Word.or(anotherX64Word); + */ + // or: function (word) { + // var high = this.high | word.high; + // var low = this.low | word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise XORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to XOR with this word. + * + * @return {X64Word} A new x64-Word object after XORing. + * + * @example + * + * var xored = x64Word.xor(anotherX64Word); + */ + // xor: function (word) { + // var high = this.high ^ word.high; + // var low = this.low ^ word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the left. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftL(25); + */ + // shiftL: function (n) { + // if (n < 32) { + // var high = (this.high << n) | (this.low >>> (32 - n)); + // var low = this.low << n; + // } else { + // var high = this.low << (n - 32); + // var low = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the right. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftR(7); + */ + // shiftR: function (n) { + // if (n < 32) { + // var low = (this.low >>> n) | (this.high << (32 - n)); + // var high = this.high >>> n; + // } else { + // var low = this.high >>> (n - 32); + // var high = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Rotates this word n bits to the left. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotL(25); + */ + // rotL: function (n) { + // return this.shiftL(n).or(this.shiftR(64 - n)); + // }, + + /** + * Rotates this word n bits to the right. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotR(7); + */ + // rotR: function (n) { + // return this.shiftR(n).or(this.shiftL(64 - n)); + // }, + + /** + * Adds this word with the passed word. + * + * @param {X64Word} word The x64-Word to add with this word. + * + * @return {X64Word} A new x64-Word object after adding. + * + * @example + * + * var added = x64Word.add(anotherX64Word); + */ + // add: function (word) { + // var low = (this.low + word.low) | 0; + // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0; + // var high = (this.high + word.high + carry) | 0; + + // return X64Word.create(high, low); + // } + }); + + /** + * An array of 64-bit words. + * + * @property {Array} words The array of CryptoJS.x64.Word objects. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var X64WordArray = C_x64.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.x64.WordArray.create(); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ]); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ], 10); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 8; + } + }, + + /** + * Converts this 64-bit word array to a 32-bit word array. + * + * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array. + * + * @example + * + * var x32WordArray = x64WordArray.toX32(); + */ + toX32: function () { + // Shortcuts + var x64Words = this.words; + var x64WordsLength = x64Words.length; + + // Convert + var x32Words = []; + for (var i = 0; i < x64WordsLength; i++) { + var x64Word = x64Words[i]; + x32Words.push(x64Word.high); + x32Words.push(x64Word.low); + } + + return X32WordArray.create(x32Words, this.sigBytes); + }, + + /** + * Creates a copy of this word array. + * + * @return {X64WordArray} The clone. + * + * @example + * + * var clone = x64WordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + + // Clone "words" array + var words = clone.words = this.words.slice(0); + + // Clone each X64Word object + var wordsLength = words.length; + for (var i = 0; i < wordsLength; i++) { + words[i] = words[i].clone(); + } + + return clone; + } + }); + }()); + /* + CryptoJS v3.1.2 + code.google.com/p/crypto-js + (c) 2009-2013 by Jeff Mott. All rights reserved. + code.google.com/p/crypto-js/wiki/License + */ + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + + function X64Word_create() { + return X64Word.create.apply(X64Word, arguments); + } + + // Constants + var K = [ + X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd), + X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc), + X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019), + X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118), + X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe), + X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2), + X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1), + X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694), + X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3), + X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65), + X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483), + X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5), + X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210), + X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4), + X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725), + X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70), + X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926), + X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df), + X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8), + X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b), + X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001), + X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30), + X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910), + X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8), + X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53), + X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8), + X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb), + X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3), + X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60), + X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec), + X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9), + X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b), + X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207), + X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178), + X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6), + X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b), + X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493), + X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c), + X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a), + X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817) + ]; + + // Reusable objects + var W = []; + (function () { + for (var i = 0; i < 80; i++) { + W[i] = X64Word_create(); + } + }()); + + /** + * SHA-512 hash algorithm. + */ + var SHA512 = C_algo.SHA512 = Hasher.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b), + new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1), + new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f), + new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179) + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var H = this._hash.words; + + var H0 = H[0]; + var H1 = H[1]; + var H2 = H[2]; + var H3 = H[3]; + var H4 = H[4]; + var H5 = H[5]; + var H6 = H[6]; + var H7 = H[7]; + + var H0h = H0.high; + var H0l = H0.low; + var H1h = H1.high; + var H1l = H1.low; + var H2h = H2.high; + var H2l = H2.low; + var H3h = H3.high; + var H3l = H3.low; + var H4h = H4.high; + var H4l = H4.low; + var H5h = H5.high; + var H5l = H5.low; + var H6h = H6.high; + var H6l = H6.low; + var H7h = H7.high; + var H7l = H7.low; + + // Working variables + var ah = H0h; + var al = H0l; + var bh = H1h; + var bl = H1l; + var ch = H2h; + var cl = H2l; + var dh = H3h; + var dl = H3l; + var eh = H4h; + var el = H4l; + var fh = H5h; + var fl = H5l; + var gh = H6h; + var gl = H6l; + var hh = H7h; + var hl = H7l; + + // Rounds + for (var i = 0; i < 80; i++) { + // Shortcut + var Wi = W[i]; + + // Extend message + if (i < 16) { + var Wih = Wi.high = M[offset + i * 2] | 0; + var Wil = Wi.low = M[offset + i * 2 + 1] | 0; + } else { + // Gamma0 + var gamma0x = W[i - 15]; + var gamma0xh = gamma0x.high; + var gamma0xl = gamma0x.low; + var gamma0h = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7); + var gamma0l = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25)); + + // Gamma1 + var gamma1x = W[i - 2]; + var gamma1xh = gamma1x.high; + var gamma1xl = gamma1x.low; + var gamma1h = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6); + var gamma1l = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26)); + + // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] + var Wi7 = W[i - 7]; + var Wi7h = Wi7.high; + var Wi7l = Wi7.low; + + var Wi16 = W[i - 16]; + var Wi16h = Wi16.high; + var Wi16l = Wi16.low; + + var Wil = gamma0l + Wi7l; + var Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); + var Wil = Wil + gamma1l; + var Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); + var Wil = Wil + Wi16l; + var Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); + + Wi.high = Wih; + Wi.low = Wil; + } + + var chh = (eh & fh) ^ (~eh & gh); + var chl = (el & fl) ^ (~el & gl); + var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch); + var majl = (al & bl) ^ (al & cl) ^ (bl & cl); + + var sigma0h = ((ah >>> 28) | (al << 4)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7)); + var sigma0l = ((al >>> 28) | (ah << 4)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7)); + var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9)); + var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9)); + + // t1 = h + sigma1 + ch + K[i] + W[i] + var Ki = K[i]; + var Kih = Ki.high; + var Kil = Ki.low; + + var t1l = hl + sigma1l; + var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0); + var t1l = t1l + chl; + var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0); + var t1l = t1l + Kil; + var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0); + var t1l = t1l + Wil; + var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0); + + // t2 = sigma0 + maj + var t2l = sigma0l + majl; + var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0); + + // Update working variables + hh = gh; + hl = gl; + gh = fh; + gl = fl; + fh = eh; + fl = el; + el = (dl + t1l) | 0; + eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; + dh = ch; + dl = cl; + ch = bh; + cl = bl; + bh = ah; + bl = al; + al = (t1l + t2l) | 0; + ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0; + } + + // Intermediate hash value + H0l = H0.low = (H0l + al); + H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0)); + H1l = H1.low = (H1l + bl); + H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0)); + H2l = H2.low = (H2l + cl); + H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0)); + H3l = H3.low = (H3l + dl); + H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0)); + H4l = H4.low = (H4l + el); + H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0)); + H5l = H5.low = (H5l + fl); + H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0)); + H6l = H6.low = (H6l + gl); + H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0)); + H7l = H7.low = (H7l + hl); + H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0)); + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Convert hash to 32-bit word array before returning + var hash = this._hash.toX32(); + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + }, + + blockSize: 1024 / 32 + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA512('message'); + * var hash = CryptoJS.SHA512(wordArray); + */ + C.SHA512 = Hasher._createHelper(SHA512); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA512(message, key); + */ + C.HmacSHA512 = Hasher._createHmacHelper(SHA512); + }()); + + + /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ + var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var b64pad = "="; + + function hex2b64(h) { + var i; + var c; + var ret = ""; + for (i = 0; i + 3 <= h.length; i += 3) { + c = parseInt(h.substring(i, i + 3), 16); + ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63); + } + if (i + 1 == h.length) { + c = parseInt(h.substring(i, i + 1), 16); + ret += b64map.charAt(c << 2); + } + else if (i + 2 == h.length) { + c = parseInt(h.substring(i, i + 2), 16); + ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4); + } + if (b64pad) while ((ret.length & 3) > 0) ret += b64pad; + return ret; + } + + // convert a base64 string to hex + function b64tohex(s) { + var ret = "" + var i; + var k = 0; // b64 state, 0-3 + var slop; + var v; + for (i = 0; i < s.length; ++i) { + if (s.charAt(i) == b64pad) break; + v = b64map.indexOf(s.charAt(i)); + if (v < 0) continue; + if (k == 0) { + ret += int2char(v >> 2); + slop = v & 3; + k = 1; + } + else if (k == 1) { + ret += int2char((slop << 2) | (v >> 4)); + slop = v & 0xf; + k = 2; + } + else if (k == 2) { + ret += int2char(slop); + ret += int2char(v >> 2); + slop = v & 3; + k = 3; + } + else { + ret += int2char((slop << 2) | (v >> 4)); + ret += int2char(v & 0xf); + k = 0; + } + } + if (k == 1) + ret += int2char(slop << 2); + return ret; + } + + // convert a base64 string to a byte/number array + function b64toBA(s) { + //piggyback on b64tohex for now, optimize later + var h = b64tohex(s); + var i; + var a = new Array(); + for (i = 0; 2 * i < h.length; ++i) { + a[i] = parseInt(h.substring(2 * i, 2 * i + 2), 16); + } + return a; + } + /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ + // Copyright (c) 2005 Tom Wu + // All Rights Reserved. + // See "LICENSE" for details. + + // Basic JavaScript BN library - subset useful for RSA encryption. + + // Bits per digit + var dbits; + + // JavaScript engine analysis + var canary = 0xdeadbeefcafe; + var j_lm = ((canary & 0xffffff) == 0xefcafe); + + // (public) Constructor + function BigInteger(a, b, c) { + if (a != null) + if ("number" == typeof a) this.fromNumber(a, b, c); + else if (b == null && "string" != typeof a) this.fromString(a, 256); + else this.fromString(a, b); + } + + // return new, unset BigInteger + function nbi() { return new BigInteger(null); } + + // am: Compute w_j += (x*this_i), propagate carries, + // c is initial carry, returns final carry. + // c < 3*dvalue, x < 2*dvalue, this_i < dvalue + // We need to select the fastest one that works in this environment. + + // am1: use a single mult and divide to get the high bits, + // max digit bits should be 26 because + // max internal value = 2*dvalue^2-2*dvalue (< 2^53) + function am1(i, x, w, j, c, n) { + while (--n >= 0) { + var v = x * this[i++] + w[j] + c; + c = Math.floor(v / 0x4000000); + w[j++] = v & 0x3ffffff; + } + return c; + } + // am2 avoids a big mult-and-extract completely. + // Max digit bits should be <= 30 because we do bitwise ops + // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) + function am2(i, x, w, j, c, n) { + var xl = x & 0x7fff, xh = x >> 15; + while (--n >= 0) { + var l = this[i] & 0x7fff; + var h = this[i++] >> 15; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff); + c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30); + w[j++] = l & 0x3fffffff; + } + return c; + } + // Alternately, set max digit bits to 28 since some + // browsers slow down when dealing with 32-bit numbers. + function am3(i, x, w, j, c, n) { + var xl = x & 0x3fff, xh = x >> 14; + while (--n >= 0) { + var l = this[i] & 0x3fff; + var h = this[i++] >> 14; + var m = xh * l + h * xl; + l = xl * l + ((m & 0x3fff) << 14) + w[j] + c; + c = (l >> 28) + (m >> 14) + xh * h; + w[j++] = l & 0xfffffff; + } + return c; + } + if (j_lm && (navigator.appName == "Microsoft Internet Explorer")) { + BigInteger.prototype.am = am2; + dbits = 30; + } + else if (j_lm && (navigator.appName != "Netscape")) { + BigInteger.prototype.am = am1; + dbits = 26; + } + else { // Mozilla/Netscape seems to prefer am3 + BigInteger.prototype.am = am3; + dbits = 28; + } + + BigInteger.prototype.DB = dbits; + BigInteger.prototype.DM = ((1 << dbits) - 1); + BigInteger.prototype.DV = (1 << dbits); + + var BI_FP = 52; + BigInteger.prototype.FV = Math.pow(2, BI_FP); + BigInteger.prototype.F1 = BI_FP - dbits; + BigInteger.prototype.F2 = 2 * dbits - BI_FP; + + // Digit conversions + var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"; + var BI_RC = new Array(); + var rr, vv; + rr = "0".charCodeAt(0); + for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv; + rr = "a".charCodeAt(0); + for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; + rr = "A".charCodeAt(0); + for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv; + + function int2char(n) { return BI_RM.charAt(n); } + function intAt(s, i) { + var c = BI_RC[s.charCodeAt(i)]; + return (c == null) ? -1 : c; + } + + // (protected) copy this to r + function bnpCopyTo(r) { + for (var i = this.t - 1; i >= 0; --i) r[i] = this[i]; + r.t = this.t; + r.s = this.s; + } + + // (protected) set from integer value x, -DV <= x < DV + function bnpFromInt(x) { + this.t = 1; + this.s = (x < 0) ? -1 : 0; + if (x > 0) this[0] = x; + else if (x < -1) this[0] = x + this.DV; + else this.t = 0; + } + + // return bigint initialized to value + function nbv(i) { var r = nbi(); r.fromInt(i); return r; } + + // (protected) set from string and radix + function bnpFromString(s, b) { + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 256) k = 8; // byte array + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else { this.fromRadix(s, b); return; } + this.t = 0; + this.s = 0; + var i = s.length, mi = false, sh = 0; + while (--i >= 0) { + var x = (k == 8) ? s[i] & 0xff : intAt(s, i); + if (x < 0) { + if (s.charAt(i) == "-") mi = true; + continue; + } + mi = false; + if (sh == 0) + this[this.t++] = x; + else if (sh + k > this.DB) { + this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh; + this[this.t++] = (x >> (this.DB - sh)); + } + else + this[this.t - 1] |= x << sh; + sh += k; + if (sh >= this.DB) sh -= this.DB; + } + if (k == 8 && (s[0] & 0x80) != 0) { + this.s = -1; + if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh; + } + this.clamp(); + if (mi) BigInteger.ZERO.subTo(this, this); + } + + // (protected) clamp off excess high words + function bnpClamp() { + var c = this.s & this.DM; + while (this.t > 0 && this[this.t - 1] == c)--this.t; + } + + // (public) return string representation in given radix + function bnToString(b) { + if (this.s < 0) return "-" + this.negate().toString(b); + var k; + if (b == 16) k = 4; + else if (b == 8) k = 3; + else if (b == 2) k = 1; + else if (b == 32) k = 5; + else if (b == 4) k = 2; + else return this.toRadix(b); + var km = (1 << k) - 1, d, m = false, r = "", i = this.t; + var p = this.DB - (i * this.DB) % k; + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) > 0) { m = true; r = int2char(d); } + while (i >= 0) { + if (p < k) { + d = (this[i] & ((1 << p) - 1)) << (k - p); + d |= this[--i] >> (p += this.DB - k); + } + else { + d = (this[i] >> (p -= k)) & km; + if (p <= 0) { p += this.DB; --i; } + } + if (d > 0) m = true; + if (m) r += int2char(d); + } + } + return m ? r : "0"; + } + + // (public) -this + function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this, r); return r; } + + // (public) |this| + function bnAbs() { return (this.s < 0) ? this.negate() : this; } + + // (public) return + if this > a, - if this < a, 0 if equal + function bnCompareTo(a) { + var r = this.s - a.s; + if (r != 0) return r; + var i = this.t; + r = i - a.t; + if (r != 0) return (this.s < 0) ? -r : r; + while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r; + return 0; + } + + // returns bit length of the integer x + function nbits(x) { + var r = 1, t; + if ((t = x >>> 16) != 0) { x = t; r += 16; } + if ((t = x >> 8) != 0) { x = t; r += 8; } + if ((t = x >> 4) != 0) { x = t; r += 4; } + if ((t = x >> 2) != 0) { x = t; r += 2; } + if ((t = x >> 1) != 0) { x = t; r += 1; } + return r; + } + + // (public) return the number of bits in "this" + function bnBitLength() { + if (this.t <= 0) return 0; + return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM)); + } + + // (protected) r = this << n*DB + function bnpDLShiftTo(n, r) { + var i; + for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i]; + for (i = n - 1; i >= 0; --i) r[i] = 0; + r.t = this.t + n; + r.s = this.s; + } + + // (protected) r = this >> n*DB + function bnpDRShiftTo(n, r) { + for (var i = n; i < this.t; ++i) r[i - n] = this[i]; + r.t = Math.max(this.t - n, 0); + r.s = this.s; + } + + // (protected) r = this << n + function bnpLShiftTo(n, r) { + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << cbs) - 1; + var ds = Math.floor(n / this.DB), c = (this.s << bs) & this.DM, i; + for (i = this.t - 1; i >= 0; --i) { + r[i + ds + 1] = (this[i] >> cbs) | c; + c = (this[i] & bm) << bs; + } + for (i = ds - 1; i >= 0; --i) r[i] = 0; + r[ds] = c; + r.t = this.t + ds + 1; + r.s = this.s; + r.clamp(); + } + + // (protected) r = this >> n + function bnpRShiftTo(n, r) { + r.s = this.s; + var ds = Math.floor(n / this.DB); + if (ds >= this.t) { r.t = 0; return; } + var bs = n % this.DB; + var cbs = this.DB - bs; + var bm = (1 << bs) - 1; + r[0] = this[ds] >> bs; + for (var i = ds + 1; i < this.t; ++i) { + r[i - ds - 1] |= (this[i] & bm) << cbs; + r[i - ds] = this[i] >> bs; + } + if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs; + r.t = this.t - ds; + r.clamp(); + } + + // (protected) r = this - a + function bnpSubTo(a, r) { + var i = 0, c = 0, m = Math.min(a.t, this.t); + while (i < m) { + c += this[i] - a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + if (a.t < this.t) { + c -= a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while (i < a.t) { + c -= a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c -= a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c < -1) r[i++] = this.DV + c; + else if (c > 0) r[i++] = c; + r.t = i; + r.clamp(); + } + + // (protected) r = this * a, r != this,a (HAC 14.12) + // "this" should be the larger one if appropriate. + function bnpMultiplyTo(a, r) { + var x = this.abs(), y = a.abs(); + var i = x.t; + r.t = i + y.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t); + r.s = 0; + r.clamp(); + if (this.s != a.s) BigInteger.ZERO.subTo(r, r); + } + + // (protected) r = this^2, r != this (HAC 14.16) + function bnpSquareTo(r) { + var x = this.abs(); + var i = r.t = 2 * x.t; + while (--i >= 0) r[i] = 0; + for (i = 0; i < x.t - 1; ++i) { + var c = x.am(i, x[i], r, 2 * i, 0, 1); + if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) { + r[i + x.t] -= x.DV; + r[i + x.t + 1] = 1; + } + } + if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1); + r.s = 0; + r.clamp(); + } + + // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) + // r != q, this != m. q or r may be null. + function bnpDivRemTo(m, q, r) { + var pm = m.abs(); + if (pm.t <= 0) return; + var pt = this.abs(); + if (pt.t < pm.t) { + if (q != null) q.fromInt(0); + if (r != null) this.copyTo(r); + return; + } + if (r == null) r = nbi(); + var y = nbi(), ts = this.s, ms = m.s; + var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus + if (nsh > 0) { pm.lShiftTo(nsh, y); pt.lShiftTo(nsh, r); } + else { pm.copyTo(y); pt.copyTo(r); } + var ys = y.t; + var y0 = y[ys - 1]; + if (y0 == 0) return; + var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0); + var d1 = this.FV / yt, d2 = (1 << this.F1) / yt, e = 1 << this.F2; + var i = r.t, j = i - ys, t = (q == null) ? nbi() : q; + y.dlShiftTo(j, t); + if (r.compareTo(t) >= 0) { + r[r.t++] = 1; + r.subTo(t, r); + } + BigInteger.ONE.dlShiftTo(ys, t); + t.subTo(y, y); // "negative" y so we can replace sub with am later + while (y.t < ys) y[y.t++] = 0; + while (--j >= 0) { + // Estimate quotient digit + var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2); + if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out + y.dlShiftTo(j, t); + r.subTo(t, r); + while (r[i] < --qd) r.subTo(t, r); + } + } + if (q != null) { + r.drShiftTo(ys, q); + if (ts != ms) BigInteger.ZERO.subTo(q, q); + } + r.t = ys; + r.clamp(); + if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder + if (ts < 0) BigInteger.ZERO.subTo(r, r); + } + + // (public) this mod a + function bnMod(a) { + var r = nbi(); + this.abs().divRemTo(a, null, r); + if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r); + return r; + } + + // Modular reduction using "classic" algorithm + function Classic(m) { this.m = m; } + function cConvert(x) { + if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); + else return x; + } + function cRevert(x) { return x; } + function cReduce(x) { x.divRemTo(this.m, null, x); } + function cMulTo(x, y, r) { x.multiplyTo(y, r); this.reduce(r); } + function cSqrTo(x, r) { x.squareTo(r); this.reduce(r); } + + Classic.prototype.convert = cConvert; + Classic.prototype.revert = cRevert; + Classic.prototype.reduce = cReduce; + Classic.prototype.mulTo = cMulTo; + Classic.prototype.sqrTo = cSqrTo; + + // (protected) return "-1/this % 2^DB"; useful for Mont. reduction + // justification: + // xy == 1 (mod m) + // xy = 1+km + // xy(2-xy) = (1+km)(1-km) + // x[y(2-xy)] = 1-k^2m^2 + // x[y(2-xy)] == 1 (mod m^2) + // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 + // should reduce x and y(2-xy) by m^2 at each step to keep size bounded. + // JS multiply "overflows" differently from C/C++, so care is needed here. + function bnpInvDigit() { + if (this.t < 1) return 0; + var x = this[0]; + if ((x & 1) == 0) return 0; + var y = x & 3; // y == 1/x mod 2^2 + y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4 + y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8 + y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16 + // last step - calculate inverse mod DV directly; + // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints + y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits + // we really want the negative inverse, and -DV < y < DV + return (y > 0) ? this.DV - y : -y; + } + + // Montgomery reduction + function Montgomery(m) { + this.m = m; + this.mp = m.invDigit(); + this.mpl = this.mp & 0x7fff; + this.mph = this.mp >> 15; + this.um = (1 << (m.DB - 15)) - 1; + this.mt2 = 2 * m.t; + } + + // xR mod m + function montConvert(x) { + var r = nbi(); + x.abs().dlShiftTo(this.m.t, r); + r.divRemTo(this.m, null, r); + if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r); + return r; + } + + // x/R mod m + function montRevert(x) { + var r = nbi(); + x.copyTo(r); + this.reduce(r); + return r; + } + + // x = x/R mod m (HAC 14.32) + function montReduce(x) { + while (x.t <= this.mt2) // pad x so am has enough room later + x[x.t++] = 0; + for (var i = 0; i < this.m.t; ++i) { + // faster way of calculating u0 = x[i]*mp mod DV + var j = x[i] & 0x7fff; + var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM; + // use am to combine the multiply-shift-add into one call + j = i + this.m.t; + x[j] += this.m.am(0, u0, x, i, 0, this.m.t); + // propagate carry + while (x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } + } + x.clamp(); + x.drShiftTo(this.m.t, x); + if (x.compareTo(this.m) >= 0) x.subTo(this.m, x); + } + + // r = "x^2/R mod m"; x != r + function montSqrTo(x, r) { x.squareTo(r); this.reduce(r); } + + // r = "xy/R mod m"; x,y != r + function montMulTo(x, y, r) { x.multiplyTo(y, r); this.reduce(r); } + + Montgomery.prototype.convert = montConvert; + Montgomery.prototype.revert = montRevert; + Montgomery.prototype.reduce = montReduce; + Montgomery.prototype.mulTo = montMulTo; + Montgomery.prototype.sqrTo = montSqrTo; + + // (protected) true iff this is even + function bnpIsEven() { return ((this.t > 0) ? (this[0] & 1) : this.s) == 0; } + + // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) + function bnpExp(e, z) { + if (e > 0xffffffff || e < 1) return BigInteger.ONE; + var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e) - 1; + g.copyTo(r); + while (--i >= 0) { + z.sqrTo(r, r2); + if ((e & (1 << i)) > 0) z.mulTo(r2, g, r); + else { var t = r; r = r2; r2 = t; } + } + return z.revert(r); + } + + // (public) this^e % m, 0 <= e < 2^32 + function bnModPowInt(e, m) { + var z; + if (e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); + return this.exp(e, z); + } + + // protected + BigInteger.prototype.copyTo = bnpCopyTo; + BigInteger.prototype.fromInt = bnpFromInt; + BigInteger.prototype.fromString = bnpFromString; + BigInteger.prototype.clamp = bnpClamp; + BigInteger.prototype.dlShiftTo = bnpDLShiftTo; + BigInteger.prototype.drShiftTo = bnpDRShiftTo; + BigInteger.prototype.lShiftTo = bnpLShiftTo; + BigInteger.prototype.rShiftTo = bnpRShiftTo; + BigInteger.prototype.subTo = bnpSubTo; + BigInteger.prototype.multiplyTo = bnpMultiplyTo; + BigInteger.prototype.squareTo = bnpSquareTo; + BigInteger.prototype.divRemTo = bnpDivRemTo; + BigInteger.prototype.invDigit = bnpInvDigit; + BigInteger.prototype.isEven = bnpIsEven; + BigInteger.prototype.exp = bnpExp; + + // public + BigInteger.prototype.toString = bnToString; + BigInteger.prototype.negate = bnNegate; + BigInteger.prototype.abs = bnAbs; + BigInteger.prototype.compareTo = bnCompareTo; + BigInteger.prototype.bitLength = bnBitLength; + BigInteger.prototype.mod = bnMod; + BigInteger.prototype.modPowInt = bnModPowInt; + + // "constants" + BigInteger.ZERO = nbv(0); + BigInteger.ONE = nbv(1); + /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ + // Copyright (c) 2005-2009 Tom Wu + // All Rights Reserved. + // See "LICENSE" for details. + + // Extended JavaScript BN functions, required for RSA private ops. + + // Version 1.1: new BigInteger("0", 10) returns "proper" zero + // Version 1.2: square() API, isProbablePrime fix + + // (public) + function bnClone() { var r = nbi(); this.copyTo(r); return r; } + + // (public) return value as integer + function bnIntValue() { + if (this.s < 0) { + if (this.t == 1) return this[0] - this.DV; + else if (this.t == 0) return -1; + } + else if (this.t == 1) return this[0]; + else if (this.t == 0) return 0; + // assumes 16 < DB < 32 + return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0]; + } + + // (public) return value as byte + function bnByteValue() { return (this.t == 0) ? this.s : (this[0] << 24) >> 24; } + + // (public) return value as short (assumes DB>=16) + function bnShortValue() { return (this.t == 0) ? this.s : (this[0] << 16) >> 16; } + + // (protected) return x s.t. r^x < DV + function bnpChunkSize(r) { return Math.floor(Math.LN2 * this.DB / Math.log(r)); } + + // (public) 0 if this == 0, 1 if this > 0 + function bnSigNum() { + if (this.s < 0) return -1; + else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0; + else return 1; + } + + // (protected) convert to radix string + function bnpToRadix(b) { + if (b == null) b = 10; + if (this.signum() == 0 || b < 2 || b > 36) return "0"; + var cs = this.chunkSize(b); + var a = Math.pow(b, cs); + var d = nbv(a), y = nbi(), z = nbi(), r = ""; + this.divRemTo(d, y, z); + while (y.signum() > 0) { + r = (a + z.intValue()).toString(b).substr(1) + r; + y.divRemTo(d, y, z); + } + return z.intValue().toString(b) + r; + } + + // (protected) convert from radix string + function bnpFromRadix(s, b) { + this.fromInt(0); + if (b == null) b = 10; + var cs = this.chunkSize(b); + var d = Math.pow(b, cs), mi = false, j = 0, w = 0; + for (var i = 0; i < s.length; ++i) { + var x = intAt(s, i); + if (x < 0) { + if (s.charAt(i) == "-" && this.signum() == 0) mi = true; + continue; + } + w = b * w + x; + if (++j >= cs) { + this.dMultiply(d); + this.dAddOffset(w, 0); + j = 0; + w = 0; + } + } + if (j > 0) { + this.dMultiply(Math.pow(b, j)); + this.dAddOffset(w, 0); + } + if (mi) BigInteger.ZERO.subTo(this, this); + } + + // (protected) alternate constructor + function bnpFromNumber(a, b, c) { + if ("number" == typeof b) { + // new BigInteger(int,int,RNG) + if (a < 2) this.fromInt(1); + else { + this.fromNumber(a, c); + if (!this.testBit(a - 1)) // force MSB set + this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this); + if (this.isEven()) this.dAddOffset(1, 0); // force odd + while (!this.isProbablePrime(b)) { + this.dAddOffset(2, 0); + if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this); + } + } + } + else { + // new BigInteger(int,RNG) + var x = new Array(), t = a & 7; + x.length = (a >> 3) + 1; + b.nextBytes(x); + if (t > 0) x[0] &= ((1 << t) - 1); else x[0] = 0; + this.fromString(x, 256); + } + } + + // (public) convert to bigendian byte array + function bnToByteArray() { + var i = this.t, r = new Array(); + r[0] = this.s; + var p = this.DB - (i * this.DB) % 8, d, k = 0; + if (i-- > 0) { + if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p) + r[k++] = d | (this.s << (this.DB - p)); + while (i >= 0) { + if (p < 8) { + d = (this[i] & ((1 << p) - 1)) << (8 - p); + d |= this[--i] >> (p += this.DB - 8); + } + else { + d = (this[i] >> (p -= 8)) & 0xff; + if (p <= 0) { p += this.DB; --i; } + } + if ((d & 0x80) != 0) d |= -256; + if (k == 0 && (this.s & 0x80) != (d & 0x80))++k; + if (k > 0 || d != this.s) r[k++] = d; + } + } + return r; + } + + function bnEquals(a) { return (this.compareTo(a) == 0); } + function bnMin(a) { return (this.compareTo(a) < 0) ? this : a; } + function bnMax(a) { return (this.compareTo(a) > 0) ? this : a; } + + // (protected) r = this op a (bitwise) + function bnpBitwiseTo(a, op, r) { + var i, f, m = Math.min(a.t, this.t); + for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]); + if (a.t < this.t) { + f = a.s & this.DM; + for (i = m; i < this.t; ++i) r[i] = op(this[i], f); + r.t = this.t; + } + else { + f = this.s & this.DM; + for (i = m; i < a.t; ++i) r[i] = op(f, a[i]); + r.t = a.t; + } + r.s = op(this.s, a.s); + r.clamp(); + } + + // (public) this & a + function op_and(x, y) { return x & y; } + function bnAnd(a) { var r = nbi(); this.bitwiseTo(a, op_and, r); return r; } + + // (public) this | a + function op_or(x, y) { return x | y; } + function bnOr(a) { var r = nbi(); this.bitwiseTo(a, op_or, r); return r; } + + // (public) this ^ a + function op_xor(x, y) { return x ^ y; } + function bnXor(a) { var r = nbi(); this.bitwiseTo(a, op_xor, r); return r; } + + // (public) this & ~a + function op_andnot(x, y) { return x & ~y; } + function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a, op_andnot, r); return r; } + + // (public) ~this + function bnNot() { + var r = nbi(); + for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i]; + r.t = this.t; + r.s = ~this.s; + return r; + } + + // (public) this << n + function bnShiftLeft(n) { + var r = nbi(); + if (n < 0) this.rShiftTo(-n, r); else this.lShiftTo(n, r); + return r; + } + + // (public) this >> n + function bnShiftRight(n) { + var r = nbi(); + if (n < 0) this.lShiftTo(-n, r); else this.rShiftTo(n, r); + return r; + } + + // return index of lowest 1-bit in x, x < 2^31 + function lbit(x) { + if (x == 0) return -1; + var r = 0; + if ((x & 0xffff) == 0) { x >>= 16; r += 16; } + if ((x & 0xff) == 0) { x >>= 8; r += 8; } + if ((x & 0xf) == 0) { x >>= 4; r += 4; } + if ((x & 3) == 0) { x >>= 2; r += 2; } + if ((x & 1) == 0)++r; + return r; + } + + // (public) returns index of lowest 1-bit (or -1 if none) + function bnGetLowestSetBit() { + for (var i = 0; i < this.t; ++i) + if (this[i] != 0) return i * this.DB + lbit(this[i]); + if (this.s < 0) return this.t * this.DB; + return -1; + } + + // return number of 1 bits in x + function cbit(x) { + var r = 0; + while (x != 0) { x &= x - 1; ++r; } + return r; + } + + // (public) return number of set bits + function bnBitCount() { + var r = 0, x = this.s & this.DM; + for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x); + return r; + } + + // (public) true iff nth bit is set + function bnTestBit(n) { + var j = Math.floor(n / this.DB); + if (j >= this.t) return (this.s != 0); + return ((this[j] & (1 << (n % this.DB))) != 0); + } + + // (protected) this op (1<>= this.DB; + } + if (a.t < this.t) { + c += a.s; + while (i < this.t) { + c += this[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += this.s; + } + else { + c += this.s; + while (i < a.t) { + c += a[i]; + r[i++] = c & this.DM; + c >>= this.DB; + } + c += a.s; + } + r.s = (c < 0) ? -1 : 0; + if (c > 0) r[i++] = c; + else if (c < -1) r[i++] = this.DV + c; + r.t = i; + r.clamp(); + } + + // (public) this + a + function bnAdd(a) { var r = nbi(); this.addTo(a, r); return r; } + + // (public) this - a + function bnSubtract(a) { var r = nbi(); this.subTo(a, r); return r; } + + // (public) this * a + function bnMultiply(a) { var r = nbi(); this.multiplyTo(a, r); return r; } + + // (public) this^2 + function bnSquare() { var r = nbi(); this.squareTo(r); return r; } + + // (public) this / a + function bnDivide(a) { var r = nbi(); this.divRemTo(a, r, null); return r; } + + // (public) this % a + function bnRemainder(a) { var r = nbi(); this.divRemTo(a, null, r); return r; } + + // (public) [this/a,this%a] + function bnDivideAndRemainder(a) { + var q = nbi(), r = nbi(); + this.divRemTo(a, q, r); + return new Array(q, r); + } + + // (protected) this *= n, this >= 0, 1 < n < DV + function bnpDMultiply(n) { + this[this.t] = this.am(0, n - 1, this, 0, 0, this.t); + ++this.t; + this.clamp(); + } + + // (protected) this += n << w words, this >= 0 + function bnpDAddOffset(n, w) { + if (n == 0) return; + while (this.t <= w) this[this.t++] = 0; + this[w] += n; + while (this[w] >= this.DV) { + this[w] -= this.DV; + if (++w >= this.t) this[this.t++] = 0; + ++this[w]; + } + } + + // A "null" reducer + function NullExp() { } + function nNop(x) { return x; } + function nMulTo(x, y, r) { x.multiplyTo(y, r); } + function nSqrTo(x, r) { x.squareTo(r); } + + NullExp.prototype.convert = nNop; + NullExp.prototype.revert = nNop; + NullExp.prototype.mulTo = nMulTo; + NullExp.prototype.sqrTo = nSqrTo; + + // (public) this^e + function bnPow(e) { return this.exp(e, new NullExp()); } + + // (protected) r = lower n words of "this * a", a.t <= n + // "this" should be the larger one if appropriate. + function bnpMultiplyLowerTo(a, n, r) { + var i = Math.min(this.t + a.t, n); + r.s = 0; // assumes a,this >= 0 + r.t = i; + while (i > 0) r[--i] = 0; + var j; + for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t); + for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i); + r.clamp(); + } + + // (protected) r = "this * a" without lower n words, n > 0 + // "this" should be the larger one if appropriate. + function bnpMultiplyUpperTo(a, n, r) { + --n; + var i = r.t = this.t + a.t - n; + r.s = 0; // assumes a,this >= 0 + while (--i >= 0) r[i] = 0; + for (i = Math.max(n - this.t, 0); i < a.t; ++i) + r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n); + r.clamp(); + r.drShiftTo(1, r); + } + + // Barrett modular reduction + function Barrett(m) { + // setup Barrett + this.r2 = nbi(); + this.q3 = nbi(); + BigInteger.ONE.dlShiftTo(2 * m.t, this.r2); + this.mu = this.r2.divide(m); + this.m = m; + } + + function barrettConvert(x) { + if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m); + else if (x.compareTo(this.m) < 0) return x; + else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } + } + + function barrettRevert(x) { return x; } + + // x = x mod m (HAC 14.42) + function barrettReduce(x) { + x.drShiftTo(this.m.t - 1, this.r2); + if (x.t > this.m.t + 1) { x.t = this.m.t + 1; x.clamp(); } + this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3); + this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2); + while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1); + x.subTo(this.r2, x); + while (x.compareTo(this.m) >= 0) x.subTo(this.m, x); + } + + // r = x^2 mod m; x != r + function barrettSqrTo(x, r) { x.squareTo(r); this.reduce(r); } + + // r = x*y mod m; x,y != r + function barrettMulTo(x, y, r) { x.multiplyTo(y, r); this.reduce(r); } + + Barrett.prototype.convert = barrettConvert; + Barrett.prototype.revert = barrettRevert; + Barrett.prototype.reduce = barrettReduce; + Barrett.prototype.mulTo = barrettMulTo; + Barrett.prototype.sqrTo = barrettSqrTo; + + // (public) this^e % m (HAC 14.85) + function bnModPow(e, m) { + var i = e.bitLength(), k, r = nbv(1), z; + if (i <= 0) return r; + else if (i < 18) k = 1; + else if (i < 48) k = 3; + else if (i < 144) k = 4; + else if (i < 768) k = 5; + else k = 6; + if (i < 8) + z = new Classic(m); + else if (m.isEven()) + z = new Barrett(m); + else + z = new Montgomery(m); + + // precomputation + var g = new Array(), n = 3, k1 = k - 1, km = (1 << k) - 1; + g[1] = z.convert(this); + if (k > 1) { + var g2 = nbi(); + z.sqrTo(g[1], g2); + while (n <= km) { + g[n] = nbi(); + z.mulTo(g2, g[n - 2], g[n]); + n += 2; + } + } + + var j = e.t - 1, w, is1 = true, r2 = nbi(), t; + i = nbits(e[j]) - 1; + while (j >= 0) { + if (i >= k1) w = (e[j] >> (i - k1)) & km; + else { + w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i); + if (j > 0) w |= e[j - 1] >> (this.DB + i - k1); + } + + n = k; + while ((w & 1) == 0) { w >>= 1; --n; } + if ((i -= n) < 0) { i += this.DB; --j; } + if (is1) { // ret == 1, don't bother squaring or multiplying it + g[w].copyTo(r); + is1 = false; + } + else { + while (n > 1) { z.sqrTo(r, r2); z.sqrTo(r2, r); n -= 2; } + if (n > 0) z.sqrTo(r, r2); else { t = r; r = r2; r2 = t; } + z.mulTo(r2, g[w], r); + } + + while (j >= 0 && (e[j] & (1 << i)) == 0) { + z.sqrTo(r, r2); t = r; r = r2; r2 = t; + if (--i < 0) { i = this.DB - 1; --j; } + } + } + return z.revert(r); + } + + // (public) gcd(this,a) (HAC 14.54) + function bnGCD(a) { + var x = (this.s < 0) ? this.negate() : this.clone(); + var y = (a.s < 0) ? a.negate() : a.clone(); + if (x.compareTo(y) < 0) { var t = x; x = y; y = t; } + var i = x.getLowestSetBit(), g = y.getLowestSetBit(); + if (g < 0) return x; + if (i < g) g = i; + if (g > 0) { + x.rShiftTo(g, x); + y.rShiftTo(g, y); + } + while (x.signum() > 0) { + if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x); + if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y); + if (x.compareTo(y) >= 0) { + x.subTo(y, x); + x.rShiftTo(1, x); + } + else { + y.subTo(x, y); + y.rShiftTo(1, y); + } + } + if (g > 0) y.lShiftTo(g, y); + return y; + } + + // (protected) this % n, n < 2^26 + function bnpModInt(n) { + if (n <= 0) return 0; + var d = this.DV % n, r = (this.s < 0) ? n - 1 : 0; + if (this.t > 0) + if (d == 0) r = this[0] % n; + else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n; + return r; + } + + // (public) 1/this % m (HAC 14.61) + function bnModInverse(m) { + var ac = m.isEven(); + if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO; + var u = m.clone(), v = this.clone(); + var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1); + while (u.signum() != 0) { + while (u.isEven()) { + u.rShiftTo(1, u); + if (ac) { + if (!a.isEven() || !b.isEven()) { a.addTo(this, a); b.subTo(m, b); } + a.rShiftTo(1, a); + } + else if (!b.isEven()) b.subTo(m, b); + b.rShiftTo(1, b); + } + while (v.isEven()) { + v.rShiftTo(1, v); + if (ac) { + if (!c.isEven() || !d.isEven()) { c.addTo(this, c); d.subTo(m, d); } + c.rShiftTo(1, c); + } + else if (!d.isEven()) d.subTo(m, d); + d.rShiftTo(1, d); + } + if (u.compareTo(v) >= 0) { + u.subTo(v, u); + if (ac) a.subTo(c, a); + b.subTo(d, b); + } + else { + v.subTo(u, v); + if (ac) c.subTo(a, c); + d.subTo(b, d); + } + } + if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO; + if (d.compareTo(m) >= 0) return d.subtract(m); + if (d.signum() < 0) d.addTo(m, d); else return d; + if (d.signum() < 0) return d.add(m); else return d; + } + + var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]; + var lplim = (1 << 26) / lowprimes[lowprimes.length - 1]; + + // (public) test primality with certainty >= 1-.5^t + function bnIsProbablePrime(t) { + var i, x = this.abs(); + if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) { + for (i = 0; i < lowprimes.length; ++i) + if (x[0] == lowprimes[i]) return true; + return false; + } + if (x.isEven()) return false; + i = 1; + while (i < lowprimes.length) { + var m = lowprimes[i], j = i + 1; + while (j < lowprimes.length && m < lplim) m *= lowprimes[j++]; + m = x.modInt(m); + while (i < j) if (m % lowprimes[i++] == 0) return false; + } + return x.millerRabin(t); + } + + // (protected) true if probably prime (HAC 4.24, Miller-Rabin) + function bnpMillerRabin(t) { + var n1 = this.subtract(BigInteger.ONE); + var k = n1.getLowestSetBit(); + if (k <= 0) return false; + var r = n1.shiftRight(k); + t = (t + 1) >> 1; + if (t > lowprimes.length) t = lowprimes.length; + var a = nbi(); + for (var i = 0; i < t; ++i) { + //Pick bases at random, instead of starting at 2 + a.fromInt(lowprimes[Math.floor(Math.random() * lowprimes.length)]); + var y = a.modPow(r, this); + if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) { + var j = 1; + while (j++ < k && y.compareTo(n1) != 0) { + y = y.modPowInt(2, this); + if (y.compareTo(BigInteger.ONE) == 0) return false; + } + if (y.compareTo(n1) != 0) return false; + } + } + return true; + } + + // protected + BigInteger.prototype.chunkSize = bnpChunkSize; + BigInteger.prototype.toRadix = bnpToRadix; + BigInteger.prototype.fromRadix = bnpFromRadix; + BigInteger.prototype.fromNumber = bnpFromNumber; + BigInteger.prototype.bitwiseTo = bnpBitwiseTo; + BigInteger.prototype.changeBit = bnpChangeBit; + BigInteger.prototype.addTo = bnpAddTo; + BigInteger.prototype.dMultiply = bnpDMultiply; + BigInteger.prototype.dAddOffset = bnpDAddOffset; + BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo; + BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo; + BigInteger.prototype.modInt = bnpModInt; + BigInteger.prototype.millerRabin = bnpMillerRabin; + + // public + BigInteger.prototype.clone = bnClone; + BigInteger.prototype.intValue = bnIntValue; + BigInteger.prototype.byteValue = bnByteValue; + BigInteger.prototype.shortValue = bnShortValue; + BigInteger.prototype.signum = bnSigNum; + BigInteger.prototype.toByteArray = bnToByteArray; + BigInteger.prototype.equals = bnEquals; + BigInteger.prototype.min = bnMin; + BigInteger.prototype.max = bnMax; + BigInteger.prototype.and = bnAnd; + BigInteger.prototype.or = bnOr; + BigInteger.prototype.xor = bnXor; + BigInteger.prototype.andNot = bnAndNot; + BigInteger.prototype.not = bnNot; + BigInteger.prototype.shiftLeft = bnShiftLeft; + BigInteger.prototype.shiftRight = bnShiftRight; + BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit; + BigInteger.prototype.bitCount = bnBitCount; + BigInteger.prototype.testBit = bnTestBit; + BigInteger.prototype.setBit = bnSetBit; + BigInteger.prototype.clearBit = bnClearBit; + BigInteger.prototype.flipBit = bnFlipBit; + BigInteger.prototype.add = bnAdd; + BigInteger.prototype.subtract = bnSubtract; + BigInteger.prototype.multiply = bnMultiply; + BigInteger.prototype.divide = bnDivide; + BigInteger.prototype.remainder = bnRemainder; + BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder; + BigInteger.prototype.modPow = bnModPow; + BigInteger.prototype.modInverse = bnModInverse; + BigInteger.prototype.pow = bnPow; + BigInteger.prototype.gcd = bnGCD; + BigInteger.prototype.isProbablePrime = bnIsProbablePrime; + + // JSBN-specific extension + BigInteger.prototype.square = bnSquare; + + // BigInteger interfaces not implemented in jsbn: + + // BigInteger(int signum, byte[] magnitude) + // double doubleValue() + // float floatValue() + // int hashCode() + // long longValue() + // static BigInteger valueOf(long val) + /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ + // Depends on jsbn.js and rng.js + + // Version 1.1: support utf-8 encoding in pkcs1pad2 + + // convert a (hex) string to a bignum object + function parseBigInt(str, r) { + return new BigInteger(str, r); + } + + function linebrk(s, n) { + var ret = ""; + var i = 0; + while (i + n < s.length) { + ret += s.substring(i, i + n) + "\n"; + i += n; + } + return ret + s.substring(i, s.length); + } + + function byte2Hex(b) { + if (b < 0x10) + return "0" + b.toString(16); + else + return b.toString(16); + } + + // PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint + function pkcs1pad2(s, n) { + if (n < s.length + 11) { // TODO: fix for utf-8 + alert("Message too long for RSA"); + return null; + } + var ba = new Array(); + var i = s.length - 1; + while (i >= 0 && n > 0) { + var c = s.charCodeAt(i--); + if (c < 128) { // encode using utf-8 + ba[--n] = c; + } + else if ((c > 127) && (c < 2048)) { + ba[--n] = (c & 63) | 128; + ba[--n] = (c >> 6) | 192; + } + else { + ba[--n] = (c & 63) | 128; + ba[--n] = ((c >> 6) & 63) | 128; + ba[--n] = (c >> 12) | 224; + } + } + ba[--n] = 0; + var rng = new SecureRandom(); + var x = new Array(); + while (n > 2) { // random non-zero pad + x[0] = 0; + while (x[0] == 0) rng.nextBytes(x); + ba[--n] = x[0]; + } + ba[--n] = 2; + ba[--n] = 0; + return new BigInteger(ba); + } + + // PKCS#1 (OAEP) mask generation function + function oaep_mgf1_arr(seed, len, hash) { + var mask = '', i = 0; + + while (mask.length < len) { + mask += hash(String.fromCharCode.apply(String, seed.concat([ + (i & 0xff000000) >> 24, + (i & 0x00ff0000) >> 16, + (i & 0x0000ff00) >> 8, + i & 0x000000ff]))); + i += 1; + } + + return mask; + } + + var SHA1_SIZE = 20; + + // PKCS#1 (OAEP) pad input string s to n bytes, and return a bigint + function oaep_pad(s, n, hash) { + if (s.length + 2 * SHA1_SIZE + 2 > n) { + throw "Message too long for RSA"; + } + + var PS = '', i; + + for (i = 0; i < n - s.length - 2 * SHA1_SIZE - 2; i += 1) { + PS += '\x00'; + } + + var DB = rstr_sha1('') + PS + '\x01' + s; + var seed = new Array(SHA1_SIZE); + new SecureRandom().nextBytes(seed); + + var dbMask = oaep_mgf1_arr(seed, DB.length, hash || rstr_sha1); + var maskedDB = []; + + for (i = 0; i < DB.length; i += 1) { + maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i); + } + + var seedMask = oaep_mgf1_arr(maskedDB, seed.length, rstr_sha1); + var maskedSeed = [0]; + + for (i = 0; i < seed.length; i += 1) { + maskedSeed[i + 1] = seed[i] ^ seedMask.charCodeAt(i); + } + + return new BigInteger(maskedSeed.concat(maskedDB)); + } + + // "empty" RSA key constructor + function RSAKey() { + this.n = null; + this.e = 0; + this.d = null; + this.p = null; + this.q = null; + this.dmp1 = null; + this.dmq1 = null; + this.coeff = null; + } + + // Set the public key fields N and e from hex strings + function RSASetPublic(N, E) { + this.isPublic = true; + if (typeof N !== "string") { + this.n = N; + this.e = E; + } + else if (N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N, 16); + this.e = parseInt(E, 16); + } + else + alert("Invalid RSA public key"); + } + + // Perform raw public operation on "x": return x^e (mod n) + function RSADoPublic(x) { + return x.modPowInt(this.e, this.n); + } + + // Return the PKCS#1 RSA encryption of "text" as an even-length hex string + function RSAEncrypt(text) { + var m = pkcs1pad2(text, (this.n.bitLength() + 7) >> 3); + if (m == null) return null; + var c = this.doPublic(m); + if (c == null) return null; + var h = c.toString(16); + if ((h.length & 1) == 0) return h; else return "0" + h; + } + + // Return the PKCS#1 OAEP RSA encryption of "text" as an even-length hex string + function RSAEncryptOAEP(text, hash) { + var m = oaep_pad(text, (this.n.bitLength() + 7) >> 3, hash); + if (m == null) return null; + var c = this.doPublic(m); + if (c == null) return null; + var h = c.toString(16); + if ((h.length & 1) == 0) return h; else return "0" + h; + } + + // Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string + //function RSAEncryptB64(text) { + // var h = this.encrypt(text); + // if(h) return hex2b64(h); else return null; + //} + + // protected + RSAKey.prototype.doPublic = RSADoPublic; + + // public + RSAKey.prototype.setPublic = RSASetPublic; + RSAKey.prototype.encrypt = RSAEncrypt; + RSAKey.prototype.encryptOAEP = RSAEncryptOAEP; + //RSAKey.prototype.encrypt_b64 = RSAEncryptB64; + + RSAKey.prototype.type = "RSA"; + /*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ + */ + // Depends on rsa.js and jsbn2.js + + // Version 1.1: support utf-8 decoding in pkcs1unpad2 + + // Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext + function pkcs1unpad2(d, n) { + var b = d.toByteArray(); + var i = 0; + while (i < b.length && b[i] == 0)++i; + if (b.length - i != n - 1 || b[i] != 2) + return null; + ++i; + while (b[i] != 0) + if (++i >= b.length) return null; + var ret = ""; + while (++i < b.length) { + var c = b[i] & 255; + if (c < 128) { // utf-8 decode + ret += String.fromCharCode(c); + } + else if ((c > 191) && (c < 224)) { + ret += String.fromCharCode(((c & 31) << 6) | (b[i + 1] & 63)); + ++i; + } + else { + ret += String.fromCharCode(((c & 15) << 12) | ((b[i + 1] & 63) << 6) | (b[i + 2] & 63)); + i += 2; + } + } + return ret; + } + + // PKCS#1 (OAEP) mask generation function + function oaep_mgf1_str(seed, len, hash) { + var mask = '', i = 0; + + while (mask.length < len) { + mask += hash(seed + String.fromCharCode.apply(String, [ + (i & 0xff000000) >> 24, + (i & 0x00ff0000) >> 16, + (i & 0x0000ff00) >> 8, + i & 0x000000ff])); + i += 1; + } + + return mask; + } + + var SHA1_SIZE = 20; + + // Undo PKCS#1 (OAEP) padding and, if valid, return the plaintext + function oaep_unpad(d, n, hash) { + d = d.toByteArray(); + + var i; + + for (i = 0; i < d.length; i += 1) { + d[i] &= 0xff; + } + + while (d.length < n) { + d.unshift(0); + } + + d = String.fromCharCode.apply(String, d); + + if (d.length < 2 * SHA1_SIZE + 2) { + throw "Cipher too short"; + } + + var maskedSeed = d.substr(1, SHA1_SIZE) + var maskedDB = d.substr(SHA1_SIZE + 1); + + var seedMask = oaep_mgf1_str(maskedDB, SHA1_SIZE, hash || rstr_sha1); + var seed = [], i; + + for (i = 0; i < maskedSeed.length; i += 1) { + seed[i] = maskedSeed.charCodeAt(i) ^ seedMask.charCodeAt(i); + } + + var dbMask = oaep_mgf1_str(String.fromCharCode.apply(String, seed), + d.length - SHA1_SIZE, rstr_sha1); + + var DB = []; + + for (i = 0; i < maskedDB.length; i += 1) { + DB[i] = maskedDB.charCodeAt(i) ^ dbMask.charCodeAt(i); + } + + DB = String.fromCharCode.apply(String, DB); + + if (DB.substr(0, SHA1_SIZE) !== rstr_sha1('')) { + throw "Hash mismatch"; + } + + DB = DB.substr(SHA1_SIZE); + + var first_one = DB.indexOf('\x01'); + var last_zero = (first_one != -1) ? DB.substr(0, first_one).lastIndexOf('\x00') : -1; + + if (last_zero + 1 != first_one) { + throw "Malformed data"; + } + + return DB.substr(first_one + 1); + } + + // Set the private key fields N, e, and d from hex strings + function RSASetPrivate(N, E, D) { + this.isPrivate = true; + if (typeof N !== "string") { + this.n = N; + this.e = E; + this.d = D; + } + else if (N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N, 16); + this.e = parseInt(E, 16); + this.d = parseBigInt(D, 16); + } + else + alert("Invalid RSA private key"); + } + + // Set the private key fields N, e, d and CRT params from hex strings + function RSASetPrivateEx(N, E, D, P, Q, DP, DQ, C) { + this.isPrivate = true; + if (N == null) throw "RSASetPrivateEx N == null"; + if (E == null) throw "RSASetPrivateEx E == null"; + if (N.length == 0) throw "RSASetPrivateEx N.length == 0"; + if (E.length == 0) throw "RSASetPrivateEx E.length == 0"; + + if (N != null && E != null && N.length > 0 && E.length > 0) { + this.n = parseBigInt(N, 16); + this.e = parseInt(E, 16); + this.d = parseBigInt(D, 16); + this.p = parseBigInt(P, 16); + this.q = parseBigInt(Q, 16); + this.dmp1 = parseBigInt(DP, 16); + this.dmq1 = parseBigInt(DQ, 16); + this.coeff = parseBigInt(C, 16); + } else { + alert("Invalid RSA private key in RSASetPrivateEx"); + } + } + + // Generate a new random private key B bits long, using public expt E + function RSAGenerate(B, E) { + var rng = new SecureRandom(); + var qs = B >> 1; + this.e = parseInt(E, 16); + var ee = new BigInteger(E, 16); + for (; ;) { + for (; ;) { + this.p = new BigInteger(B - qs, 1, rng); + if (this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) break; + } + for (; ;) { + this.q = new BigInteger(qs, 1, rng); + if (this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) break; + } + if (this.p.compareTo(this.q) <= 0) { + var t = this.p; + this.p = this.q; + this.q = t; + } + var p1 = this.p.subtract(BigInteger.ONE); // p1 = p - 1 + var q1 = this.q.subtract(BigInteger.ONE); // q1 = q - 1 + var phi = p1.multiply(q1); + if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { + this.n = this.p.multiply(this.q); // this.n = p * q + this.d = ee.modInverse(phi); // this.d = + this.dmp1 = this.d.mod(p1); // this.dmp1 = d mod (p - 1) + this.dmq1 = this.d.mod(q1); // this.dmq1 = d mod (q - 1) + this.coeff = this.q.modInverse(this.p); // this.coeff = (q ^ -1) mod p + break; + } + } + this.isPrivate = true; + } + + // Perform raw private operation on "x": return x^d (mod n) + function RSADoPrivate(x) { + if (this.p == null || this.q == null) + return x.modPow(this.d, this.n); + + // TODO: re-calculate any missing CRT params + var xp = x.mod(this.p).modPow(this.dmp1, this.p); // xp=cp? + var xq = x.mod(this.q).modPow(this.dmq1, this.q); // xq=cq? + + while (xp.compareTo(xq) < 0) + xp = xp.add(this.p); + // NOTE: + // xp.subtract(xq) => cp -cq + // xp.subtract(xq).multiply(this.coeff).mod(this.p) => (cp - cq) * u mod p = h + // xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq) => cq + (h * q) = M + return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq); + } + + // Return the PKCS#1 RSA decryption of "ctext". + // "ctext" is an even-length hex string and the output is a plain string. + function RSADecrypt(ctext) { + var c = parseBigInt(ctext, 16); + var m = this.doPrivate(c); + if (m == null) return null; + return pkcs1unpad2(m, (this.n.bitLength() + 7) >> 3); + } + + // Return the PKCS#1 OAEP RSA decryption of "ctext". + // "ctext" is an even-length hex string and the output is a plain string. + function RSADecryptOAEP(ctext, hash) { + var c = parseBigInt(ctext, 16); + var m = this.doPrivate(c); + if (m == null) return null; + return oaep_unpad(m, (this.n.bitLength() + 7) >> 3, hash); + } + + // Return the PKCS#1 RSA decryption of "ctext". + // "ctext" is a Base64-encoded string and the output is a plain string. + //function RSAB64Decrypt(ctext) { + // var h = b64tohex(ctext); + // if(h) return this.decrypt(h); else return null; + //} + + // protected + RSAKey.prototype.doPrivate = RSADoPrivate; + + // public + RSAKey.prototype.setPrivate = RSASetPrivate; + RSAKey.prototype.setPrivateEx = RSASetPrivateEx; + RSAKey.prototype.generate = RSAGenerate; + RSAKey.prototype.decrypt = RSADecrypt; + RSAKey.prototype.decryptOAEP = RSADecryptOAEP; + //RSAKey.prototype.b64_decrypt = RSAB64Decrypt; + /*! rsapem-1.1.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license + */ + // + // rsa-pem.js - adding function for reading/writing PKCS#1 PEM private key + // to RSAKey class. + // + // version: 1.1.1 (2013-Apr-12) + // + // Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com) + // + // This software is licensed under the terms of the MIT License. + // http://kjur.github.com/jsrsasign/license/ + // + // The above copyright and license notice shall be + // included in all copies or substantial portions of the Software. + // + // + // Depends on: + // + // + // + // _RSApem_pemToBase64(sPEM) + // + // removing PEM header, PEM footer and space characters including + // new lines from PEM formatted RSA private key string. + // + + /** + * @fileOverview + * @name rsapem-1.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version 1.1 + * @license MIT License + */ + function _rsapem_pemToBase64(sPEMPrivateKey) { + var s = sPEMPrivateKey; + s = s.replace("-----BEGIN RSA PRIVATE KEY-----", ""); + s = s.replace("-----END RSA PRIVATE KEY-----", ""); + s = s.replace(/[ \n]+/g, ""); + return s; + } + + function _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey) { + var a = new Array(); + var v1 = ASN1HEX.getStartPosOfV_AtObj(hPrivateKey, 0); + var n1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, v1); + var e1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, n1); + var d1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, e1); + var p1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, d1); + var q1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, p1); + var dp1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, q1); + var dq1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dp1); + var co1 = ASN1HEX.getPosOfNextSibling_AtObj(hPrivateKey, dq1); + a.push(v1, n1, e1, d1, p1, q1, dp1, dq1, co1); + return a; + } + + function _rsapem_getHexValueArrayOfChildrenFromHex(hPrivateKey) { + var posArray = _rsapem_getPosArrayOfChildrenFromHex(hPrivateKey); + var v = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[0]); + var n = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[1]); + var e = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[2]); + var d = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[3]); + var p = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[4]); + var q = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[5]); + var dp = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[6]); + var dq = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[7]); + var co = ASN1HEX.getHexOfV_AtObj(hPrivateKey, posArray[8]); + var a = new Array(); + a.push(v, n, e, d, p, q, dp, dq, co); + return a; + } + + /** + * read RSA private key from a ASN.1 hexadecimal string + * @name readPrivateKeyFromASN1HexString + * @memberOf RSAKey# + * @function + * @param {String} keyHex ASN.1 hexadecimal string of PKCS#1 private key. + * @since 1.1.1 + */ + function _rsapem_readPrivateKeyFromASN1HexString(keyHex) { + var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex); + this.setPrivateEx(a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); + } + + /** + * read PKCS#1 private key from a string + * @name readPrivateKeyFromPEMString + * @memberOf RSAKey# + * @function + * @param {String} keyPEM string of PKCS#1 private key. + */ + function _rsapem_readPrivateKeyFromPEMString(keyPEM) { + var keyB64 = _rsapem_pemToBase64(keyPEM); + var keyHex = b64tohex(keyB64) // depends base64.js + var a = _rsapem_getHexValueArrayOfChildrenFromHex(keyHex); + this.setPrivateEx(a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); + } + + RSAKey.prototype.readPrivateKeyFromPEMString = _rsapem_readPrivateKeyFromPEMString; + RSAKey.prototype.readPrivateKeyFromASN1HexString = _rsapem_readPrivateKeyFromASN1HexString; + /*! rsasign-1.2.7.js (c) 2012 Kenji Urushima | kjur.github.com/jsrsasign/license + */ + var _RE_HEXDECONLY = new RegExp(""); _RE_HEXDECONLY.compile("[^0-9a-f]", "gi"); function _rsasign_getHexPaddedDigestInfoForString(d, e, a) { var b = function (f) { return KJUR.crypto.Util.hashString(f, a) }; var c = b(d); return KJUR.crypto.Util.getPaddedDigestInfoHex(c, a, e) } function _zeroPaddingOfSignature(e, d) { var c = ""; var a = d / 4 - e.length; for (var b = 0; b < a; b++) { c = c + "0" } return c + e } function _rsasign_signString(d, a) { var b = function (e) { return KJUR.crypto.Util.hashString(e, a) }; var c = b(d); return this.signWithMessageHash(c, a) } function _rsasign_signWithMessageHash(e, c) { var f = KJUR.crypto.Util.getPaddedDigestInfoHex(e, c, this.n.bitLength()); var b = parseBigInt(f, 16); var d = this.doPrivate(b); var a = d.toString(16); return _zeroPaddingOfSignature(a, this.n.bitLength()) } function _rsasign_signStringWithSHA1(a) { return _rsasign_signString.call(this, a, "sha1") } function _rsasign_signStringWithSHA256(a) { return _rsasign_signString.call(this, a, "sha256") } function pss_mgf1_str(c, a, e) { var b = "", d = 0; while (b.length < a) { b += hextorstr(e(rstrtohex(c + String.fromCharCode.apply(String, [(d & 4278190080) >> 24, (d & 16711680) >> 16, (d & 65280) >> 8, d & 255])))); d += 1 } return b } function _rsasign_signStringPSS(e, a, d) { var c = function (f) { return KJUR.crypto.Util.hashHex(f, a) }; var b = c(rstrtohex(e)); if (d === undefined) { d = -1 } return this.signWithMessageHashPSS(b, a, d) } function _rsasign_signWithMessageHashPSS(l, a, k) { var b = hextorstr(l); var g = b.length; var m = this.n.bitLength() - 1; var c = Math.ceil(m / 8); var d; var o = function (i) { return KJUR.crypto.Util.hashHex(i, a) }; if (k === -1 || k === undefined) { k = g } else { if (k === -2) { k = c - g - 2 } else { if (k < -2) { throw "invalid salt length" } } } if (c < (g + k + 2)) { throw "data too long" } var f = ""; if (k > 0) { f = new Array(k); new SecureRandom().nextBytes(f); f = String.fromCharCode.apply(String, f) } var n = hextorstr(o(rstrtohex("\x00\x00\x00\x00\x00\x00\x00\x00" + b + f))); var j = []; for (d = 0; d < c - k - g - 2; d += 1) { j[d] = 0 } var e = String.fromCharCode.apply(String, j) + "\x01" + f; var h = pss_mgf1_str(n, e.length, o); var q = []; for (d = 0; d < e.length; d += 1) { q[d] = e.charCodeAt(d) ^ h.charCodeAt(d) } var p = (65280 >> (8 * c - m)) & 255; q[0] &= ~p; for (d = 0; d < g; d++) { q.push(n.charCodeAt(d)) } q.push(188); return _zeroPaddingOfSignature(this.doPrivate(new BigInteger(q)).toString(16), this.n.bitLength()) } function _rsasign_getDecryptSignatureBI(a, d, c) { var b = new RSAKey(); b.setPublic(d, c); var e = b.doPublic(a); return e } function _rsasign_getHexDigestInfoFromSig(a, c, b) { var e = _rsasign_getDecryptSignatureBI(a, c, b); var d = e.toString(16).replace(/^1f+00/, ""); return d } function _rsasign_getAlgNameAndHashFromHexDisgestInfo(f) { for (var e in KJUR.crypto.Util.DIGESTINFOHEAD) { var d = KJUR.crypto.Util.DIGESTINFOHEAD[e]; var b = d.length; if (f.substring(0, b) == d) { var c = [e, f.substring(b)]; return c } } return [] } function _rsasign_verifySignatureWithArgs(f, b, g, j) { var e = _rsasign_getHexDigestInfoFromSig(b, g, j); var h = _rsasign_getAlgNameAndHashFromHexDisgestInfo(e); if (h.length == 0) { return false } var d = h[0]; var i = h[1]; var a = function (k) { return KJUR.crypto.Util.hashString(k, d) }; var c = a(f); return (i == c) } function _rsasign_verifyHexSignatureForMessage(c, b) { var d = parseBigInt(c, 16); var a = _rsasign_verifySignatureWithArgs(b, d, this.n.toString(16), this.e.toString(16)); return a } function _rsasign_verifyString(f, j) { j = j.replace(_RE_HEXDECONLY, ""); j = j.replace(/[ \n]+/g, ""); var b = parseBigInt(j, 16); if (b.bitLength() > this.n.bitLength()) { return 0 } var i = this.doPublic(b); var e = i.toString(16).replace(/^1f+00/, ""); var g = _rsasign_getAlgNameAndHashFromHexDisgestInfo(e); if (g.length == 0) { return false } var d = g[0]; var h = g[1]; var a = function (k) { return KJUR.crypto.Util.hashString(k, d) }; var c = a(f); return (h == c) } function _rsasign_verifyWithMessageHash(e, a) { a = a.replace(_RE_HEXDECONLY, ""); a = a.replace(/[ \n]+/g, ""); var b = parseBigInt(a, 16); if (b.bitLength() > this.n.bitLength()) { return 0 } var h = this.doPublic(b); var g = h.toString(16).replace(/^1f+00/, ""); var c = _rsasign_getAlgNameAndHashFromHexDisgestInfo(g); if (c.length == 0) { return false } var d = c[0]; var f = c[1]; return (f == e) } function _rsasign_verifyStringPSS(c, b, a, f) { var e = function (g) { return KJUR.crypto.Util.hashHex(g, a) }; var d = e(rstrtohex(c)); if (f === undefined) { f = -1 } return this.verifyWithMessageHashPSS(d, b, a, f) } function _rsasign_verifyWithMessageHashPSS(f, s, l, c) { var k = new BigInteger(s, 16); if (k.bitLength() > this.n.bitLength()) { return false } var r = function (i) { return KJUR.crypto.Util.hashHex(i, l) }; var j = hextorstr(f); var h = j.length; var g = this.n.bitLength() - 1; var m = Math.ceil(g / 8); var q; if (c === -1 || c === undefined) { c = h } else { if (c === -2) { c = m - h - 2 } else { if (c < -2) { throw "invalid salt length" } } } if (m < (h + c + 2)) { throw "data too long" } var a = this.doPublic(k).toByteArray(); for (q = 0; q < a.length; q += 1) { a[q] &= 255 } while (a.length < m) { a.unshift(0) } if (a[m - 1] !== 188) { throw "encoded message does not end in 0xbc" } a = String.fromCharCode.apply(String, a); var d = a.substr(0, m - h - 1); var e = a.substr(d.length, h); var p = (65280 >> (8 * m - g)) & 255; if ((d.charCodeAt(0) & p) !== 0) { throw "bits beyond keysize not zero" } var n = pss_mgf1_str(e, d.length, r); var o = []; for (q = 0; q < d.length; q += 1) { o[q] = d.charCodeAt(q) ^ n.charCodeAt(q) } o[0] &= ~p; var b = m - h - c - 2; for (q = 0; q < b; q += 1) { if (o[q] !== 0) { throw "leftmost octets not zero" } } if (o[b] !== 1) { throw "0x01 marker not found" } return e === hextorstr(r(rstrtohex("\x00\x00\x00\x00\x00\x00\x00\x00" + j + String.fromCharCode.apply(String, o.slice(-c))))) } RSAKey.prototype.signWithMessageHash = _rsasign_signWithMessageHash; RSAKey.prototype.signString = _rsasign_signString; RSAKey.prototype.signStringWithSHA1 = _rsasign_signStringWithSHA1; RSAKey.prototype.signStringWithSHA256 = _rsasign_signStringWithSHA256; RSAKey.prototype.sign = _rsasign_signString; RSAKey.prototype.signWithSHA1 = _rsasign_signStringWithSHA1; RSAKey.prototype.signWithSHA256 = _rsasign_signStringWithSHA256; RSAKey.prototype.signWithMessageHashPSS = _rsasign_signWithMessageHashPSS; RSAKey.prototype.signStringPSS = _rsasign_signStringPSS; RSAKey.prototype.signPSS = _rsasign_signStringPSS; RSAKey.SALT_LEN_HLEN = -1; RSAKey.SALT_LEN_MAX = -2; RSAKey.prototype.verifyWithMessageHash = _rsasign_verifyWithMessageHash; RSAKey.prototype.verifyString = _rsasign_verifyString; RSAKey.prototype.verifyHexSignatureForMessage = _rsasign_verifyHexSignatureForMessage; RSAKey.prototype.verify = _rsasign_verifyString; RSAKey.prototype.verifyHexSignatureForByteArrayMessage = _rsasign_verifyHexSignatureForMessage; RSAKey.prototype.verifyWithMessageHashPSS = _rsasign_verifyWithMessageHashPSS; RSAKey.prototype.verifyStringPSS = _rsasign_verifyStringPSS; RSAKey.prototype.verifyPSS = _rsasign_verifyStringPSS; RSAKey.SALT_LEN_RECOVER = -2; + /*! asn1hex-1.1.5.js (c) 2012-2014 Kenji Urushima | kjur.github.com/jsrsasign/license + */ + /* + * asn1hex.js - Hexadecimal represented ASN.1 string library + * + * Copyright (c) 2010-2014 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * http://kjur.github.com/jsrsasign/license/ + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + + /** + * @fileOverview + * @name asn1hex-1.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version asn1hex 1.1.5 (2014-May-25) + * @license MIT License + */ + + /* + * MEMO: + * f('3082025b02...', 2) ... 82025b ... 3bytes + * f('020100', 2) ... 01 ... 1byte + * f('0203001...', 2) ... 03 ... 1byte + * f('02818003...', 2) ... 8180 ... 2bytes + * f('3080....0000', 2) ... 80 ... -1 + * + * Requirements: + * - ASN.1 type octet length MUST be 1. + * (i.e. ASN.1 primitives like SET, SEQUENCE, INTEGER, OCTETSTRING ...) + */ + + /** + * ASN.1 DER encoded hexadecimal string utility class + * @name ASN1HEX + * @class ASN.1 DER encoded hexadecimal string utility class + * @since jsrsasign 1.1 + */ + var ASN1HEX = new function () { + /** + * get byte length for ASN.1 L(length) bytes + * @name getByteLengthOfL_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return byte length for ASN.1 L(length) bytes + */ + this.getByteLengthOfL_AtObj = function (s, pos) { + if (s.substring(pos + 2, pos + 3) != '8') return 1; + var i = parseInt(s.substring(pos + 3, pos + 4)); + if (i == 0) return -1; // length octet '80' indefinite length + if (0 < i && i < 10) return i + 1; // including '8?' octet; + return -2; // malformed format + }; + + /** + * get hexadecimal string for ASN.1 L(length) bytes + * @name getHexOfL_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return {String} hexadecimal string for ASN.1 L(length) bytes + */ + this.getHexOfL_AtObj = function (s, pos) { + var len = this.getByteLengthOfL_AtObj(s, pos); + if (len < 1) return ''; + return s.substring(pos + 2, pos + 2 + len * 2); + }; + + // getting ASN.1 length value at the position 'idx' of + // hexa decimal string 's'. + // + // f('3082025b02...', 0) ... 82025b ... ??? + // f('020100', 0) ... 01 ... 1 + // f('0203001...', 0) ... 03 ... 3 + // f('02818003...', 0) ... 8180 ... 128 + /** + * get integer value of ASN.1 length for ASN.1 data + * @name getIntOfL_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return ASN.1 L(length) integer value + */ + this.getIntOfL_AtObj = function (s, pos) { + var hLength = this.getHexOfL_AtObj(s, pos); + if (hLength == '') return -1; + var bi; + if (parseInt(hLength.substring(0, 1)) < 8) { + bi = new BigInteger(hLength, 16); + } else { + bi = new BigInteger(hLength.substring(2), 16); + } + return bi.intValue(); + }; + + /** + * get ASN.1 value starting string position for ASN.1 object refered by index 'idx'. + * @name getStartPosOfV_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + */ + this.getStartPosOfV_AtObj = function (s, pos) { + var l_len = this.getByteLengthOfL_AtObj(s, pos); + if (l_len < 0) return l_len; + return pos + (l_len + 1) * 2; + }; + + /** + * get hexadecimal string of ASN.1 V(value) + * @name getHexOfV_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return {String} hexadecimal string of ASN.1 value. + */ + this.getHexOfV_AtObj = function (s, pos) { + var pos1 = this.getStartPosOfV_AtObj(s, pos); + var len = this.getIntOfL_AtObj(s, pos); + return s.substring(pos1, pos1 + len * 2); + }; + + /** + * get hexadecimal string of ASN.1 TLV at + * @name getHexOfTLV_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return {String} hexadecimal string of ASN.1 TLV. + * @since 1.1 + */ + this.getHexOfTLV_AtObj = function (s, pos) { + var hT = s.substr(pos, 2); + var hL = this.getHexOfL_AtObj(s, pos); + var hV = this.getHexOfV_AtObj(s, pos); + return hT + hL + hV; + }; + + /** + * get next sibling starting index for ASN.1 object string + * @name getPosOfNextSibling_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} pos string index + * @return next sibling starting index for ASN.1 object string + */ + this.getPosOfNextSibling_AtObj = function (s, pos) { + var pos1 = this.getStartPosOfV_AtObj(s, pos); + var len = this.getIntOfL_AtObj(s, pos); + return pos1 + len * 2; + }; + + /** + * get array of indexes of child ASN.1 objects + * @name getPosArrayOfChildren_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} s hexadecimal string of ASN.1 DER encoded data + * @param {Number} start string index of ASN.1 object + * @return {Array of Number} array of indexes for childen of ASN.1 objects + */ + this.getPosArrayOfChildren_AtObj = function (h, pos) { + var a = new Array(); + var p0 = this.getStartPosOfV_AtObj(h, pos); + a.push(p0); + + var len = this.getIntOfL_AtObj(h, pos); + var p = p0; + var k = 0; + while (1) { + var pNext = this.getPosOfNextSibling_AtObj(h, p); + if (pNext == null || (pNext - p0 >= (len * 2))) break; + if (k >= 200) break; + + a.push(pNext); + p = pNext; + + k++; + } + + return a; + }; + + /** + * get string index of nth child object of ASN.1 object refered by h, idx + * @name getNthChildIndex_AtObj + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} idx start string index of ASN.1 object + * @param {Number} nth for child + * @return {Number} string index of nth child. + * @since 1.1 + */ + this.getNthChildIndex_AtObj = function (h, idx, nth) { + var a = this.getPosArrayOfChildren_AtObj(h, idx); + return a[nth]; + }; + + // ========== decendant methods ============================== + /** + * get string index of nth child object of ASN.1 object refered by h, idx + * @name getDecendantIndexByNthList + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} currentIndex start string index of ASN.1 object + * @param {Array of Number} nthList array list of nth + * @return {Number} string index refered by nthList + * @since 1.1 + * @example + * The "nthList" is a index list of structured ASN.1 object + * reference. Here is a sample structure and "nthList"s which + * refers each objects. + * + * SQUENCE - + * SEQUENCE - [0] + * IA5STRING 000 - [0, 0] + * UTF8STRING 001 - [0, 1] + * SET - [1] + * IA5STRING 010 - [1, 0] + * UTF8STRING 011 - [1, 1] + */ + this.getDecendantIndexByNthList = function (h, currentIndex, nthList) { + if (nthList.length == 0) { + return currentIndex; + } + var firstNth = nthList.shift(); + var a = this.getPosArrayOfChildren_AtObj(h, currentIndex); + return this.getDecendantIndexByNthList(h, a[firstNth], nthList); + }; + + /** + * get hexadecimal string of ASN.1 TLV refered by current index and nth index list. + * @name getDecendantHexTLVByNthList + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} currentIndex start string index of ASN.1 object + * @param {Array of Number} nthList array list of nth + * @return {Number} hexadecimal string of ASN.1 TLV refered by nthList + * @since 1.1 + */ + this.getDecendantHexTLVByNthList = function (h, currentIndex, nthList) { + var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); + return this.getHexOfTLV_AtObj(h, idx); + }; + + /** + * get hexadecimal string of ASN.1 V refered by current index and nth index list. + * @name getDecendantHexVByNthList + * @memberOf ASN1HEX + * @function + * @param {String} h hexadecimal string of ASN.1 DER encoded data + * @param {Number} currentIndex start string index of ASN.1 object + * @param {Array of Number} nthList array list of nth + * @return {Number} hexadecimal string of ASN.1 V refered by nthList + * @since 1.1 + */ + this.getDecendantHexVByNthList = function (h, currentIndex, nthList) { + var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); + return this.getHexOfV_AtObj(h, idx); + }; + }; + + /* + * @since asn1hex 1.1.4 + */ + ASN1HEX.getVbyList = function (h, currentIndex, nthList, checkingTag) { + var idx = this.getDecendantIndexByNthList(h, currentIndex, nthList); + if (idx === undefined) { + throw "can't find nthList object"; + } + if (checkingTag !== undefined) { + if (h.substr(idx, 2) != checkingTag) { + throw "checking tag doesn't match: " + + h.substr(idx, 2) + "!=" + checkingTag; + } + } + return this.getHexOfV_AtObj(h, idx); + }; + + /** + * get OID string from hexadecimal encoded value + * @name hextooidstr + * @memberOf ASN1HEX + * @function + * @param {String} hex hexadecmal string of ASN.1 DER encoded OID value + * @return {String} OID string (ex. '1.2.3.4.567') + * @since asn1hex 1.1.5 + */ + ASN1HEX.hextooidstr = function (hex) { + var zeroPadding = function (s, len) { + if (s.length >= len) return s; + return new Array(len - s.length + 1).join('0') + s; + }; + + var a = []; + + // a[0], a[1] + var hex0 = hex.substr(0, 2); + var i0 = parseInt(hex0, 16); + a[0] = new String(Math.floor(i0 / 40)); + a[1] = new String(i0 % 40); + + // a[2]..a[n] + var hex1 = hex.substr(2); + var b = []; + for (var i = 0; i < hex1.length / 2; i++) { + b.push(parseInt(hex1.substr(i * 2, 2), 16)); + } + var c = []; + var cbin = ""; + for (var i = 0; i < b.length; i++) { + if (b[i] & 0x80) { + cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7); + } else { + cbin = cbin + zeroPadding((b[i] & 0x7f).toString(2), 7); + c.push(new String(parseInt(cbin, 2))); + cbin = ""; + } + } + + var s = a.join("."); + if (c.length > 0) s = s + "." + c.join("."); + return s; + }; + + /*! x509-1.1.3.js (c) 2012-2014 Kenji Urushima | kjur.github.com/jsrsasign/license + */ + /* + * x509.js - X509 class to read subject public key from certificate. + * + * Copyright (c) 2010-2014 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * http://kjur.github.com/jsrsasign/license + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + + /** + * @fileOverview + * @name x509-1.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version x509 1.1.3 (2014-May-17) + * @since jsrsasign 1.x.x + * @license MIT License + */ + + /* + * Depends: + * base64.js + * rsa.js + * asn1hex.js + */ + + /** + * X.509 certificate class.
+ * @class X.509 certificate class + * @property {RSAKey} subjectPublicKeyRSA Tom Wu's RSAKey object + * @property {String} subjectPublicKeyRSA_hN hexadecimal string for modulus of RSA public key + * @property {String} subjectPublicKeyRSA_hE hexadecimal string for public exponent of RSA public key + * @property {String} hex hexacedimal string for X.509 certificate. + * @author Kenji Urushima + * @version 1.0.1 (08 May 2012) + * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ + */ + function X509() { + this.subjectPublicKeyRSA = null; + this.subjectPublicKeyRSA_hN = null; + this.subjectPublicKeyRSA_hE = null; + this.hex = null; + + // ===== get basic fields from hex ===================================== + + /** + * get hexadecimal string of serialNumber field of certificate.
+ * @name getSerialNumberHex + * @memberOf X509# + * @function + */ + this.getSerialNumberHex = function () { + return ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 1]); + }; + + /** + * get hexadecimal string of issuer field TLV of certificate.
+ * @name getIssuerHex + * @memberOf X509# + * @function + */ + this.getIssuerHex = function () { + return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3]); + }; + + /** + * get string of issuer field of certificate.
+ * @name getIssuerString + * @memberOf X509# + * @function + */ + this.getIssuerString = function () { + return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 3])); + }; + + /** + * get hexadecimal string of subject field of certificate.
+ * @name getSubjectHex + * @memberOf X509# + * @function + */ + this.getSubjectHex = function () { + return ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5]); + }; + + /** + * get string of subject field of certificate.
+ * @name getSubjectString + * @memberOf X509# + * @function + */ + this.getSubjectString = function () { + return X509.hex2dn(ASN1HEX.getDecendantHexTLVByNthList(this.hex, 0, [0, 5])); + }; + + /** + * get notBefore field string of certificate.
+ * @name getNotBefore + * @memberOf X509# + * @function + */ + this.getNotBefore = function () { + var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 0]); + s = s.replace(/(..)/g, "%$1"); + s = decodeURIComponent(s); + return s; + }; + + /** + * get notAfter field string of certificate.
+ * @name getNotAfter + * @memberOf X509# + * @function + */ + this.getNotAfter = function () { + var s = ASN1HEX.getDecendantHexVByNthList(this.hex, 0, [0, 4, 1]); + s = s.replace(/(..)/g, "%$1"); + s = decodeURIComponent(s); + return s; + }; + + // ===== read certificate public key ========================== + + // ===== read certificate ===================================== + /** + * read PEM formatted X.509 certificate from string.
+ * @name readCertPEM + * @memberOf X509# + * @function + * @param {String} sCertPEM string for PEM formatted X.509 certificate + */ + this.readCertPEM = function (sCertPEM) { + var hCert = X509.pemToHex(sCertPEM); + var a = X509.getPublicKeyHexArrayFromCertHex(hCert); + var rsa = new RSAKey(); + rsa.setPublic(a[0], a[1]); + this.subjectPublicKeyRSA = rsa; + this.subjectPublicKeyRSA_hN = a[0]; + this.subjectPublicKeyRSA_hE = a[1]; + this.hex = hCert; + }; + + this.readCertPEMWithoutRSAInit = function (sCertPEM) { + var hCert = X509.pemToHex(sCertPEM); + var a = X509.getPublicKeyHexArrayFromCertHex(hCert); + this.subjectPublicKeyRSA.setPublic(a[0], a[1]); + this.subjectPublicKeyRSA_hN = a[0]; + this.subjectPublicKeyRSA_hE = a[1]; + this.hex = hCert; + }; + }; + + X509.pemToBase64 = function (sCertPEM) { + var s = sCertPEM; + s = s.replace("-----BEGIN CERTIFICATE-----", ""); + s = s.replace("-----END CERTIFICATE-----", ""); + s = s.replace(/[ \n]+/g, ""); + return s; + }; + + X509.pemToHex = function (sCertPEM) { + var b64Cert = X509.pemToBase64(sCertPEM); + var hCert = b64tohex(b64Cert); + return hCert; + }; + + // NOTE: Without BITSTRING encapsulation. + X509.getSubjectPublicKeyPosFromCertHex = function (hCert) { + var pInfo = X509.getSubjectPublicKeyInfoPosFromCertHex(hCert); + if (pInfo == -1) return -1; + var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pInfo); + if (a.length != 2) return -1; + var pBitString = a[1]; + if (hCert.substring(pBitString, pBitString + 2) != '03') return -1; + var pBitStringV = ASN1HEX.getStartPosOfV_AtObj(hCert, pBitString); + + if (hCert.substring(pBitStringV, pBitStringV + 2) != '00') return -1; + return pBitStringV + 2; + }; + + // NOTE: privateKeyUsagePeriod field of X509v2 not supported. + // NOTE: v1 and v3 supported + X509.getSubjectPublicKeyInfoPosFromCertHex = function (hCert) { + var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0); + var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, pTbsCert); + if (a.length < 1) return -1; + if (hCert.substring(a[0], a[0] + 10) == "a003020102") { // v3 + if (a.length < 6) return -1; + return a[6]; + } else { + if (a.length < 5) return -1; + return a[5]; + } + }; + + X509.getPublicKeyHexArrayFromCertHex = function (hCert) { + var p = X509.getSubjectPublicKeyPosFromCertHex(hCert); + var a = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, p); + if (a.length != 2) return []; + var hN = ASN1HEX.getHexOfV_AtObj(hCert, a[0]); + var hE = ASN1HEX.getHexOfV_AtObj(hCert, a[1]); + if (hN != null && hE != null) { + return [hN, hE]; + } else { + return []; + } + }; + + X509.getHexTbsCertificateFromCert = function (hCert) { + var pTbsCert = ASN1HEX.getStartPosOfV_AtObj(hCert, 0); + return pTbsCert; + }; + + X509.getPublicKeyHexArrayFromCertPEM = function (sCertPEM) { + var hCert = X509.pemToHex(sCertPEM); + var a = X509.getPublicKeyHexArrayFromCertHex(hCert); + return a; + }; + + X509.hex2dn = function (hDN) { + var s = ""; + var a = ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0); + for (var i = 0; i < a.length; i++) { + var hRDN = ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]); + s = s + "/" + X509.hex2rdn(hRDN); + } + return s; + }; + + X509.hex2rdn = function (hRDN) { + var hType = ASN1HEX.getDecendantHexTLVByNthList(hRDN, 0, [0, 0]); + var hValue = ASN1HEX.getDecendantHexVByNthList(hRDN, 0, [0, 1]); + var type = ""; + try { type = X509.DN_ATTRHEX[hType]; } catch (ex) { type = hType; } + hValue = hValue.replace(/(..)/g, "%$1"); + var value = decodeURIComponent(hValue); + return type + "=" + value; + }; + + X509.DN_ATTRHEX = { + "0603550406": "C", + "060355040a": "O", + "060355040b": "OU", + "0603550403": "CN", + "0603550405": "SN", + "0603550408": "ST", + "0603550407": "L", + }; + + /** + * get RSAKey/ECDSA public key object from PEM certificate string + * @name getPublicKeyFromCertPEM + * @memberOf X509 + * @function + * @param {String} sCertPEM PEM formatted RSA/ECDSA/DSA X.509 certificate + * @return returns RSAKey/KJUR.crypto.{ECDSA,DSA} object of public key + * @since x509 1.1.1 + * @description + * NOTE: DSA is also supported since x509 1.1.2. + */ + X509.getPublicKeyFromCertPEM = function (sCertPEM) { + var info = X509.getPublicKeyInfoPropOfCertPEM(sCertPEM); + + if (info.algoid == "2a864886f70d010101") { // RSA + var aRSA = KEYUTIL.parsePublicRawRSAKeyHex(info.keyhex); + var key = new RSAKey(); + key.setPublic(aRSA.n, aRSA.e); + return key; + } else if (info.algoid == "2a8648ce3d0201") { // ECC + var curveName = KJUR.crypto.OID.oidhex2name[info.algparam]; + var key = new KJUR.crypto.ECDSA({ 'curve': curveName, 'info': info.keyhex }); + key.setPublicKeyHex(info.keyhex); + return key; + } else if (info.algoid == "2a8648ce380401") { // DSA 1.2.840.10040.4.1 + var p = ASN1HEX.getVbyList(info.algparam, 0, [0], "02"); + var q = ASN1HEX.getVbyList(info.algparam, 0, [1], "02"); + var g = ASN1HEX.getVbyList(info.algparam, 0, [2], "02"); + var y = ASN1HEX.getHexOfV_AtObj(info.keyhex, 0); + y = y.substr(2); + var key = new KJUR.crypto.DSA(); + key.setPublic(new BigInteger(p, 16), + new BigInteger(q, 16), + new BigInteger(g, 16), + new BigInteger(y, 16)); + return key; + } else { + throw "unsupported key"; + } + }; + + /** + * get public key information from PEM certificate + * @name getPublicKeyInfoPropOfCertPEM + * @memberOf X509 + * @function + * @param {String} sCertPEM string of PEM formatted certificate + * @return {Hash} hash of information for public key + * @since x509 1.1.1 + * @description + * Resulted associative array has following properties: + *
    + *
  • algoid - hexadecimal string of OID of asymmetric key algorithm
  • + *
  • algparam - hexadecimal string of OID of ECC curve name or null
  • + *
  • keyhex - hexadecimal string of key in the certificate
  • + *
+ * @since x509 1.1.1 + */ + X509.getPublicKeyInfoPropOfCertPEM = function (sCertPEM) { + var result = {}; + result.algparam = null; + var hCert = X509.pemToHex(sCertPEM); + + // 1. Certificate ASN.1 + var a1 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, 0); + if (a1.length != 3) + throw "malformed X.509 certificate PEM (code:001)"; // not 3 item of seq Cert + + // 2. tbsCertificate + if (hCert.substr(a1[0], 2) != "30") + throw "malformed X.509 certificate PEM (code:002)"; // tbsCert not seq + + var a2 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a1[0]); + + // 3. subjectPublicKeyInfo + if (a2.length < 7) + throw "malformed X.509 certificate PEM (code:003)"; // no subjPubKeyInfo + + var a3 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a2[6]); + + if (a3.length != 2) + throw "malformed X.509 certificate PEM (code:004)"; // not AlgId and PubKey + + // 4. AlgId + var a4 = ASN1HEX.getPosArrayOfChildren_AtObj(hCert, a3[0]); + + if (a4.length != 2) + throw "malformed X.509 certificate PEM (code:005)"; // not 2 item in AlgId + + result.algoid = ASN1HEX.getHexOfV_AtObj(hCert, a4[0]); + + if (hCert.substr(a4[1], 2) == "06") { // EC + result.algparam = ASN1HEX.getHexOfV_AtObj(hCert, a4[1]); + } else if (hCert.substr(a4[1], 2) == "30") { // DSA + result.algparam = ASN1HEX.getHexOfTLV_AtObj(hCert, a4[1]); + } + + // 5. Public Key Hex + if (hCert.substr(a3[1], 2) != "03") + throw "malformed X.509 certificate PEM (code:006)"; // not bitstring + + var unusedBitAndKeyHex = ASN1HEX.getHexOfV_AtObj(hCert, a3[1]); + result.keyhex = unusedBitAndKeyHex.substr(2); + + return result; + }; + + /* + X509.prototype.readCertPEM = _x509_readCertPEM; + X509.prototype.readCertPEMWithoutRSAInit = _x509_readCertPEMWithoutRSAInit; + X509.prototype.getSerialNumberHex = _x509_getSerialNumberHex; + X509.prototype.getIssuerHex = _x509_getIssuerHex; + X509.prototype.getSubjectHex = _x509_getSubjectHex; + X509.prototype.getIssuerString = _x509_getIssuerString; + X509.prototype.getSubjectString = _x509_getSubjectString; + X509.prototype.getNotBefore = _x509_getNotBefore; + X509.prototype.getNotAfter = _x509_getNotAfter; + */ + /*! crypto-1.1.5.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license + */ + /* + * crypto.js - Cryptographic Algorithm Provider class + * + * Copyright (c) 2013 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * http://kjur.github.com/jsrsasign/license + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + + /** + * @fileOverview + * @name crypto-1.1.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version 1.1.5 (2013-Oct-06) + * @since jsrsasign 2.2 + * @license MIT License + */ + + /** + * kjur's class library name space + * @name KJUR + * @namespace kjur's class library name space + */ + if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; + /** + * kjur's cryptographic algorithm provider library name space + *

+ * This namespace privides following crytpgrahic classes. + *

    + *
  • {@link KJUR.crypto.MessageDigest} - Java JCE(cryptograhic extension) style MessageDigest class
  • + *
  • {@link KJUR.crypto.Signature} - Java JCE(cryptograhic extension) style Signature class
  • + *
  • {@link KJUR.crypto.Util} - cryptographic utility functions and properties
  • + *
+ * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2. + *

+ * @name KJUR.crypto + * @namespace + */ + if (typeof KJUR.crypto == "undefined" || !KJUR.crypto) KJUR.crypto = {}; + + /** + * static object for cryptographic function utilities + * @name KJUR.crypto.Util + * @class static object for cryptographic function utilities + * @property {Array} DIGESTINFOHEAD PKCS#1 DigestInfo heading hexadecimal bytes for each hash algorithms + * @property {Array} DEFAULTPROVIDER associative array of default provider name for each hash and signature algorithms + * @description + */ + KJUR.crypto.Util = new function () { + this.DIGESTINFOHEAD = { + 'sha1': "3021300906052b0e03021a05000414", + 'sha224': "302d300d06096086480165030402040500041c", + 'sha256': "3031300d060960864801650304020105000420", + 'sha384': "3041300d060960864801650304020205000430", + 'sha512': "3051300d060960864801650304020305000440", + 'md2': "3020300c06082a864886f70d020205000410", + 'md5': "3020300c06082a864886f70d020505000410", + 'ripemd160': "3021300906052b2403020105000414", + }; + + /* + * @since crypto 1.1.1 + */ + this.DEFAULTPROVIDER = { + 'md5': 'cryptojs', + 'sha1': 'cryptojs', + 'sha224': 'cryptojs', + 'sha256': 'cryptojs', + 'sha384': 'cryptojs', + 'sha512': 'cryptojs', + 'ripemd160': 'cryptojs', + 'hmacmd5': 'cryptojs', + 'hmacsha1': 'cryptojs', + 'hmacsha224': 'cryptojs', + 'hmacsha256': 'cryptojs', + 'hmacsha384': 'cryptojs', + 'hmacsha512': 'cryptojs', + 'hmacripemd160': 'cryptojs', + + 'MD5withRSA': 'cryptojs/jsrsa', + 'SHA1withRSA': 'cryptojs/jsrsa', + 'SHA224withRSA': 'cryptojs/jsrsa', + 'SHA256withRSA': 'cryptojs/jsrsa', + 'SHA384withRSA': 'cryptojs/jsrsa', + 'SHA512withRSA': 'cryptojs/jsrsa', + 'RIPEMD160withRSA': 'cryptojs/jsrsa', + + 'MD5withECDSA': 'cryptojs/jsrsa', + 'SHA1withECDSA': 'cryptojs/jsrsa', + 'SHA224withECDSA': 'cryptojs/jsrsa', + 'SHA256withECDSA': 'cryptojs/jsrsa', + 'SHA384withECDSA': 'cryptojs/jsrsa', + 'SHA512withECDSA': 'cryptojs/jsrsa', + 'RIPEMD160withECDSA': 'cryptojs/jsrsa', + + 'SHA1withDSA': 'cryptojs/jsrsa', + 'SHA224withDSA': 'cryptojs/jsrsa', + 'SHA256withDSA': 'cryptojs/jsrsa', + + 'MD5withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA1withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA224withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA256withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA384withRSAandMGF1': 'cryptojs/jsrsa', + 'SHA512withRSAandMGF1': 'cryptojs/jsrsa', + 'RIPEMD160withRSAandMGF1': 'cryptojs/jsrsa', + }; + + /* + * @since crypto 1.1.2 + */ + this.CRYPTOJSMESSAGEDIGESTNAME = { + 'md5': 'CryptoJS.algo.MD5', + 'sha1': 'CryptoJS.algo.SHA1', + 'sha224': 'CryptoJS.algo.SHA224', + 'sha256': 'CryptoJS.algo.SHA256', + 'sha384': 'CryptoJS.algo.SHA384', + 'sha512': 'CryptoJS.algo.SHA512', + 'ripemd160': 'CryptoJS.algo.RIPEMD160' + }; + + /** + * get hexadecimal DigestInfo + * @name getDigestInfoHex + * @memberOf KJUR.crypto.Util + * @function + * @param {String} hHash hexadecimal hash value + * @param {String} alg hash algorithm name (ex. 'sha1') + * @return {String} hexadecimal string DigestInfo ASN.1 structure + */ + this.getDigestInfoHex = function (hHash, alg) { + if (typeof this.DIGESTINFOHEAD[alg] == "undefined") + throw "alg not supported in Util.DIGESTINFOHEAD: " + alg; + return this.DIGESTINFOHEAD[alg] + hHash; + }; + + /** + * get PKCS#1 padded hexadecimal DigestInfo + * @name getPaddedDigestInfoHex + * @memberOf KJUR.crypto.Util + * @function + * @param {String} hHash hexadecimal hash value of message to be signed + * @param {String} alg hash algorithm name (ex. 'sha1') + * @param {Integer} keySize key bit length (ex. 1024) + * @return {String} hexadecimal string of PKCS#1 padded DigestInfo + */ + this.getPaddedDigestInfoHex = function (hHash, alg, keySize) { + var hDigestInfo = this.getDigestInfoHex(hHash, alg); + var pmStrLen = keySize / 4; // minimum PM length + + if (hDigestInfo.length + 22 > pmStrLen) // len(0001+ff(*8)+00+hDigestInfo)=22 + throw "key is too short for SigAlg: keylen=" + keySize + "," + alg; + + var hHead = "0001"; + var hTail = "00" + hDigestInfo; + var hMid = ""; + var fLen = pmStrLen - hHead.length - hTail.length; + for (var i = 0; i < fLen; i += 2) { + hMid += "ff"; + } + var hPaddedMessage = hHead + hMid + hTail; + return hPaddedMessage; + }; + + /** + * get hexadecimal hash of string with specified algorithm + * @name hashString + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @param {String} alg hash algorithm name + * @return {String} hexadecimal string of hash value + * @since 1.1.1 + */ + this.hashString = function (s, alg) { + var md = new KJUR.crypto.MessageDigest({ 'alg': alg }); + return md.digestString(s); + }; + + /** + * get hexadecimal hash of hexadecimal string with specified algorithm + * @name hashHex + * @memberOf KJUR.crypto.Util + * @function + * @param {String} sHex input hexadecimal string to be hashed + * @param {String} alg hash algorithm name + * @return {String} hexadecimal string of hash value + * @since 1.1.1 + */ + this.hashHex = function (sHex, alg) { + var md = new KJUR.crypto.MessageDigest({ 'alg': alg }); + return md.digestHex(sHex); + }; + + /** + * get hexadecimal SHA1 hash of string + * @name sha1 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.sha1 = function (s) { + var md = new KJUR.crypto.MessageDigest({ 'alg': 'sha1', 'prov': 'cryptojs' }); + return md.digestString(s); + }; + + /** + * get hexadecimal SHA256 hash of string + * @name sha256 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.sha256 = function (s) { + var md = new KJUR.crypto.MessageDigest({ 'alg': 'sha256', 'prov': 'cryptojs' }); + return md.digestString(s); + }; + + this.sha256Hex = function (s) { + var md = new KJUR.crypto.MessageDigest({ 'alg': 'sha256', 'prov': 'cryptojs' }); + return md.digestHex(s); + }; + + /** + * get hexadecimal SHA512 hash of string + * @name sha512 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.sha512 = function (s) { + var md = new KJUR.crypto.MessageDigest({ 'alg': 'sha512', 'prov': 'cryptojs' }); + return md.digestString(s); + }; + + this.sha512Hex = function (s) { + var md = new KJUR.crypto.MessageDigest({ 'alg': 'sha512', 'prov': 'cryptojs' }); + return md.digestHex(s); + }; + + /** + * get hexadecimal MD5 hash of string + * @name md5 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.md5 = function (s) { + var md = new KJUR.crypto.MessageDigest({ 'alg': 'md5', 'prov': 'cryptojs' }); + return md.digestString(s); + }; + + /** + * get hexadecimal RIPEMD160 hash of string + * @name ripemd160 + * @memberOf KJUR.crypto.Util + * @function + * @param {String} s input string to be hashed + * @return {String} hexadecimal string of hash value + * @since 1.0.3 + */ + this.ripemd160 = function (s) { + var md = new KJUR.crypto.MessageDigest({ 'alg': 'ripemd160', 'prov': 'cryptojs' }); + return md.digestString(s); + }; + + /* + * @since 1.1.2 + */ + this.getCryptoJSMDByName = function (s) { + + }; + }; + + /** + * MessageDigest class which is very similar to java.security.MessageDigest class + * @name KJUR.crypto.MessageDigest + * @class MessageDigest class which is very similar to java.security.MessageDigest class + * @param {Array} params parameters for constructor + * @description + *
+ * Currently this supports following algorithm and providers combination: + *
    + *
  • md5 - cryptojs
  • + *
  • sha1 - cryptojs
  • + *
  • sha224 - cryptojs
  • + *
  • sha256 - cryptojs
  • + *
  • sha384 - cryptojs
  • + *
  • sha512 - cryptojs
  • + *
  • ripemd160 - cryptojs
  • + *
  • sha256 - sjcl (NEW from crypto.js 1.0.4)
  • + *
+ * @example + * // CryptoJS provider sample + * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/core.js"></script> + * <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/sha1.js"></script> + * <script src="crypto-1.0.js"></script> + * var md = new KJUR.crypto.MessageDigest({alg: "sha1", prov: "cryptojs"}); + * md.updateString('aaa') + * var mdHex = md.digest() + * + * // SJCL(Stanford JavaScript Crypto Library) provider sample + * <script src="http://bitwiseshiftleft.github.io/sjcl/sjcl.js"></script> + * <script src="crypto-1.0.js"></script> + * var md = new KJUR.crypto.MessageDigest({alg: "sha256", prov: "sjcl"}); // sjcl supports sha256 only + * md.updateString('aaa') + * var mdHex = md.digest() + */ + KJUR.crypto.MessageDigest = function (params) { + var md = null; + var algName = null; + var provName = null; + + /** + * set hash algorithm and provider + * @name setAlgAndProvider + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} alg hash algorithm name + * @param {String} prov provider name + * @description + * @example + * // for SHA1 + * md.setAlgAndProvider('sha1', 'cryptojs'); + * // for RIPEMD160 + * md.setAlgAndProvider('ripemd160', 'cryptojs'); + */ + this.setAlgAndProvider = function (alg, prov) { + if (alg != null && prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg]; + + // for cryptojs + if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(alg) != -1 && + prov == 'cryptojs') { + try { + this.md = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[alg]).create(); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; + } + this.updateString = function (str) { + this.md.update(str); + }; + this.updateHex = function (hex) { + var wHex = CryptoJS.enc.Hex.parse(hex); + this.md.update(wHex); + }; + this.digest = function () { + var hash = this.md.finalize(); + return hash.toString(CryptoJS.enc.Hex); + }; + this.digestString = function (str) { + this.updateString(str); + return this.digest(); + }; + this.digestHex = function (hex) { + this.updateHex(hex); + return this.digest(); + }; + } + if (':sha256:'.indexOf(alg) != -1 && + prov == 'sjcl') { + try { + this.md = new sjcl.hash.sha256(); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail alg=" + alg + "/" + ex; + } + this.updateString = function (str) { + this.md.update(str); + }; + this.updateHex = function (hex) { + var baHex = sjcl.codec.hex.toBits(hex); + this.md.update(baHex); + }; + this.digest = function () { + var hash = this.md.finalize(); + return sjcl.codec.hex.fromBits(hash); + }; + this.digestString = function (str) { + this.updateString(str); + return this.digest(); + }; + this.digestHex = function (hex) { + this.updateHex(hex); + return this.digest(); + }; + } + }; + + /** + * update digest by specified string + * @name updateString + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} str string to update + * @description + * @example + * md.updateString('New York'); + */ + this.updateString = function (str) { + throw "updateString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * update digest by specified hexadecimal string + * @name updateHex + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} hex hexadecimal string to update + * @description + * @example + * md.updateHex('0afe36'); + */ + this.updateHex = function (hex) { + throw "updateHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * completes hash calculation and returns hash result + * @name digest + * @memberOf KJUR.crypto.MessageDigest + * @function + * @description + * @example + * md.digest() + */ + this.digest = function () { + throw "digest() not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * performs final update on the digest using string, then completes the digest computation + * @name digestString + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} str string to final update + * @description + * @example + * md.digestString('aaa') + */ + this.digestString = function (str) { + throw "digestString(str) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + /** + * performs final update on the digest using hexadecimal string, then completes the digest computation + * @name digestHex + * @memberOf KJUR.crypto.MessageDigest + * @function + * @param {String} hex hexadecimal string to final update + * @description + * @example + * md.digestHex('0f2abd') + */ + this.digestHex = function (hex) { + throw "digestHex(hex) not supported for this alg/prov: " + this.algName + "/" + this.provName; + }; + + if (params !== undefined) { + if (params['alg'] !== undefined) { + this.algName = params['alg']; + if (params['prov'] === undefined) + this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; + this.setAlgAndProvider(this.algName, this.provName); + } + } + }; + + /** + * Mac(Message Authentication Code) class which is very similar to java.security.Mac class + * @name KJUR.crypto.Mac + * @class Mac class which is very similar to java.security.Mac class + * @param {Array} params parameters for constructor + * @description + *
+ * Currently this supports following algorithm and providers combination: + *
    + *
  • hmacmd5 - cryptojs
  • + *
  • hmacsha1 - cryptojs
  • + *
  • hmacsha224 - cryptojs
  • + *
  • hmacsha256 - cryptojs
  • + *
  • hmacsha384 - cryptojs
  • + *
  • hmacsha512 - cryptojs
  • + *
+ * NOTE: HmacSHA224 and HmacSHA384 issue was fixed since jsrsasign 4.1.4. + * Please use 'ext/cryptojs-312-core-fix*.js' instead of 'core.js' of original CryptoJS + * to avoid those issue. + * @example + * var mac = new KJUR.crypto.Mac({alg: "HmacSHA1", prov: "cryptojs", "pass": "pass"}); + * mac.updateString('aaa') + * var macHex = md.doFinal() + */ + KJUR.crypto.Mac = function (params) { + var mac = null; + var pass = null; + var algName = null; + var provName = null; + var algProv = null; + + this.setAlgAndProvider = function (alg, prov) { + if (alg == null) alg = "hmacsha1"; + + alg = alg.toLowerCase(); + if (alg.substr(0, 4) != "hmac") { + throw "setAlgAndProvider unsupported HMAC alg: " + alg; + } + + if (prov === undefined) prov = KJUR.crypto.Util.DEFAULTPROVIDER[alg]; + this.algProv = alg + "/" + prov; + + var hashAlg = alg.substr(4); + + // for cryptojs + if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(hashAlg) != -1 && + prov == 'cryptojs') { + try { + var mdObj = eval(KJUR.crypto.Util.CRYPTOJSMESSAGEDIGESTNAME[hashAlg]); + this.mac = CryptoJS.algo.HMAC.create(mdObj, this.pass); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail hashAlg=" + hashAlg + "/" + ex; + } + this.updateString = function (str) { + this.mac.update(str); + }; + this.updateHex = function (hex) { + var wHex = CryptoJS.enc.Hex.parse(hex); + this.mac.update(wHex); + }; + this.doFinal = function () { + var hash = this.mac.finalize(); + return hash.toString(CryptoJS.enc.Hex); + }; + this.doFinalString = function (str) { + this.updateString(str); + return this.doFinal(); + }; + this.doFinalHex = function (hex) { + this.updateHex(hex); + return this.doFinal(); + }; + } + }; + + /** + * update digest by specified string + * @name updateString + * @memberOf KJUR.crypto.Mac + * @function + * @param {String} str string to update + * @description + * @example + * md.updateString('New York'); + */ + this.updateString = function (str) { + throw "updateString(str) not supported for this alg/prov: " + this.algProv; + }; + + /** + * update digest by specified hexadecimal string + * @name updateHex + * @memberOf KJUR.crypto.Mac + * @function + * @param {String} hex hexadecimal string to update + * @description + * @example + * md.updateHex('0afe36'); + */ + this.updateHex = function (hex) { + throw "updateHex(hex) not supported for this alg/prov: " + this.algProv; + }; + + /** + * completes hash calculation and returns hash result + * @name doFinal + * @memberOf KJUR.crypto.Mac + * @function + * @description + * @example + * md.digest() + */ + this.doFinal = function () { + throw "digest() not supported for this alg/prov: " + this.algProv; + }; + + /** + * performs final update on the digest using string, then completes the digest computation + * @name doFinalString + * @memberOf KJUR.crypto.Mac + * @function + * @param {String} str string to final update + * @description + * @example + * md.digestString('aaa') + */ + this.doFinalString = function (str) { + throw "digestString(str) not supported for this alg/prov: " + this.algProv; + }; + + /** + * performs final update on the digest using hexadecimal string, + * then completes the digest computation + * @name doFinalHex + * @memberOf KJUR.crypto.Mac + * @function + * @param {String} hex hexadecimal string to final update + * @description + * @example + * md.digestHex('0f2abd') + */ + this.doFinalHex = function (hex) { + throw "digestHex(hex) not supported for this alg/prov: " + this.algProv; + }; + + if (params !== undefined) { + if (params['pass'] !== undefined) { + this.pass = params['pass']; + } + if (params['alg'] !== undefined) { + this.algName = params['alg']; + if (params['prov'] === undefined) + this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; + this.setAlgAndProvider(this.algName, this.provName); + } + } + }; + + /** + * Signature class which is very similar to java.security.Signature class + * @name KJUR.crypto.Signature + * @class Signature class which is very similar to java.security.Signature class + * @param {Array} params parameters for constructor + * @property {String} state Current state of this signature object whether 'SIGN', 'VERIFY' or null + * @description + *
+ * As for params of constructor's argument, it can be specify following attributes: + *
    + *
  • alg - signature algorithm name (ex. {MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160}with{RSA,ECDSA,DSA})
  • + *
  • provider - currently 'cryptojs/jsrsa' only
  • + *
+ *

SUPPORTED ALGORITHMS AND PROVIDERS

+ * This Signature class supports following signature algorithm and provider names: + *
    + *
  • MD5withRSA - cryptojs/jsrsa
  • + *
  • SHA1withRSA - cryptojs/jsrsa
  • + *
  • SHA224withRSA - cryptojs/jsrsa
  • + *
  • SHA256withRSA - cryptojs/jsrsa
  • + *
  • SHA384withRSA - cryptojs/jsrsa
  • + *
  • SHA512withRSA - cryptojs/jsrsa
  • + *
  • RIPEMD160withRSA - cryptojs/jsrsa
  • + *
  • MD5withECDSA - cryptojs/jsrsa
  • + *
  • SHA1withECDSA - cryptojs/jsrsa
  • + *
  • SHA224withECDSA - cryptojs/jsrsa
  • + *
  • SHA256withECDSA - cryptojs/jsrsa
  • + *
  • SHA384withECDSA - cryptojs/jsrsa
  • + *
  • SHA512withECDSA - cryptojs/jsrsa
  • + *
  • RIPEMD160withECDSA - cryptojs/jsrsa
  • + *
  • MD5withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA1withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA224withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA256withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA384withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA512withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • RIPEMD160withRSAandMGF1 - cryptojs/jsrsa
  • + *
  • SHA1withDSA - cryptojs/jsrsa
  • + *
  • SHA224withDSA - cryptojs/jsrsa
  • + *
  • SHA256withDSA - cryptojs/jsrsa
  • + *
+ * Here are supported elliptic cryptographic curve names and their aliases for ECDSA: + *
    + *
  • secp256k1
  • + *
  • secp256r1, NIST P-256, P-256, prime256v1
  • + *
  • secp384r1, NIST P-384, P-384
  • + *
+ * NOTE1: DSA signing algorithm is also supported since crypto 1.1.5. + *

EXAMPLES

+ * @example + * // RSA signature generation + * var sig = new KJUR.crypto.Signature({"alg": "SHA1withRSA"}); + * sig.init(prvKeyPEM); + * sig.updateString('aaa'); + * var hSigVal = sig.sign(); + * + * // DSA signature validation + * var sig2 = new KJUR.crypto.Signature({"alg": "SHA1withDSA"}); + * sig2.init(certPEM); + * sig.updateString('aaa'); + * var isValid = sig2.verify(hSigVal); + * + * // ECDSA signing + * var sig = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'}); + * sig.init(prvKeyPEM); + * sig.updateString('aaa'); + * var sigValueHex = sig.sign(); + * + * // ECDSA verifying + * var sig2 = new KJUR.crypto.Signature({'alg':'SHA1withECDSA'}); + * sig.init(certPEM); + * sig.updateString('aaa'); + * var isValid = sig.verify(sigValueHex); + */ + KJUR.crypto.Signature = function (params) { + var prvKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for signing + var pubKey = null; // RSAKey/KJUR.crypto.{ECDSA,DSA} object for verifying + + var md = null; // KJUR.crypto.MessageDigest object + var sig = null; + var algName = null; + var provName = null; + var algProvName = null; + var mdAlgName = null; + var pubkeyAlgName = null; // rsa,ecdsa,rsaandmgf1(=rsapss) + var state = null; + var pssSaltLen = -1; + var initParams = null; + + var sHashHex = null; // hex hash value for hex + var hDigestInfo = null; + var hPaddedDigestInfo = null; + var hSign = null; + + this._setAlgNames = function () { + if (this.algName.match(/^(.+)with(.+)$/)) { + this.mdAlgName = RegExp.$1.toLowerCase(); + this.pubkeyAlgName = RegExp.$2.toLowerCase(); + } + }; + + this._zeroPaddingOfSignature = function (hex, bitLength) { + var s = ""; + var nZero = bitLength / 4 - hex.length; + for (var i = 0; i < nZero; i++) { + s = s + "0"; + } + return s + hex; + }; + + /** + * set signature algorithm and provider + * @name setAlgAndProvider + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} alg signature algorithm name + * @param {String} prov provider name + * @description + * @example + * md.setAlgAndProvider('SHA1withRSA', 'cryptojs/jsrsa'); + */ + this.setAlgAndProvider = function (alg, prov) { + this._setAlgNames(); + if (prov != 'cryptojs/jsrsa') + throw "provider not supported: " + prov; + + if (':md5:sha1:sha224:sha256:sha384:sha512:ripemd160:'.indexOf(this.mdAlgName) != -1) { + try { + this.md = new KJUR.crypto.MessageDigest({ 'alg': this.mdAlgName }); + } catch (ex) { + throw "setAlgAndProvider hash alg set fail alg=" + + this.mdAlgName + "/" + ex; + } + + this.init = function (keyparam, pass) { + var keyObj = null; + try { + if (pass === undefined) { + keyObj = KEYUTIL.getKey(keyparam); + } else { + keyObj = KEYUTIL.getKey(keyparam, pass); + } + } catch (ex) { + throw "init failed:" + ex; + } + + if (keyObj.isPrivate === true) { + this.prvKey = keyObj; + this.state = "SIGN"; + } else if (keyObj.isPublic === true) { + this.pubKey = keyObj; + this.state = "VERIFY"; + } else { + throw "init failed.:" + keyObj; + } + }; + + this.initSign = function (params) { + if (typeof params['ecprvhex'] == 'string' && + typeof params['eccurvename'] == 'string') { + this.ecprvhex = params['ecprvhex']; + this.eccurvename = params['eccurvename']; + } else { + this.prvKey = params; + } + this.state = "SIGN"; + }; + + this.initVerifyByPublicKey = function (params) { + if (typeof params['ecpubhex'] == 'string' && + typeof params['eccurvename'] == 'string') { + this.ecpubhex = params['ecpubhex']; + this.eccurvename = params['eccurvename']; + } else if (params instanceof KJUR.crypto.ECDSA) { + this.pubKey = params; + } else if (params instanceof RSAKey) { + this.pubKey = params; + } + this.state = "VERIFY"; + }; + + this.initVerifyByCertificatePEM = function (certPEM) { + var x509 = new X509(); + x509.readCertPEM(certPEM); + this.pubKey = x509.subjectPublicKeyRSA; + this.state = "VERIFY"; + }; + + this.updateString = function (str) { + this.md.updateString(str); + }; + this.updateHex = function (hex) { + this.md.updateHex(hex); + }; + + this.sign = function () { + this.sHashHex = this.md.digest(); + if (typeof this.ecprvhex != "undefined" && + typeof this.eccurvename != "undefined") { + var ec = new KJUR.crypto.ECDSA({ 'curve': this.eccurvename }); + this.hSign = ec.signHex(this.sHashHex, this.ecprvhex); + } else if (this.pubkeyAlgName == "rsaandmgf1") { + this.hSign = this.prvKey.signWithMessageHashPSS(this.sHashHex, + this.mdAlgName, + this.pssSaltLen); + } else if (this.pubkeyAlgName == "rsa") { + this.hSign = this.prvKey.signWithMessageHash(this.sHashHex, + this.mdAlgName); + } else if (this.prvKey instanceof KJUR.crypto.ECDSA) { + this.hSign = this.prvKey.signWithMessageHash(this.sHashHex); + } else if (this.prvKey instanceof KJUR.crypto.DSA) { + this.hSign = this.prvKey.signWithMessageHash(this.sHashHex); + } else { + throw "Signature: unsupported public key alg: " + this.pubkeyAlgName; + } + return this.hSign; + }; + this.signString = function (str) { + this.updateString(str); + return this.sign(); + }; + this.signHex = function (hex) { + this.updateHex(hex); + return this.sign(); + }; + this.verify = function (hSigVal) { + this.sHashHex = this.md.digest(); + if (typeof this.ecpubhex != "undefined" && + typeof this.eccurvename != "undefined") { + var ec = new KJUR.crypto.ECDSA({ curve: this.eccurvename }); + return ec.verifyHex(this.sHashHex, hSigVal, this.ecpubhex); + } else if (this.pubkeyAlgName == "rsaandmgf1") { + return this.pubKey.verifyWithMessageHashPSS(this.sHashHex, hSigVal, + this.mdAlgName, + this.pssSaltLen); + } else if (this.pubkeyAlgName == "rsa") { + return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); + } else if (this.pubKey instanceof KJUR.crypto.ECDSA) { + return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); + } else if (this.pubKey instanceof KJUR.crypto.DSA) { + return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); + } else { + throw "Signature: unsupported public key alg: " + this.pubkeyAlgName; + } + }; + } + }; + + /** + * Initialize this object for signing or verifying depends on key + * @name init + * @memberOf KJUR.crypto.Signature + * @function + * @param {Object} key specifying public or private key as plain/encrypted PKCS#5/8 PEM file, certificate PEM or {@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA} object + * @param {String} pass (OPTION) passcode for encrypted private key + * @since crypto 1.1.3 + * @description + * This method is very useful initialize method for Signature class since + * you just specify key then this method will automatically initialize it + * using {@link KEYUTIL.getKey} method. + * As for 'key', following argument type are supported: + *
signing
+ *
    + *
  • PEM formatted PKCS#8 encrypted RSA/ECDSA private key concluding "BEGIN ENCRYPTED PRIVATE KEY"
  • + *
  • PEM formatted PKCS#5 encrypted RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" and ",ENCRYPTED"
  • + *
  • PEM formatted PKCS#8 plain RSA/ECDSA private key concluding "BEGIN PRIVATE KEY"
  • + *
  • PEM formatted PKCS#5 plain RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" without ",ENCRYPTED"
  • + *
  • RSAKey object of private key
  • + *
  • KJUR.crypto.ECDSA object of private key
  • + *
  • KJUR.crypto.DSA object of private key
  • + *
+ *
verification
+ *
    + *
  • PEM formatted PKCS#8 RSA/EC/DSA public key concluding "BEGIN PUBLIC KEY"
  • + *
  • PEM formatted X.509 certificate with RSA/EC/DSA public key concluding + * "BEGIN CERTIFICATE", "BEGIN X509 CERTIFICATE" or "BEGIN TRUSTED CERTIFICATE".
  • + *
  • RSAKey object of public key
  • + *
  • KJUR.crypto.ECDSA object of public key
  • + *
  • KJUR.crypto.DSA object of public key
  • + *
+ * @example + * sig.init(sCertPEM) + */ + this.init = function (key, pass) { + throw "init(key, pass) not supported for this alg:prov=" + + this.algProvName; + }; + + /** + * Initialize this object for verifying with a public key + * @name initVerifyByPublicKey + * @memberOf KJUR.crypto.Signature + * @function + * @param {Object} param RSAKey object of public key or associative array for ECDSA + * @since 1.0.2 + * @deprecated from crypto 1.1.5. please use init() method instead. + * @description + * Public key information will be provided as 'param' parameter and the value will be + * following: + *
    + *
  • {@link RSAKey} object for RSA verification
  • + *
  • associative array for ECDSA verification + * (ex. {'ecpubhex': '041f..', 'eccurvename': 'secp256r1'}) + *
  • + *
+ * @example + * sig.initVerifyByPublicKey(rsaPrvKey) + */ + this.initVerifyByPublicKey = function (rsaPubKey) { + throw "initVerifyByPublicKey(rsaPubKeyy) not supported for this alg:prov=" + + this.algProvName; + }; + + /** + * Initialize this object for verifying with a certficate + * @name initVerifyByCertificatePEM + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} certPEM PEM formatted string of certificate + * @since 1.0.2 + * @deprecated from crypto 1.1.5. please use init() method instead. + * @description + * @example + * sig.initVerifyByCertificatePEM(certPEM) + */ + this.initVerifyByCertificatePEM = function (certPEM) { + throw "initVerifyByCertificatePEM(certPEM) not supported for this alg:prov=" + + this.algProvName; + }; + + /** + * Initialize this object for signing + * @name initSign + * @memberOf KJUR.crypto.Signature + * @function + * @param {Object} param RSAKey object of public key or associative array for ECDSA + * @deprecated from crypto 1.1.5. please use init() method instead. + * @description + * Private key information will be provided as 'param' parameter and the value will be + * following: + *
    + *
  • {@link RSAKey} object for RSA signing
  • + *
  • associative array for ECDSA signing + * (ex. {'ecprvhex': '1d3f..', 'eccurvename': 'secp256r1'})
  • + *
+ * @example + * sig.initSign(prvKey) + */ + this.initSign = function (prvKey) { + throw "initSign(prvKey) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * Updates the data to be signed or verified by a string + * @name updateString + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} str string to use for the update + * @description + * @example + * sig.updateString('aaa') + */ + this.updateString = function (str) { + throw "updateString(str) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * Updates the data to be signed or verified by a hexadecimal string + * @name updateHex + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} hex hexadecimal string to use for the update + * @description + * @example + * sig.updateHex('1f2f3f') + */ + this.updateHex = function (hex) { + throw "updateHex(hex) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * Returns the signature bytes of all data updates as a hexadecimal string + * @name sign + * @memberOf KJUR.crypto.Signature + * @function + * @return the signature bytes as a hexadecimal string + * @description + * @example + * var hSigValue = sig.sign() + */ + this.sign = function () { + throw "sign() not supported for this alg:prov=" + this.algProvName; + }; + + /** + * performs final update on the sign using string, then returns the signature bytes of all data updates as a hexadecimal string + * @name signString + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} str string to final update + * @return the signature bytes of a hexadecimal string + * @description + * @example + * var hSigValue = sig.signString('aaa') + */ + this.signString = function (str) { + throw "digestString(str) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * performs final update on the sign using hexadecimal string, then returns the signature bytes of all data updates as a hexadecimal string + * @name signHex + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} hex hexadecimal string to final update + * @return the signature bytes of a hexadecimal string + * @description + * @example + * var hSigValue = sig.signHex('1fdc33') + */ + this.signHex = function (hex) { + throw "digestHex(hex) not supported for this alg:prov=" + this.algProvName; + }; + + /** + * verifies the passed-in signature. + * @name verify + * @memberOf KJUR.crypto.Signature + * @function + * @param {String} str string to final update + * @return {Boolean} true if the signature was verified, otherwise false + * @description + * @example + * var isValid = sig.verify('1fbcefdca4823a7(snip)') + */ + this.verify = function (hSigVal) { + throw "verify(hSigVal) not supported for this alg:prov=" + this.algProvName; + }; + + this.initParams = params; + + if (params !== undefined) { + if (params['alg'] !== undefined) { + this.algName = params['alg']; + if (params['prov'] === undefined) { + this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; + } else { + this.provName = params['prov']; + } + this.algProvName = this.algName + ":" + this.provName; + this.setAlgAndProvider(this.algName, this.provName); + this._setAlgNames(); + } + + if (params['psssaltlen'] !== undefined) this.pssSaltLen = params['psssaltlen']; + + if (params['prvkeypem'] !== undefined) { + if (params['prvkeypas'] !== undefined) { + throw "both prvkeypem and prvkeypas parameters not supported"; + } else { + try { + var prvKey = new RSAKey(); + prvKey.readPrivateKeyFromPEMString(params['prvkeypem']); + this.initSign(prvKey); + } catch (ex) { + throw "fatal error to load pem private key: " + ex; + } + } + } + } + }; + + /** + * static object for cryptographic function utilities + * @name KJUR.crypto.OID + * @class static object for cryptography related OIDs + * @property {Array} oidhex2name key value of hexadecimal OID and its name + * (ex. '2a8648ce3d030107' and 'secp256r1') + * @since crypto 1.1.3 + * @description + */ + + + KJUR.crypto.OID = new function () { + this.oidhex2name = { + '2a864886f70d010101': 'rsaEncryption', + '2a8648ce3d0201': 'ecPublicKey', + '2a8648ce380401': 'dsa', + '2a8648ce3d030107': 'secp256r1', + '2b8104001f': 'secp192k1', + '2b81040021': 'secp224r1', + '2b8104000a': 'secp256k1', + '2b81040023': 'secp521r1', + '2b81040022': 'secp384r1', + '2a8648ce380403': 'SHA1withDSA', // 1.2.840.10040.4.3 + '608648016503040301': 'SHA224withDSA', // 2.16.840.1.101.3.4.3.1 + '608648016503040302': 'SHA256withDSA', // 2.16.840.1.101.3.4.3.2 + }; + }; + + /*! base64x-1.1.3 (c) 2012-2014 Kenji Urushima | kjur.github.com/jsjws/license + */ + /* + * base64x.js - Base64url and supplementary functions for Tom Wu's base64.js library + * + * version: 1.1.3 (2014 May 25) + * + * Copyright (c) 2012-2014 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * http://kjur.github.com/jsjws/license/ + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + * + * DEPENDS ON: + * - base64.js - Tom Wu's Base64 library + */ + + /** + * Base64URL and supplementary functions for Tom Wu's base64.js library.
+ * This class is just provide information about global functions + * defined in 'base64x.js'. The 'base64x.js' script file provides + * global functions for converting following data each other. + *
    + *
  • (ASCII) String
  • + *
  • UTF8 String including CJK, Latin and other characters
  • + *
  • byte array
  • + *
  • hexadecimal encoded String
  • + *
  • Full URIComponent encoded String (such like "%69%94")
  • + *
  • Base64 encoded String
  • + *
  • Base64URL encoded String
  • + *
+ * All functions in 'base64x.js' are defined in {@link _global_} and not + * in this class. + * + * @class Base64URL and supplementary functions for Tom Wu's base64.js library + * @author Kenji Urushima + * @version 1.1 (07 May 2012) + * @requires base64.js + * @see 'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/ + * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ + */ + function Base64x() { + } + + // ==== string / byte array ================================ + /** + * convert a string to an array of character codes + * @param {String} s + * @return {Array of Numbers} + */ + function stoBA(s) { + var a = new Array(); + for (var i = 0; i < s.length; i++) { + a[i] = s.charCodeAt(i); + } + return a; + } + + /** + * convert an array of character codes to a string + * @param {Array of Numbers} a array of character codes + * @return {String} s + */ + function BAtos(a) { + var s = ""; + for (var i = 0; i < a.length; i++) { + s = s + String.fromCharCode(a[i]); + } + return s; + } + + // ==== byte array / hex ================================ + /** + * convert an array of bytes(Number) to hexadecimal string.
+ * @param {Array of Numbers} a array of bytes + * @return {String} hexadecimal string + */ + function BAtohex(a) { + var s = ""; + for (var i = 0; i < a.length; i++) { + var hex1 = a[i].toString(16); + if (hex1.length == 1) hex1 = "0" + hex1; + s = s + hex1; + } + return s; + } + + // ==== string / hex ================================ + /** + * convert a ASCII string to a hexadecimal string of ASCII codes.
+ * NOTE: This can't be used for non ASCII characters. + * @param {s} s ASCII string + * @return {String} hexadecimal string + */ + function stohex(s) { + return BAtohex(stoBA(s)); + } + + // ==== string / base64 ================================ + /** + * convert a ASCII string to a Base64 encoded string.
+ * NOTE: This can't be used for non ASCII characters. + * @param {s} s ASCII string + * @return {String} Base64 encoded string + */ + function stob64(s) { + return hex2b64(stohex(s)); + } + + // ==== string / base64url ================================ + /** + * convert a ASCII string to a Base64URL encoded string.
+ * NOTE: This can't be used for non ASCII characters. + * @param {s} s ASCII string + * @return {String} Base64URL encoded string + */ + function stob64u(s) { + return b64tob64u(hex2b64(stohex(s))); + } + + /** + * convert a Base64URL encoded string to a ASCII string.
+ * NOTE: This can't be used for Base64URL encoded non ASCII characters. + * @param {s} s Base64URL encoded string + * @return {String} ASCII string + */ + function b64utos(s) { + return BAtos(b64toBA(b64utob64(s))); + } + + // ==== base64 / base64url ================================ + /** + * convert a Base64 encoded string to a Base64URL encoded string.
+ * Example: "ab+c3f/==" → "ab-c3f_" + * @param {String} s Base64 encoded string + * @return {String} Base64URL encoded string + */ + function b64tob64u(s) { + s = s.replace(/\=/g, ""); + s = s.replace(/\+/g, "-"); + s = s.replace(/\//g, "_"); + return s; + } + + /** + * convert a Base64URL encoded string to a Base64 encoded string.
+ * Example: "ab-c3f_" → "ab+c3f/==" + * @param {String} s Base64URL encoded string + * @return {String} Base64 encoded string + */ + function b64utob64(s) { + if (s.length % 4 == 2) s = s + "=="; + else if (s.length % 4 == 3) s = s + "="; + s = s.replace(/-/g, "+"); + s = s.replace(/_/g, "/"); + return s; + } + + // ==== hex / base64url ================================ + /** + * convert a hexadecimal string to a Base64URL encoded string.
+ * @param {String} s hexadecimal string + * @return {String} Base64URL encoded string + */ + function hextob64u(s) { + return b64tob64u(hex2b64(s)); + } + + /** + * convert a Base64URL encoded string to a hexadecimal string.
+ * @param {String} s Base64URL encoded string + * @return {String} hexadecimal string + */ + function b64utohex(s) { + return b64tohex(b64utob64(s)); + } + + var utf8tob64u, b64utoutf8; + + if (typeof Buffer === 'function') { + utf8tob64u = function (s) { + return b64tob64u(new Buffer(s, 'utf8').toString('base64')); + }; + + b64utoutf8 = function (s) { + return new Buffer(b64utob64(s), 'base64').toString('utf8'); + }; + } + else { + // ==== utf8 / base64url ================================ + /** + * convert a UTF-8 encoded string including CJK or Latin to a Base64URL encoded string.
+ * @param {String} s UTF-8 encoded string + * @return {String} Base64URL encoded string + * @since 1.1 + */ + utf8tob64u = function (s) { + return hextob64u(uricmptohex(encodeURIComponentAll(s))); + }; + + /** + * convert a Base64URL encoded string to a UTF-8 encoded string including CJK or Latin.
+ * @param {String} s Base64URL encoded string + * @return {String} UTF-8 encoded string + * @since 1.1 + */ + b64utoutf8 = function (s) { + return decodeURIComponent(hextouricmp(b64utohex(s))); + }; + } + + // ==== utf8 / base64url ================================ + /** + * convert a UTF-8 encoded string including CJK or Latin to a Base64 encoded string.
+ * @param {String} s UTF-8 encoded string + * @return {String} Base64 encoded string + * @since 1.1.1 + */ + function utf8tob64(s) { + return hex2b64(uricmptohex(encodeURIComponentAll(s))); + } + + /** + * convert a Base64 encoded string to a UTF-8 encoded string including CJK or Latin.
+ * @param {String} s Base64 encoded string + * @return {String} UTF-8 encoded string + * @since 1.1.1 + */ + function b64toutf8(s) { + return decodeURIComponent(hextouricmp(b64tohex(s))); + } + + // ==== utf8 / hex ================================ + /** + * convert a UTF-8 encoded string including CJK or Latin to a hexadecimal encoded string.
+ * @param {String} s UTF-8 encoded string + * @return {String} hexadecimal encoded string + * @since 1.1.1 + */ + function utf8tohex(s) { + return uricmptohex(encodeURIComponentAll(s)); + } + + /** + * convert a hexadecimal encoded string to a UTF-8 encoded string including CJK or Latin.
+ * Note that when input is improper hexadecimal string as UTF-8 string, this function returns + * 'null'. + * @param {String} s hexadecimal encoded string + * @return {String} UTF-8 encoded string or null + * @since 1.1.1 + */ + function hextoutf8(s) { + return decodeURIComponent(hextouricmp(s)); + } + + /** + * convert a hexadecimal encoded string to raw string including non printable characters.
+ * @param {String} s hexadecimal encoded string + * @return {String} raw string + * @since 1.1.2 + * @example + * hextorstr("610061") → "a\x00a" + */ + function hextorstr(sHex) { + var s = ""; + for (var i = 0; i < sHex.length - 1; i += 2) { + s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16)); + } + return s; + } + + /** + * convert a raw string including non printable characters to hexadecimal encoded string.
+ * @param {String} s raw string + * @return {String} hexadecimal encoded string + * @since 1.1.2 + * @example + * rstrtohex("a\x00a") → "610061" + */ + function rstrtohex(s) { + var result = ""; + for (var i = 0; i < s.length; i++) { + result += ("0" + s.charCodeAt(i).toString(16)).slice(-2); + } + return result; + } + + // ==== hex / b64nl ======================================= + + /* + * since base64x 1.1.3 + */ + function hextob64(s) { + return hex2b64(s); + } + + /* + * since base64x 1.1.3 + */ + function hextob64nl(s) { + var b64 = hextob64(s); + var b64nl = b64.replace(/(.{64})/g, "$1\r\n"); + b64nl = b64nl.replace(/\r\n$/, ''); + return b64nl; + } + + /* + * since base64x 1.1.3 + */ + function b64nltohex(s) { + var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, ''); + var hex = b64tohex(b64); + return hex; + } + + // ==== URIComponent / hex ================================ + /** + * convert a URLComponent string such like "%67%68" to a hexadecimal string.
+ * @param {String} s URIComponent string such like "%67%68" + * @return {String} hexadecimal string + * @since 1.1 + */ + function uricmptohex(s) { + return s.replace(/%/g, ""); + } + + /** + * convert a hexadecimal string to a URLComponent string such like "%67%68".
+ * @param {String} s hexadecimal string + * @return {String} URIComponent string such like "%67%68" + * @since 1.1 + */ + function hextouricmp(s) { + return s.replace(/(..)/g, "%$1"); + } + + // ==== URIComponent ================================ + /** + * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".
+ * Note that these "0-9A-Za-z!'()*-._~" characters will not + * converted to "%xx" format by builtin 'encodeURIComponent()' function. + * However this 'encodeURIComponentAll()' function will convert + * all of characters into "%xx" format. + * @param {String} s hexadecimal string + * @return {String} URIComponent string such like "%67%68" + * @since 1.1 + */ + function encodeURIComponentAll(u8) { + var s = encodeURIComponent(u8); + var s2 = ""; + for (var i = 0; i < s.length; i++) { + if (s[i] == "%") { + s2 = s2 + s.substr(i, 3); + i = i + 2; + } else { + s2 = s2 + "%" + stohex(s[i]); + } + } + return s2; + } + + // ==== new lines ================================ + /** + * convert all DOS new line("\r\n") to UNIX new line("\n") in + * a String "s". + * @param {String} s string + * @return {String} converted string + */ + function newline_toUnix(s) { + s = s.replace(/\r\n/mg, "\n"); + return s; + } + + /** + * convert all UNIX new line("\r\n") to DOS new line("\n") in + * a String "s". + * @param {String} s string + * @return {String} converted string + */ + function newline_toDos(s) { + s = s.replace(/\r\n/mg, "\n"); + s = s.replace(/\n/mg, "\r\n"); + return s; + } + + /*! Mike Samuel (c) 2009 | code.google.com/p/json-sans-eval + */ + // This source code is free for use in the public domain. + // NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + // http://code.google.com/p/json-sans-eval/ + + /** + * Parses a string of well-formed JSON text. + * + * If the input is not well-formed, then behavior is undefined, but it is + * deterministic and is guaranteed not to modify any object other than its + * return value. + * + * This does not use `eval` so is less likely to have obscure security bugs than + * json2.js. + * It is optimized for speed, so is much faster than json_parse.js. + * + * This library should be used whenever security is a concern (when JSON may + * come from an untrusted source), speed is a concern, and erroring on malformed + * JSON is *not* a concern. + * + * Pros Cons + * +-----------------------+-----------------------+ + * json_sans_eval.js | Fast, secure | Not validating | + * +-----------------------+-----------------------+ + * json_parse.js | Validating, secure | Slow | + * +-----------------------+-----------------------+ + * json2.js | Fast, some validation | Potentially insecure | + * +-----------------------+-----------------------+ + * + * json2.js is very fast, but potentially insecure since it calls `eval` to + * parse JSON data, so an attacker might be able to supply strange JS that + * looks like JSON, but that executes arbitrary javascript. + * If you do have to use json2.js with untrusted data, make sure you keep + * your version of json2.js up to date so that you get patches as they're + * released. + * + * @param {string} json per RFC 4627 + * @param {function (this:Object, string, *):*} opt_reviver optional function + * that reworks JSON objects post-parse per Chapter 15.12 of EcmaScript3.1. + * If supplied, the function is called with a string key, and a value. + * The value is the property of 'this'. The reviver should return + * the value to use in its place. So if dates were serialized as + * {@code { "type": "Date", "time": 1234 }}, then a reviver might look like + * {@code + * function (key, value) { + * if (value && typeof value === 'object' && 'Date' === value.type) { + * return new Date(value.time); + * } else { + * return value; + * } + * }}. + * If the reviver returns {@code undefined} then the property named by key + * will be deleted from its container. + * {@code this} is bound to the object containing the specified property. + * @return {Object|Array} + * @author Mike Samuel + */ + var jsonParse = (function () { + var number + = '(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)'; + var oneChar = '(?:[^\\0-\\x08\\x0a-\\x1f\"\\\\]' + + '|\\\\(?:[\"/\\\\bfnrt]|u[0-9A-Fa-f]{4}))'; + var string = '(?:\"' + oneChar + '*\")'; + + // Will match a value in a well-formed JSON file. + // If the input is not well-formed, may match strangely, but not in an unsafe + // way. + // Since this only matches value tokens, it does not match whitespace, colons, + // or commas. + var jsonToken = new RegExp( + '(?:false|true|null|[\\{\\}\\[\\]]' + + '|' + number + + '|' + string + + ')', 'g'); + + // Matches escape sequences in a string literal + var escapeSequence = new RegExp('\\\\(?:([^u])|u(.{4}))', 'g'); + + // Decodes escape sequences in object literals + var escapes = { + '"': '"', + '/': '/', + '\\': '\\', + 'b': '\b', + 'f': '\f', + 'n': '\n', + 'r': '\r', + 't': '\t' + }; + function unescapeOne(_, ch, hex) { + return ch ? escapes[ch] : String.fromCharCode(parseInt(hex, 16)); + } + + // A non-falsy value that coerces to the empty string when used as a key. + var EMPTY_STRING = new String(''); + var SLASH = '\\'; + + // Constructor to use based on an open token. + var firstTokenCtors = { '{': Object, '[': Array }; + + var hop = Object.hasOwnProperty; + + return function (json, opt_reviver) { + // Split into tokens + var toks = json.match(jsonToken); + // Construct the object to return + var result; + var tok = toks[0]; + var topLevelPrimitive = false; + if ('{' === tok) { + result = {}; + } else if ('[' === tok) { + result = []; + } else { + // The RFC only allows arrays or objects at the top level, but the JSON.parse + // defined by the EcmaScript 5 draft does allow strings, booleans, numbers, and null + // at the top level. + result = []; + topLevelPrimitive = true; + } + + // If undefined, the key in an object key/value record to use for the next + // value parsed. + var key; + // Loop over remaining tokens maintaining a stack of uncompleted objects and + // arrays. + var stack = [result]; + for (var i = 1 - topLevelPrimitive, n = toks.length; i < n; ++i) { + tok = toks[i]; + + var cont; + switch (tok.charCodeAt(0)) { + default: // sign or digit + cont = stack[0]; + cont[key || cont.length] = +(tok); + key = void 0; + break; + case 0x22: // '"' + tok = tok.substring(1, tok.length - 1); + if (tok.indexOf(SLASH) !== -1) { + tok = tok.replace(escapeSequence, unescapeOne); + } + cont = stack[0]; + if (!key) { + if (cont instanceof Array) { + key = cont.length; + } else { + key = tok || EMPTY_STRING; // Use as key for next value seen. + break; + } + } + cont[key] = tok; + key = void 0; + break; + case 0x5b: // '[' + cont = stack[0]; + stack.unshift(cont[key || cont.length] = []); + key = void 0; + break; + case 0x5d: // ']' + stack.shift(); + break; + case 0x66: // 'f' + cont = stack[0]; + cont[key || cont.length] = false; + key = void 0; + break; + case 0x6e: // 'n' + cont = stack[0]; + cont[key || cont.length] = null; + key = void 0; + break; + case 0x74: // 't' + cont = stack[0]; + cont[key || cont.length] = true; + key = void 0; + break; + case 0x7b: // '{' + cont = stack[0]; + stack.unshift(cont[key || cont.length] = {}); + key = void 0; + break; + case 0x7d: // '}' + stack.shift(); + break; + } + } + // Fail if we've got an uncompleted object. + if (topLevelPrimitive) { + if (stack.length !== 1) { throw new Error(); } + result = result[0]; + } else { + if (stack.length) { throw new Error(); } + } + + if (opt_reviver) { + // Based on walk as implemented in http://www.json.org/json2.js + var walk = function (holder, key) { + var value = holder[key]; + if (value && typeof value === 'object') { + var toDelete = null; + for (var k in value) { + if (hop.call(value, k) && value !== holder) { + // Recurse to properties first. This has the effect of causing + // the reviver to be called on the object graph depth-first. + + // Since 'this' is bound to the holder of the property, the + // reviver can access sibling properties of k including ones + // that have not yet been revived. + + // The value returned by the reviver is used in place of the + // current value of property k. + // If it returns undefined then the property is deleted. + var v = walk(value, k); + if (v !== void 0) { + value[k] = v; + } else { + // Deleting properties inside the loop has vaguely defined + // semantics in ES3 and ES3.1. + if (!toDelete) { toDelete = []; } + toDelete.push(k); + } + } + } + if (toDelete) { + for (var i = toDelete.length; --i >= 0;) { + delete value[toDelete[i]]; + } + } + } + return opt_reviver.call(holder, key, value); + }; + result = walk({ '': result }, ''); + } + + return result; + }; + })(); + + /*! jws-3.0.2 (c) 2013 Kenji Urushima | kjur.github.com/jsjws/license + */ + /* + * jws.js - JSON Web Signature Class + * + * version: 3.0.2 (2013 Sep 24) + * + * Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com) + * + * This software is licensed under the terms of the MIT License. + * http://kjur.github.com/jsjws/license/ + * + * The above copyright and license notice shall be + * included in all copies or substantial portions of the Software. + */ + + /** + * @fileOverview + * @name jws-3.0.js + * @author Kenji Urushima kenji.urushima@gmail.com + * @version 3.0.1 (2013-Sep-24) + * @since jsjws 1.0 + * @license MIT License + */ + + if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; + if (typeof KJUR.jws == "undefined" || !KJUR.jws) KJUR.jws = {}; + + /** + * JSON Web Signature(JWS) class.
+ * @name KJUR.jws.JWS + * @class JSON Web Signature(JWS) class + * @property {Dictionary} parsedJWS This property is set after JWS signature verification.
+ * Following "parsedJWS_*" properties can be accessed as "parsedJWS.*" because of + * JsDoc restriction. + * @property {String} parsedJWS_headB64U string of Encrypted JWS Header + * @property {String} parsedJWS_payloadB64U string of Encrypted JWS Payload + * @property {String} parsedJWS_sigvalB64U string of Encrypted JWS signature value + * @property {String} parsedJWS_si string of Signature Input + * @property {String} parsedJWS_sigvalH hexadecimal string of JWS signature value + * @property {String} parsedJWS_sigvalBI BigInteger(defined in jsbn.js) object of JWS signature value + * @property {String} parsedJWS_headS string of decoded JWS Header + * @property {String} parsedJWS_headS string of decoded JWS Payload + * @requires base64x.js, json-sans-eval.js and jsrsasign library + * @see 'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/ + * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ + * @see IETF I-D JSON Web Algorithms (JWA) + * @since jsjws 1.0 + * @description + *

Supported Algorithms

+ * Here is supported algorithm names for {@link KJUR.jws.JWS.sign} and {@link KJUR.jws.JWS.verify} + * methods. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
alg valuespec requirementjsjws support
HS256REQUIREDSUPPORTED
HS384OPTIONALSUPPORTED
HS512OPTIONALSUPPORTED
RS256RECOMMENDEDSUPPORTED
RS384OPTIONALSUPPORTED
RS512OPTIONALSUPPORTED
ES256RECOMMENDED+SUPPORTED
ES384OPTIONALSUPPORTED
ES512OPTIONAL-
PS256OPTIONALSUPPORTED
PS384OPTIONALSUPPORTED
PS512OPTIONALSUPPORTED
noneREQUIREDSUPPORTED
+ * NOTE: HS384 is supported since jsjws 3.0.2 with jsrsasign 4.1.4. + */ + KJUR.jws.JWS = function () { + + // === utility ============================================================= + + /** + * parse JWS string and set public property 'parsedJWS' dictionary.
+ * @name parseJWS + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sJWS JWS signature string to be parsed. + * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". + * @throws if JWS Header is a malformed JSON string. + * @since jws 1.1 + */ + this.parseJWS = function (sJWS, sigValNotNeeded) { + if ((this.parsedJWS !== undefined) && + (sigValNotNeeded || (this.parsedJWS.sigvalH !== undefined))) { + return; + } + if (sJWS.match(/^([^.]+)\.([^.]+)\.([^.]+)$/) == null) { + throw "JWS signature is not a form of 'Head.Payload.SigValue'."; + } + var b6Head = RegExp.$1; + var b6Payload = RegExp.$2; + var b6SigVal = RegExp.$3; + var sSI = b6Head + "." + b6Payload; + this.parsedJWS = {}; + this.parsedJWS.headB64U = b6Head; + this.parsedJWS.payloadB64U = b6Payload; + this.parsedJWS.sigvalB64U = b6SigVal; + this.parsedJWS.si = sSI; + + if (!sigValNotNeeded) { + var hSigVal = b64utohex(b6SigVal); + var biSigVal = parseBigInt(hSigVal, 16); + this.parsedJWS.sigvalH = hSigVal; + this.parsedJWS.sigvalBI = biSigVal; + } + + var sHead = b64utoutf8(b6Head); + var sPayload = b64utoutf8(b6Payload); + this.parsedJWS.headS = sHead; + this.parsedJWS.payloadS = sPayload; + + if (!KJUR.jws.JWS.isSafeJSONString(sHead, this.parsedJWS, 'headP')) + throw "malformed JSON string for JWS Head: " + sHead; + }; + + // ==== JWS Validation ========================================================= + function _getSignatureInputByString(sHead, sPayload) { + return utf8tob64u(sHead) + "." + utf8tob64u(sPayload); + }; + + function _getHashBySignatureInput(sSignatureInput, sHashAlg) { + var hashfunc = function (s) { return KJUR.crypto.Util.hashString(s, sHashAlg); }; + if (hashfunc == null) throw "hash function not defined in jsrsasign: " + sHashAlg; + return hashfunc(sSignatureInput); + }; + + function _jws_verifySignature(sHead, sPayload, hSig, hN, hE) { + var sSignatureInput = _getSignatureInputByString(sHead, sPayload); + var biSig = parseBigInt(hSig, 16); + return _rsasign_verifySignatureWithArgs(sSignatureInput, biSig, hN, hE); + }; + + /** + * verify JWS signature with naked RSA public key.
+ * This only supports "RS256" and "RS512" algorithm. + * @name verifyJWSByNE + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sJWS JWS signature string to be verified + * @param {String} hN hexadecimal string for modulus of RSA public key + * @param {String} hE hexadecimal string for public exponent of RSA public key + * @return {String} returns 1 when JWS signature is valid, otherwise returns 0 + * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". + * @throws if JWS Header is a malformed JSON string. + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} + */ + this.verifyJWSByNE = function (sJWS, hN, hE) { + this.parseJWS(sJWS); + return _rsasign_verifySignatureWithArgs(this.parsedJWS.si, this.parsedJWS.sigvalBI, hN, hE); + }; + + /** + * verify JWS signature with RSA public key.
+ * This only supports "RS256", "RS512", "PS256" and "PS512" algorithms. + * @name verifyJWSByKey + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sJWS JWS signature string to be verified + * @param {RSAKey} key RSA public key + * @return {Boolean} returns true when JWS signature is valid, otherwise returns false + * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". + * @throws if JWS Header is a malformed JSON string. + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} + */ + this.verifyJWSByKey = function (sJWS, key) { + this.parseJWS(sJWS); + var hashAlg = _jws_getHashAlgFromParsedHead(this.parsedJWS.headP); + var isPSS = this.parsedJWS.headP['alg'].substr(0, 2) == "PS"; + + if (key.hashAndVerify) { + return key.hashAndVerify(hashAlg, + new Buffer(this.parsedJWS.si, 'utf8').toString('base64'), + b64utob64(this.parsedJWS.sigvalB64U), + 'base64', + isPSS); + } else if (isPSS) { + return key.verifyStringPSS(this.parsedJWS.si, + this.parsedJWS.sigvalH, hashAlg); + } else { + return key.verifyString(this.parsedJWS.si, + this.parsedJWS.sigvalH); + } + }; + + /** + * verify JWS signature by PEM formatted X.509 certificate.
+ * This only supports "RS256" and "RS512" algorithm. + * @name verifyJWSByPemX509Cert + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sJWS JWS signature string to be verified + * @param {String} sPemX509Cert string of PEM formatted X.509 certificate + * @return {String} returns 1 when JWS signature is valid, otherwise returns 0 + * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". + * @throws if JWS Header is a malformed JSON string. + * @since 1.1 + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} + */ + this.verifyJWSByPemX509Cert = function (sJWS, sPemX509Cert) { + this.parseJWS(sJWS); + var x509 = new X509(); + x509.readCertPEM(sPemX509Cert); + return x509.subjectPublicKeyRSA.verifyString(this.parsedJWS.si, this.parsedJWS.sigvalH); + }; + + // ==== JWS Generation ========================================================= + function _jws_getHashAlgFromParsedHead(head) { + var sigAlg = head["alg"]; + var hashAlg = ""; + + if (sigAlg != "RS256" && sigAlg != "RS512" && + sigAlg != "PS256" && sigAlg != "PS512") + throw "JWS signature algorithm not supported: " + sigAlg; + if (sigAlg.substr(2) == "256") hashAlg = "sha256"; + if (sigAlg.substr(2) == "512") hashAlg = "sha512"; + return hashAlg; + }; + + function _jws_getHashAlgFromHead(sHead) { + return _jws_getHashAlgFromParsedHead(jsonParse(sHead)); + }; + + function _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD) { + var rsa = new RSAKey(); + rsa.setPrivate(hN, hE, hD); + + var hashAlg = _jws_getHashAlgFromHead(sHead); + var sigValue = rsa.signString(sSI, hashAlg); + return sigValue; + }; + + function _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, head) { + var hashAlg = null; + if (typeof head == "undefined") { + hashAlg = _jws_getHashAlgFromHead(sHead); + } else { + hashAlg = _jws_getHashAlgFromParsedHead(head); + } + + var isPSS = head['alg'].substr(0, 2) == "PS"; + + if (key.hashAndSign) { + return b64tob64u(key.hashAndSign(hashAlg, sSI, 'binary', 'base64', isPSS)); + } else if (isPSS) { + return hextob64u(key.signStringPSS(sSI, hashAlg)); + } else { + return hextob64u(key.signString(sSI, hashAlg)); + } + }; + + function _jws_generateSignatureValueByNED(sHead, sPayload, hN, hE, hD) { + var sSI = _getSignatureInputByString(sHead, sPayload); + return _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD); + }; + + /** + * generate JWS signature by Header, Payload and a naked RSA private key.
+ * This only supports "RS256" and "RS512" algorithm. + * @name generateJWSByNED + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sHead string of JWS Header + * @param {String} sPayload string of JWS Payload + * @param {String} hN hexadecimal string for modulus of RSA public key + * @param {String} hE hexadecimal string for public exponent of RSA public key + * @param {String} hD hexadecimal string for private exponent of RSA private key + * @return {String} JWS signature string + * @throws if sHead is a malformed JSON string. + * @throws if supported signature algorithm was not specified in JSON Header. + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} + */ + this.generateJWSByNED = function (sHead, sPayload, hN, hE, hD) { + if (!KJUR.jws.JWS.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead; + var sSI = _getSignatureInputByString(sHead, sPayload); + var hSigValue = _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD); + var b64SigValue = hextob64u(hSigValue); + + this.parsedJWS = {}; + this.parsedJWS.headB64U = sSI.split(".")[0]; + this.parsedJWS.payloadB64U = sSI.split(".")[1]; + this.parsedJWS.sigvalB64U = b64SigValue; + + return sSI + "." + b64SigValue; + }; + + /** + * generate JWS signature by Header, Payload and a RSA private key.
+ * This only supports "RS256", "RS512", "PS256" and "PS512" algorithms. + * @name generateJWSByKey + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sHead string of JWS Header + * @param {String} sPayload string of JWS Payload + * @param {RSAKey} RSA private key + * @return {String} JWS signature string + * @throws if sHead is a malformed JSON string. + * @throws if supported signature algorithm was not specified in JSON Header. + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} + */ + this.generateJWSByKey = function (sHead, sPayload, key) { + var obj = {}; + if (!KJUR.jws.JWS.isSafeJSONString(sHead, obj, 'headP')) + throw "JWS Head is not safe JSON string: " + sHead; + var sSI = _getSignatureInputByString(sHead, sPayload); + var b64SigValue = _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, obj.headP); + + this.parsedJWS = {}; + this.parsedJWS.headB64U = sSI.split(".")[0]; + this.parsedJWS.payloadB64U = sSI.split(".")[1]; + this.parsedJWS.sigvalB64U = b64SigValue; + + return sSI + "." + b64SigValue; + }; + + // === sign with PKCS#1 RSA private key ===================================================== + function _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey) { + var rsa = new RSAKey(); + rsa.readPrivateKeyFromPEMString(sPemPrvKey); + var hashAlg = _jws_getHashAlgFromHead(sHead); + var sigValue = rsa.signString(sSI, hashAlg); + return sigValue; + }; + + /** + * generate JWS signature by Header, Payload and a PEM formatted PKCS#1 RSA private key.
+ * This only supports "RS256" and "RS512" algorithm. + * @name generateJWSByP1PrvKey + * @memberOf KJUR.jws.JWS + * @function + * @param {String} sHead string of JWS Header + * @param {String} sPayload string of JWS Payload + * @param {String} string for sPemPrvKey PEM formatted PKCS#1 RSA private key
+ * Heading and trailing space characters in PEM key will be ignored. + * @return {String} JWS signature string + * @throws if sHead is a malformed JSON string. + * @throws if supported signature algorithm was not specified in JSON Header. + * @since 1.1 + * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} + */ + this.generateJWSByP1PrvKey = function (sHead, sPayload, sPemPrvKey) { + if (!KJUR.jws.JWS.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead; + var sSI = _getSignatureInputByString(sHead, sPayload); + var hSigValue = _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey); + var b64SigValue = hextob64u(hSigValue); + + this.parsedJWS = {}; + this.parsedJWS.headB64U = sSI.split(".")[0]; + this.parsedJWS.payloadB64U = sSI.split(".")[1]; + this.parsedJWS.sigvalB64U = b64SigValue; + + return sSI + "." + b64SigValue; + }; + }; + + // === major static method ======================================================== + + /** + * generate JWS signature by specified key
+ * @name sign + * @memberOf KJUR.jws.JWS + * @function + * @static + * @param {String} alg JWS algorithm name to sign and force set to sHead or null + * @param {String} sHead string of JWS Header + * @param {String} sPayload string of JWS Payload + * @param {String} key string of private key or key object to sign + * @param {String} pass (OPTION)passcode to use encrypted private key + * @return {String} JWS signature string + * @since jws 3.0.0 + * @see jsrsasign KJUR.crypto.Signature method + * @see jsrsasign KJUR.crypto.Mac method + * @description + * This method supports following algorithms. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
alg valuespec requirementjsjws support
HS256REQUIREDSUPPORTED
HS384OPTIONAL-
HS512OPTIONALSUPPORTED
RS256RECOMMENDEDSUPPORTED
RS384OPTIONALSUPPORTED
RS512OPTIONALSUPPORTED
ES256RECOMMENDED+SUPPORTED
ES384OPTIONALSUPPORTED
ES512OPTIONAL-
PS256OPTIONALSUPPORTED
PS384OPTIONALSUPPORTED
PS512OPTIONALSUPPORTED
noneREQUIREDSUPPORTED
+ *
+ *
NOTE1: + *
salt length of RSAPSS signature is the same as the hash algorithm length + * because of IETF JOSE ML discussion. + *
NOTE2: + *
The reason of HS384 unsupport is + * CryptoJS HmacSHA384 bug. + *
+ */ + KJUR.jws.JWS.sign = function (alg, sHeader, sPayload, key, pass) { + var ns1 = KJUR.jws.JWS; + + if (!ns1.isSafeJSONString(sHeader)) + throw "JWS Head is not safe JSON string: " + sHead; + + var pHeader = ns1.readSafeJSONString(sHeader); + + // 1. use alg if defined in sHeader + if ((alg == '' || alg == null) && + pHeader['alg'] !== undefined) { + alg = pHeader['alg']; + } + + // 2. set alg in sHeader if undefined + if ((alg != '' && alg != null) && + pHeader['alg'] === undefined) { + pHeader['alg'] = alg; + sHeader = JSON.stringify(pHeader); + } + + // 3. set signature algorithm like SHA1withRSA + var sigAlg = null; + if (ns1.jwsalg2sigalg[alg] === undefined) { + throw "unsupported alg name: " + alg; + } else { + sigAlg = ns1.jwsalg2sigalg[alg]; + } + + var uHeader = utf8tob64u(sHeader); + var uPayload = utf8tob64u(sPayload); + var uSignatureInput = uHeader + "." + uPayload + + // 4. sign + var hSig = ""; + if (sigAlg.substr(0, 4) == "Hmac") { + if (key === undefined) + throw "hexadecimal key shall be specified for HMAC"; + var mac = new KJUR.crypto.Mac({ 'alg': sigAlg, 'pass': hextorstr(key) }); + mac.updateString(uSignatureInput); + hSig = mac.doFinal(); + } else if (sigAlg.indexOf("withECDSA") != -1) { + var sig = new KJUR.crypto.Signature({ 'alg': sigAlg }); + sig.init(key, pass); + sig.updateString(uSignatureInput); + hASN1Sig = sig.sign(); + hSig = KJUR.crypto.ECDSA.asn1SigToConcatSig(hASN1Sig); + } else if (sigAlg != "none") { + var sig = new KJUR.crypto.Signature({ 'alg': sigAlg }); + sig.init(key, pass); + sig.updateString(uSignatureInput); + hSig = sig.sign(); + } + + var uSig = hextob64u(hSig); + return uSignatureInput + "." + uSig; + }; + + /** + * verify JWS signature by specified key or certificate
+ * @name verify + * @memberOf KJUR.jws.JWS + * @function + * @static + * @param {String} sJWS string of JWS signature to verify + * @param {String} key string of public key, certificate or key object to verify + * @return {Boolean} true if the signature is valid otherwise false + * @since jws 3.0.0 + * @see jsrsasign KJUR.crypto.Signature method + * @see jsrsasign KJUR.crypto.Mac method + */ + KJUR.jws.JWS.verify = function (sJWS, key) { + var jws = KJUR.jws.JWS; + var a = sJWS.split("."); + var uHeader = a[0]; + var uPayload = a[1]; + var uSignatureInput = uHeader + "." + uPayload; + var hSig = b64utohex(a[2]); + + var pHeader = jws.readSafeJSONString(b64utoutf8(a[0])); + var alg = null; + if (pHeader.alg === undefined) { + throw "algorithm not specified in header"; + } else { + alg = pHeader.alg; + } + + var sigAlg = null; + if (jws.jwsalg2sigalg[pHeader.alg] === undefined) { + throw "unsupported alg name: " + alg; + } else { + sigAlg = jws.jwsalg2sigalg[alg]; + } + + // x. verify + if (sigAlg == "none") { + return true; + } else if (sigAlg.substr(0, 4) == "Hmac") { + if (key === undefined) + throw "hexadecimal key shall be specified for HMAC"; + var mac = new KJUR.crypto.Mac({ 'alg': sigAlg, 'pass': hextorstr(key) }); + mac.updateString(uSignatureInput); + hSig2 = mac.doFinal(); + return hSig == hSig2; + } else if (sigAlg.indexOf("withECDSA") != -1) { + var hASN1Sig = null; + try { + hASN1Sig = KJUR.crypto.ECDSA.concatSigToASN1Sig(hSig); + } catch (ex) { + return false; + } + var sig = new KJUR.crypto.Signature({ 'alg': sigAlg }); + sig.init(key) + sig.updateString(uSignatureInput); + return sig.verify(hASN1Sig); + } else { + var sig = new KJUR.crypto.Signature({ 'alg': sigAlg }); + sig.init(key) + sig.updateString(uSignatureInput); + return sig.verify(hSig); + } + }; + + /* + * @since jws 3.0.0 + */ + KJUR.jws.JWS.jwsalg2sigalg = { + "HS256": "HmacSHA256", + //"HS384": "HmacSHA384", // unsupported because of CryptoJS bug + "HS512": "HmacSHA512", + "RS256": "SHA256withRSA", + "RS384": "SHA384withRSA", + "RS512": "SHA512withRSA", + "ES256": "SHA256withECDSA", + "ES384": "SHA384withECDSA", + //"ES512": "SHA512withECDSA", // unsupported because of jsrsasign's bug + "PS256": "SHA256withRSAandMGF1", + "PS384": "SHA384withRSAandMGF1", + "PS512": "SHA512withRSAandMGF1", + "none": "none", + }; + + // === utility static method ====================================================== + + /** + * check whether a String "s" is a safe JSON string or not.
+ * If a String "s" is a malformed JSON string or an other object type + * this returns 0, otherwise this returns 1. + * @name isSafeJSONString + * @memberOf KJUR.jws.JWS + * @function + * @static + * @param {String} s JSON string + * @return {Number} 1 or 0 + */ + KJUR.jws.JWS.isSafeJSONString = function (s, h, p) { + var o = null; + try { + o = jsonParse(s); + if (typeof o != "object") return 0; + if (o.constructor === Array) return 0; + if (h) h[p] = o; + return 1; + } catch (ex) { + return 0; + } + }; + + /** + * read a String "s" as JSON object if it is safe.
+ * If a String "s" is a malformed JSON string or not JSON string, + * this returns null, otherwise returns JSON object. + * @name readSafeJSONString + * @memberOf KJUR.jws.JWS + * @function + * @static + * @param {String} s JSON string + * @return {Object} JSON object or null + * @since 1.1.1 + */ + KJUR.jws.JWS.readSafeJSONString = function (s) { + var o = null; try { - if (pass === undefined) { - keyObj = KEYUTIL.getKey(keyparam); - } else { - keyObj = KEYUTIL.getKey(keyparam, pass); - } + o = jsonParse(s); + if (typeof o != "object") return null; + if (o.constructor === Array) return null; + return o; } catch (ex) { - throw "init failed:" + ex; + return null; + } + }; + + /** + * get Encoed Signature Value from JWS string.
+ * @name getEncodedSignatureValueFromJWS + * @memberOf KJUR.jws.JWS + * @function + * @static + * @param {String} sJWS JWS signature string to be verified + * @return {String} string of Encoded Signature Value + * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". + */ + KJUR.jws.JWS.getEncodedSignatureValueFromJWS = function (sJWS) { + if (sJWS.match(/^[^.]+\.[^.]+\.([^.]+)$/) == null) { + throw "JWS signature is not a form of 'Head.Payload.SigValue'."; + } + return RegExp.$1; + }; + + /** + * IntDate class for time representation for JSON Web Token(JWT) + * @class KJUR.jws.IntDate class + * @name KJUR.jws.IntDate + * @since jws 3.0.1 + * @description + * Utility class for IntDate which is integer representation of UNIX origin time + * used in JSON Web Token(JWT). + */ + KJUR.jws.IntDate = function () { + }; + + /** + * @name get + * @memberOf KJUR.jws.IntDate + * @function + * @static + * @param {String} s string of time representation + * @return {Integer} UNIX origin time in seconds for argument 's' + * @since jws 3.0.1 + * @throws "unsupported format: s" when malformed format + * @description + * This method will accept following representation of time. + *
    + *
  • now - current time
  • + *
  • now + 1hour - after 1 hour from now
  • + *
  • now + 1day - after 1 day from now
  • + *
  • now + 1month - after 30 days from now
  • + *
  • now + 1year - after 365 days from now
  • + *
  • YYYYmmDDHHMMSSZ - UTC time (ex. 20130828235959Z)
  • + *
  • number - UNIX origin time (seconds from 1970-01-01 00:00:00) (ex. 1377714748)
  • + *
+ */ + KJUR.jws.IntDate.get = function (s) { + if (s == "now") { + return KJUR.jws.IntDate.getNow(); + } else if (s == "now + 1hour") { + return KJUR.jws.IntDate.getNow() + 60 * 60; + } else if (s == "now + 1day") { + return KJUR.jws.IntDate.getNow() + 60 * 60 * 24; + } else if (s == "now + 1month") { + return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 30; + } else if (s == "now + 1year") { + return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 365; + } else if (s.match(/Z$/)) { + return KJUR.jws.IntDate.getZulu(s); + } else if (s.match(/^[0-9]+$/)) { + return parseInt(s); + } + throw "unsupported format: " + s; + }; + + KJUR.jws.IntDate.getZulu = function (s) { + if (a = s.match(/(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)Z/)) { + var year = parseInt(RegExp.$1); + var month = parseInt(RegExp.$2) - 1; + var day = parseInt(RegExp.$3); + var hour = parseInt(RegExp.$4); + var min = parseInt(RegExp.$5); + var sec = parseInt(RegExp.$6); + var d = new Date(Date.UTC(year, month, day, hour, min, sec)); + return ~~(d / 1000); + } + throw "unsupported format: " + s; + }; + + /* + * @since jws 3.0.1 + */ + KJUR.jws.IntDate.getNow = function () { + var d = ~~(new Date() / 1000); + return d; + }; + + /* + * @since jws 3.0.1 + */ + KJUR.jws.IntDate.intDate2UTCString = function (intDate) { + var d = new Date(intDate * 1000); + return d.toUTCString(); + }; + + /* + * @since jws 3.0.1 + */ + KJUR.jws.IntDate.intDate2Zulu = function (intDate) { + var d = new Date(intDate * 1000); + var year = ("0000" + d.getUTCFullYear()).slice(-4); + var mon = ("00" + (d.getUTCMonth() + 1)).slice(-2); + var day = ("00" + d.getUTCDate()).slice(-2); + var hour = ("00" + d.getUTCHours()).slice(-2); + var min = ("00" + d.getUTCMinutes()).slice(-2); + var sec = ("00" + d.getUTCSeconds()).slice(-2); + return year + mon + day + hour + min + sec + "Z"; + }; + + /*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE + * @version 3.0.2 + */ + + (function () { + "use strict"; + function lib$es6$promise$utils$$objectOrFunction(x) { + return typeof x === 'function' || (typeof x === 'object' && x !== null); + } + + function lib$es6$promise$utils$$isFunction(x) { + return typeof x === 'function'; + } + + function lib$es6$promise$utils$$isMaybeThenable(x) { + return typeof x === 'object' && x !== null; + } + + var lib$es6$promise$utils$$_isArray; + if (!Array.isArray) { + lib$es6$promise$utils$$_isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + } else { + lib$es6$promise$utils$$_isArray = Array.isArray; + } + + var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray; + var lib$es6$promise$asap$$len = 0; + var lib$es6$promise$asap$$toString = {}.toString; + var lib$es6$promise$asap$$vertxNext; + var lib$es6$promise$asap$$customSchedulerFn; + + var lib$es6$promise$asap$$asap = function asap(callback, arg) { + lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback; + lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg; + lib$es6$promise$asap$$len += 2; + if (lib$es6$promise$asap$$len === 2) { + // If len is 2, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + if (lib$es6$promise$asap$$customSchedulerFn) { + lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush); + } else { + lib$es6$promise$asap$$scheduleFlush(); + } + } + } + + function lib$es6$promise$asap$$setScheduler(scheduleFn) { + lib$es6$promise$asap$$customSchedulerFn = scheduleFn; + } + + function lib$es6$promise$asap$$setAsap(asapFn) { + lib$es6$promise$asap$$asap = asapFn; + } + + var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined; + var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {}; + var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver; + var lib$es6$promise$asap$$isNode = typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; + + // test for web worker but not in IE10 + var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; + + // node + function lib$es6$promise$asap$$useNextTick() { + // node version 0.10.x displays a deprecation warning when nextTick is used recursively + // see https://github.com/cujojs/when/issues/410 for details + return function () { + process.nextTick(lib$es6$promise$asap$$flush); + }; + } + + // vertx + function lib$es6$promise$asap$$useVertxTimer() { + return function () { + lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush); + }; + } + + function lib$es6$promise$asap$$useMutationObserver() { + var iterations = 0; + var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function () { + node.data = (iterations = ++iterations % 2); + }; + } + + // web worker + function lib$es6$promise$asap$$useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = lib$es6$promise$asap$$flush; + return function () { + channel.port2.postMessage(0); + }; + } + + function lib$es6$promise$asap$$useSetTimeout() { + return function () { + setTimeout(lib$es6$promise$asap$$flush, 1); + }; + } + + var lib$es6$promise$asap$$queue = new Array(1000); + function lib$es6$promise$asap$$flush() { + for (var i = 0; i < lib$es6$promise$asap$$len; i += 2) { + var callback = lib$es6$promise$asap$$queue[i]; + var arg = lib$es6$promise$asap$$queue[i + 1]; + + callback(arg); + + lib$es6$promise$asap$$queue[i] = undefined; + lib$es6$promise$asap$$queue[i + 1] = undefined; + } + + lib$es6$promise$asap$$len = 0; + } + + function lib$es6$promise$asap$$attemptVertx() { + try { + var r = require; + var vertx = r('vertx'); + lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext; + return lib$es6$promise$asap$$useVertxTimer(); + } catch (e) { + return lib$es6$promise$asap$$useSetTimeout(); + } + } + + var lib$es6$promise$asap$$scheduleFlush; + // Decide what async method to use to triggering processing of queued callbacks: + if (lib$es6$promise$asap$$isNode) { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick(); + } else if (lib$es6$promise$asap$$BrowserMutationObserver) { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver(); + } else if (lib$es6$promise$asap$$isWorker) { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel(); + } else if (lib$es6$promise$asap$$browserWindow === undefined && typeof require === 'function') { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertx(); + } else { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout(); + } + + function lib$es6$promise$$internal$$noop() { } + + var lib$es6$promise$$internal$$PENDING = void 0; + var lib$es6$promise$$internal$$FULFILLED = 1; + var lib$es6$promise$$internal$$REJECTED = 2; + + var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject(); + + function lib$es6$promise$$internal$$selfFulfillment() { + return new TypeError("You cannot resolve a promise with itself"); + } + + function lib$es6$promise$$internal$$cannotReturnOwn() { + return new TypeError('A promises callback cannot return that same promise.'); + } + + function lib$es6$promise$$internal$$getThen(promise) { + try { + return promise.then; + } catch (error) { + lib$es6$promise$$internal$$GET_THEN_ERROR.error = error; + return lib$es6$promise$$internal$$GET_THEN_ERROR; + } + } + + function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) { + try { + then.call(value, fulfillmentHandler, rejectionHandler); + } catch (e) { + return e; + } + } + + function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) { + lib$es6$promise$asap$$asap(function (promise) { + var sealed = false; + var error = lib$es6$promise$$internal$$tryThen(then, thenable, function (value) { + if (sealed) { return; } + sealed = true; + if (thenable !== value) { + lib$es6$promise$$internal$$resolve(promise, value); + } else { + lib$es6$promise$$internal$$fulfill(promise, value); + } + }, function (reason) { + if (sealed) { return; } + sealed = true; + + lib$es6$promise$$internal$$reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + lib$es6$promise$$internal$$reject(promise, error); + } + }, promise); + } + + function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) { + if (thenable._state === lib$es6$promise$$internal$$FULFILLED) { + lib$es6$promise$$internal$$fulfill(promise, thenable._result); + } else if (thenable._state === lib$es6$promise$$internal$$REJECTED) { + lib$es6$promise$$internal$$reject(promise, thenable._result); + } else { + lib$es6$promise$$internal$$subscribe(thenable, undefined, function (value) { + lib$es6$promise$$internal$$resolve(promise, value); + }, function (reason) { + lib$es6$promise$$internal$$reject(promise, reason); + }); + } + } + + function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable) { + if (maybeThenable.constructor === promise.constructor) { + lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable); + } else { + var then = lib$es6$promise$$internal$$getThen(maybeThenable); + + if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) { + lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error); + } else if (then === undefined) { + lib$es6$promise$$internal$$fulfill(promise, maybeThenable); + } else if (lib$es6$promise$utils$$isFunction(then)) { + lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then); + } else { + lib$es6$promise$$internal$$fulfill(promise, maybeThenable); + } + } + } + + function lib$es6$promise$$internal$$resolve(promise, value) { + if (promise === value) { + lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFulfillment()); + } else if (lib$es6$promise$utils$$objectOrFunction(value)) { + lib$es6$promise$$internal$$handleMaybeThenable(promise, value); + } else { + lib$es6$promise$$internal$$fulfill(promise, value); + } + } + + function lib$es6$promise$$internal$$publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + lib$es6$promise$$internal$$publish(promise); + } + + function lib$es6$promise$$internal$$fulfill(promise, value) { + if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } + + promise._result = value; + promise._state = lib$es6$promise$$internal$$FULFILLED; + + if (promise._subscribers.length !== 0) { + lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, promise); + } + } + + function lib$es6$promise$$internal$$reject(promise, reason) { + if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } + promise._state = lib$es6$promise$$internal$$REJECTED; + promise._result = reason; + + lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publishRejection, promise); + } + + function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) { + var subscribers = parent._subscribers; + var length = subscribers.length; + + parent._onerror = null; + + subscribers[length] = child; + subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment; + subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection; + + if (length === 0 && parent._state) { + lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, parent); + } + } + + function lib$es6$promise$$internal$$publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (subscribers.length === 0) { return; } + + var child, callback, detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; + } + + function lib$es6$promise$$internal$$ErrorObject() { + this.error = null; + } + + var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject(); + + function lib$es6$promise$$internal$$tryCatch(callback, detail) { + try { + return callback(detail); + } catch (e) { + lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e; + return lib$es6$promise$$internal$$TRY_CATCH_ERROR; + } + } + + function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) { + var hasCallback = lib$es6$promise$utils$$isFunction(callback), + value, error, succeeded, failed; + + if (hasCallback) { + value = lib$es6$promise$$internal$$tryCatch(callback, detail); + + if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value = null; + } else { + succeeded = true; + } + + if (promise === value) { + lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn()); + return; + } + + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== lib$es6$promise$$internal$$PENDING) { + // noop + } else if (hasCallback && succeeded) { + lib$es6$promise$$internal$$resolve(promise, value); + } else if (failed) { + lib$es6$promise$$internal$$reject(promise, error); + } else if (settled === lib$es6$promise$$internal$$FULFILLED) { + lib$es6$promise$$internal$$fulfill(promise, value); + } else if (settled === lib$es6$promise$$internal$$REJECTED) { + lib$es6$promise$$internal$$reject(promise, value); + } + } + + function lib$es6$promise$$internal$$initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value) { + lib$es6$promise$$internal$$resolve(promise, value); + }, function rejectPromise(reason) { + lib$es6$promise$$internal$$reject(promise, reason); + }); + } catch (e) { + lib$es6$promise$$internal$$reject(promise, e); + } + } + + function lib$es6$promise$enumerator$$Enumerator(Constructor, input) { + var enumerator = this; + + enumerator._instanceConstructor = Constructor; + enumerator.promise = new Constructor(lib$es6$promise$$internal$$noop); + + if (enumerator._validateInput(input)) { + enumerator._input = input; + enumerator.length = input.length; + enumerator._remaining = input.length; + + enumerator._init(); + + if (enumerator.length === 0) { + lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); + } else { + enumerator.length = enumerator.length || 0; + enumerator._enumerate(); + if (enumerator._remaining === 0) { + lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); + } + } + } else { + lib$es6$promise$$internal$$reject(enumerator.promise, enumerator._validationError()); + } + } + + lib$es6$promise$enumerator$$Enumerator.prototype._validateInput = function (input) { + return lib$es6$promise$utils$$isArray(input); + }; + + lib$es6$promise$enumerator$$Enumerator.prototype._validationError = function () { + return new Error('Array Methods must be provided an Array'); + }; + + lib$es6$promise$enumerator$$Enumerator.prototype._init = function () { + this._result = new Array(this.length); + }; + + var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator; + + lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function () { + var enumerator = this; + + var length = enumerator.length; + var promise = enumerator.promise; + var input = enumerator._input; + + for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { + enumerator._eachEntry(input[i], i); + } + }; + + lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function (entry, i) { + var enumerator = this; + var c = enumerator._instanceConstructor; + + if (lib$es6$promise$utils$$isMaybeThenable(entry)) { + if (entry.constructor === c && entry._state !== lib$es6$promise$$internal$$PENDING) { + entry._onerror = null; + enumerator._settledAt(entry._state, i, entry._result); + } else { + enumerator._willSettleAt(c.resolve(entry), i); + } + } else { + enumerator._remaining--; + enumerator._result[i] = entry; + } + }; + + lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function (state, i, value) { + var enumerator = this; + var promise = enumerator.promise; + + if (promise._state === lib$es6$promise$$internal$$PENDING) { + enumerator._remaining--; + + if (state === lib$es6$promise$$internal$$REJECTED) { + lib$es6$promise$$internal$$reject(promise, value); + } else { + enumerator._result[i] = value; + } + } + + if (enumerator._remaining === 0) { + lib$es6$promise$$internal$$fulfill(promise, enumerator._result); + } + }; + + lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function (promise, i) { + var enumerator = this; + + lib$es6$promise$$internal$$subscribe(promise, undefined, function (value) { + enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value); + }, function (reason) { + enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason); + }); + }; + function lib$es6$promise$promise$all$$all(entries) { + return new lib$es6$promise$enumerator$$default(this, entries).promise; + } + var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all; + function lib$es6$promise$promise$race$$race(entries) { + /*jshint validthis:true */ + var Constructor = this; + + var promise = new Constructor(lib$es6$promise$$internal$$noop); + + if (!lib$es6$promise$utils$$isArray(entries)) { + lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.')); + return promise; + } + + var length = entries.length; + + function onFulfillment(value) { + lib$es6$promise$$internal$$resolve(promise, value); + } + + function onRejection(reason) { + lib$es6$promise$$internal$$reject(promise, reason); + } + + for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { + lib$es6$promise$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); + } + + return promise; + } + var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race; + function lib$es6$promise$promise$resolve$$resolve(object) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(lib$es6$promise$$internal$$noop); + lib$es6$promise$$internal$$resolve(promise, object); + return promise; + } + var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve; + function lib$es6$promise$promise$reject$$reject(reason) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(lib$es6$promise$$internal$$noop); + lib$es6$promise$$internal$$reject(promise, reason); + return promise; + } + var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject; + + var lib$es6$promise$promise$$counter = 0; + + function lib$es6$promise$promise$$needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); + } + + function lib$es6$promise$promise$$needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); + } + + var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise; + /** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise's eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + var promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + var xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class Promise + @param {function} resolver + Useful for tooling. + @constructor + */ + function lib$es6$promise$promise$$Promise(resolver) { + this._id = lib$es6$promise$promise$$counter++; + this._state = undefined; + this._result = undefined; + this._subscribers = []; + + if (lib$es6$promise$$internal$$noop !== resolver) { + if (!lib$es6$promise$utils$$isFunction(resolver)) { + lib$es6$promise$promise$$needsResolver(); + } + + if (!(this instanceof lib$es6$promise$promise$$Promise)) { + lib$es6$promise$promise$$needsNew(); + } + + lib$es6$promise$$internal$$initializePromise(this, resolver); + } + } + + lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default; + lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default; + lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default; + lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default; + lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler; + lib$es6$promise$promise$$Promise._setAsap = lib$es6$promise$asap$$setAsap; + lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$asap; + + lib$es6$promise$promise$$Promise.prototype = { + constructor: lib$es6$promise$promise$$Promise, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + var result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + var author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + then: function (onFulfillment, onRejection) { + var parent = this; + var state = parent._state; + + if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) { + return this; + } + + var child = new this.constructor(lib$es6$promise$$internal$$noop); + var result = parent._result; + + if (state) { + var callback = arguments[state - 1]; + lib$es6$promise$asap$$asap(function () { + lib$es6$promise$$internal$$invokeCallback(state, child, callback, result); + }); + } else { + lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection); + } + + return child; + }, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + Useful for tooling. + @return {Promise} + */ + 'catch': function (onRejection) { + return this.then(null, onRejection); + } + }; + function lib$es6$promise$polyfill$$polyfill() { + var local; + + if (typeof global !== 'undefined') { + local = global; + } else if (typeof self !== 'undefined') { + local = self; + } else { + try { + local = Function('return this')(); + } catch (e) { + throw new Error('polyfill failed because global object is unavailable in this environment'); + } + } + + var P = local.Promise; + + if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) { + return; + } + + local.Promise = lib$es6$promise$promise$$default; + } + var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill; + + var lib$es6$promise$umd$$ES6Promise = { + 'Promise': lib$es6$promise$promise$$default, + 'polyfill': lib$es6$promise$polyfill$$default + }; + + /* global define:true module:true window: true */ + if (typeof define === 'function' && define['amd']) { + define(function () { return lib$es6$promise$umd$$ES6Promise; }); + } else if (typeof module !== 'undefined' && module['exports']) { + module['exports'] = lib$es6$promise$umd$$ES6Promise; + } else if (typeof this !== 'undefined') { + this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise; + } + + lib$es6$promise$polyfill$$default(); + }).call(this); + + + /** + * @constructor + */ + function DefaultHttpRequest() { + + /** + * @name _promiseFactory + * @type DefaultPromiseFactory + */ + + /** + * @param {XMLHttpRequest} xhr + * @param {object.} headers + */ + function setHeaders(xhr, headers) { + var keys = Object.keys(headers); + + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var value = headers[key]; + + xhr.setRequestHeader(key, value); + } + } + + /** + * @param {string} url + * @param {{ headers: object. }} [config] + * @returns {Promise} + */ + this.getJSON = function (url, config) { + return _promiseFactory.create(function (resolve, reject) { + + try { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.responseType = "json"; + + if (config) { + if (config.headers) { + setHeaders(xhr, config.headers); + } + } + + xhr.onload = function () { + try { + if (xhr.status === 200) { + var response = ""; + // To support IE9 get the response from xhr.responseText not xhr.response + if (window.XDomainRequest) { + response = xhr.responseText; + } else { + response = xhr.response; + } + if (typeof response === "string") { + response = JSON.parse(response); + } + resolve(response); + } + else { + reject(Error(xhr.statusText + "(" + xhr.status + ")")); + } + } + catch (err) { + reject(err); + } + }; + + xhr.onerror = function () { + reject(Error("Network error")); + }; + + xhr.send(); + } + catch (err) { + return reject(err); + } + }); + }; + } + + _httpRequest = new DefaultHttpRequest(); + + /** + * @constructor + * @param {Promise} promise + */ + function DefaultPromise(promise) { + + /** + * @param {function(*):*} successCallback + * @param {function(*):*} errorCallback + * @returns {DefaultPromise} + */ + this.then = function (successCallback, errorCallback) { + var childPromise = promise.then(successCallback, errorCallback); + + return new DefaultPromise(childPromise); + }; + + /** + * + * @param {function(*):*} errorCallback + * @returns {DefaultPromise} + */ + this.catch = function (errorCallback) { + var childPromise = promise.catch(errorCallback); + + return new DefaultPromise(childPromise); + }; + } + + /** + * @constructor + */ + function DefaultPromiseFactory() { + + this.resolve = function (value) { + return new DefaultPromise(Promise.resolve(value)); + }; + + this.reject = function (reason) { + return new DefaultPromise(Promise.reject(reason)); + }; + + /** + * @param {function(resolve:function, reject:function)} callback + * @returns {DefaultPromise} + */ + this.create = function (callback) { + return new DefaultPromise(new Promise(callback)); + }; + } + + _promiseFactory = new DefaultPromiseFactory(); + /* + * Copyright 2015 Dominick Baier, Brock Allen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + function log() { + //var param = [].join.call(arguments); + //console.log(param); + } + + function copy(obj, target) { + target = target || {}; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + target[key] = obj[key]; + } } + return target; + } - if (keyObj.isPrivate === true) { - this.prvKey = keyObj; - this.state = "SIGN"; - } else if (keyObj.isPublic === true) { - this.pubKey = keyObj; - this.state = "VERIFY"; - } else { - throw "init failed.:" + keyObj; + function rand() { + return ((Date.now() + Math.random()) * Math.random()).toString().replace(".", ""); + } + + function resolve(param) { + return _promiseFactory.resolve(param); + } + + function error(message) { + return _promiseFactory.reject(Error(message)); + } + + function parseOidcResult(queryString) { + log("parseOidcResult"); + + queryString = queryString || location.hash; + + var idx = queryString.lastIndexOf("#"); + if (idx >= 0) { + queryString = queryString.substr(idx + 1); } - }; - this.initSign = function(params) { - if (typeof params['ecprvhex'] == 'string' && - typeof params['eccurvename'] == 'string') { - this.ecprvhex = params['ecprvhex']; - this.eccurvename = params['eccurvename']; - } else { - this.prvKey = params; - } - this.state = "SIGN"; - }; - - this.initVerifyByPublicKey = function(params) { - if (typeof params['ecpubhex'] == 'string' && - typeof params['eccurvename'] == 'string') { - this.ecpubhex = params['ecpubhex']; - this.eccurvename = params['eccurvename']; - } else if (params instanceof KJUR.crypto.ECDSA) { - this.pubKey = params; - } else if (params instanceof RSAKey) { - this.pubKey = params; - } - this.state = "VERIFY"; - }; - - this.initVerifyByCertificatePEM = function(certPEM) { - var x509 = new X509(); - x509.readCertPEM(certPEM); - this.pubKey = x509.subjectPublicKeyRSA; - this.state = "VERIFY"; - }; - - this.updateString = function(str) { - this.md.updateString(str); - }; - this.updateHex = function(hex) { - this.md.updateHex(hex); - }; - - this.sign = function() { - this.sHashHex = this.md.digest(); - if (typeof this.ecprvhex != "undefined" && - typeof this.eccurvename != "undefined") { - var ec = new KJUR.crypto.ECDSA({'curve': this.eccurvename}); - this.hSign = ec.signHex(this.sHashHex, this.ecprvhex); - } else if (this.pubkeyAlgName == "rsaandmgf1") { - this.hSign = this.prvKey.signWithMessageHashPSS(this.sHashHex, - this.mdAlgName, - this.pssSaltLen); - } else if (this.pubkeyAlgName == "rsa") { - this.hSign = this.prvKey.signWithMessageHash(this.sHashHex, - this.mdAlgName); - } else if (this.prvKey instanceof KJUR.crypto.ECDSA) { - this.hSign = this.prvKey.signWithMessageHash(this.sHashHex); - } else if (this.prvKey instanceof KJUR.crypto.DSA) { - this.hSign = this.prvKey.signWithMessageHash(this.sHashHex); - } else { - throw "Signature: unsupported public key alg: " + this.pubkeyAlgName; - } - return this.hSign; - }; - this.signString = function(str) { - this.updateString(str); - return this.sign(); - }; - this.signHex = function(hex) { - this.updateHex(hex); - return this.sign(); - }; - this.verify = function(hSigVal) { - this.sHashHex = this.md.digest(); - if (typeof this.ecpubhex != "undefined" && - typeof this.eccurvename != "undefined") { - var ec = new KJUR.crypto.ECDSA({curve: this.eccurvename}); - return ec.verifyHex(this.sHashHex, hSigVal, this.ecpubhex); - } else if (this.pubkeyAlgName == "rsaandmgf1") { - return this.pubKey.verifyWithMessageHashPSS(this.sHashHex, hSigVal, - this.mdAlgName, - this.pssSaltLen); - } else if (this.pubkeyAlgName == "rsa") { - return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); - } else if (this.pubKey instanceof KJUR.crypto.ECDSA) { - return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); - } else if (this.pubKey instanceof KJUR.crypto.DSA) { - return this.pubKey.verifyWithMessageHash(this.sHashHex, hSigVal); - } else { - throw "Signature: unsupported public key alg: " + this.pubkeyAlgName; - } - }; - } - }; - - /** - * Initialize this object for signing or verifying depends on key - * @name init - * @memberOf KJUR.crypto.Signature - * @function - * @param {Object} key specifying public or private key as plain/encrypted PKCS#5/8 PEM file, certificate PEM or {@link RSAKey}, {@link KJUR.crypto.DSA} or {@link KJUR.crypto.ECDSA} object - * @param {String} pass (OPTION) passcode for encrypted private key - * @since crypto 1.1.3 - * @description - * This method is very useful initialize method for Signature class since - * you just specify key then this method will automatically initialize it - * using {@link KEYUTIL.getKey} method. - * As for 'key', following argument type are supported: - *
signing
- *
    - *
  • PEM formatted PKCS#8 encrypted RSA/ECDSA private key concluding "BEGIN ENCRYPTED PRIVATE KEY"
  • - *
  • PEM formatted PKCS#5 encrypted RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" and ",ENCRYPTED"
  • - *
  • PEM formatted PKCS#8 plain RSA/ECDSA private key concluding "BEGIN PRIVATE KEY"
  • - *
  • PEM formatted PKCS#5 plain RSA/DSA private key concluding "BEGIN RSA/DSA PRIVATE KEY" without ",ENCRYPTED"
  • - *
  • RSAKey object of private key
  • - *
  • KJUR.crypto.ECDSA object of private key
  • - *
  • KJUR.crypto.DSA object of private key
  • - *
- *
verification
- *
    - *
  • PEM formatted PKCS#8 RSA/EC/DSA public key concluding "BEGIN PUBLIC KEY"
  • - *
  • PEM formatted X.509 certificate with RSA/EC/DSA public key concluding - * "BEGIN CERTIFICATE", "BEGIN X509 CERTIFICATE" or "BEGIN TRUSTED CERTIFICATE".
  • - *
  • RSAKey object of public key
  • - *
  • KJUR.crypto.ECDSA object of public key
  • - *
  • KJUR.crypto.DSA object of public key
  • - *
- * @example - * sig.init(sCertPEM) - */ - this.init = function(key, pass) { - throw "init(key, pass) not supported for this alg:prov=" + - this.algProvName; - }; - - /** - * Initialize this object for verifying with a public key - * @name initVerifyByPublicKey - * @memberOf KJUR.crypto.Signature - * @function - * @param {Object} param RSAKey object of public key or associative array for ECDSA - * @since 1.0.2 - * @deprecated from crypto 1.1.5. please use init() method instead. - * @description - * Public key information will be provided as 'param' parameter and the value will be - * following: - *
    - *
  • {@link RSAKey} object for RSA verification
  • - *
  • associative array for ECDSA verification - * (ex. {'ecpubhex': '041f..', 'eccurvename': 'secp256r1'}) - *
  • - *
- * @example - * sig.initVerifyByPublicKey(rsaPrvKey) - */ - this.initVerifyByPublicKey = function(rsaPubKey) { - throw "initVerifyByPublicKey(rsaPubKeyy) not supported for this alg:prov=" + - this.algProvName; - }; - - /** - * Initialize this object for verifying with a certficate - * @name initVerifyByCertificatePEM - * @memberOf KJUR.crypto.Signature - * @function - * @param {String} certPEM PEM formatted string of certificate - * @since 1.0.2 - * @deprecated from crypto 1.1.5. please use init() method instead. - * @description - * @example - * sig.initVerifyByCertificatePEM(certPEM) - */ - this.initVerifyByCertificatePEM = function(certPEM) { - throw "initVerifyByCertificatePEM(certPEM) not supported for this alg:prov=" + - this.algProvName; - }; - - /** - * Initialize this object for signing - * @name initSign - * @memberOf KJUR.crypto.Signature - * @function - * @param {Object} param RSAKey object of public key or associative array for ECDSA - * @deprecated from crypto 1.1.5. please use init() method instead. - * @description - * Private key information will be provided as 'param' parameter and the value will be - * following: - *
    - *
  • {@link RSAKey} object for RSA signing
  • - *
  • associative array for ECDSA signing - * (ex. {'ecprvhex': '1d3f..', 'eccurvename': 'secp256r1'})
  • - *
- * @example - * sig.initSign(prvKey) - */ - this.initSign = function(prvKey) { - throw "initSign(prvKey) not supported for this alg:prov=" + this.algProvName; - }; - - /** - * Updates the data to be signed or verified by a string - * @name updateString - * @memberOf KJUR.crypto.Signature - * @function - * @param {String} str string to use for the update - * @description - * @example - * sig.updateString('aaa') - */ - this.updateString = function(str) { - throw "updateString(str) not supported for this alg:prov=" + this.algProvName; - }; - - /** - * Updates the data to be signed or verified by a hexadecimal string - * @name updateHex - * @memberOf KJUR.crypto.Signature - * @function - * @param {String} hex hexadecimal string to use for the update - * @description - * @example - * sig.updateHex('1f2f3f') - */ - this.updateHex = function(hex) { - throw "updateHex(hex) not supported for this alg:prov=" + this.algProvName; - }; - - /** - * Returns the signature bytes of all data updates as a hexadecimal string - * @name sign - * @memberOf KJUR.crypto.Signature - * @function - * @return the signature bytes as a hexadecimal string - * @description - * @example - * var hSigValue = sig.sign() - */ - this.sign = function() { - throw "sign() not supported for this alg:prov=" + this.algProvName; - }; - - /** - * performs final update on the sign using string, then returns the signature bytes of all data updates as a hexadecimal string - * @name signString - * @memberOf KJUR.crypto.Signature - * @function - * @param {String} str string to final update - * @return the signature bytes of a hexadecimal string - * @description - * @example - * var hSigValue = sig.signString('aaa') - */ - this.signString = function(str) { - throw "digestString(str) not supported for this alg:prov=" + this.algProvName; - }; - - /** - * performs final update on the sign using hexadecimal string, then returns the signature bytes of all data updates as a hexadecimal string - * @name signHex - * @memberOf KJUR.crypto.Signature - * @function - * @param {String} hex hexadecimal string to final update - * @return the signature bytes of a hexadecimal string - * @description - * @example - * var hSigValue = sig.signHex('1fdc33') - */ - this.signHex = function(hex) { - throw "digestHex(hex) not supported for this alg:prov=" + this.algProvName; - }; - - /** - * verifies the passed-in signature. - * @name verify - * @memberOf KJUR.crypto.Signature - * @function - * @param {String} str string to final update - * @return {Boolean} true if the signature was verified, otherwise false - * @description - * @example - * var isValid = sig.verify('1fbcefdca4823a7(snip)') - */ - this.verify = function(hSigVal) { - throw "verify(hSigVal) not supported for this alg:prov=" + this.algProvName; - }; - - this.initParams = params; - - if (params !== undefined) { - if (params['alg'] !== undefined) { - this.algName = params['alg']; - if (params['prov'] === undefined) { - this.provName = KJUR.crypto.Util.DEFAULTPROVIDER[this.algName]; - } else { - this.provName = params['prov']; - } - this.algProvName = this.algName + ":" + this.provName; - this.setAlgAndProvider(this.algName, this.provName); - this._setAlgNames(); - } - - if (params['psssaltlen'] !== undefined) this.pssSaltLen = params['psssaltlen']; - - if (params['prvkeypem'] !== undefined) { - if (params['prvkeypas'] !== undefined) { - throw "both prvkeypem and prvkeypas parameters not supported"; - } else { - try { - var prvKey = new RSAKey(); - prvKey.readPrivateKeyFromPEMString(params['prvkeypem']); - this.initSign(prvKey); - } catch (ex) { - throw "fatal error to load pem private key: " + ex; - } - } - } - } -}; - -/** - * static object for cryptographic function utilities - * @name KJUR.crypto.OID - * @class static object for cryptography related OIDs - * @property {Array} oidhex2name key value of hexadecimal OID and its name - * (ex. '2a8648ce3d030107' and 'secp256r1') - * @since crypto 1.1.3 - * @description - */ - - -KJUR.crypto.OID = new function() { - this.oidhex2name = { - '2a864886f70d010101': 'rsaEncryption', - '2a8648ce3d0201': 'ecPublicKey', - '2a8648ce380401': 'dsa', - '2a8648ce3d030107': 'secp256r1', - '2b8104001f': 'secp192k1', - '2b81040021': 'secp224r1', - '2b8104000a': 'secp256k1', - '2b81040023': 'secp521r1', - '2b81040022': 'secp384r1', - '2a8648ce380403': 'SHA1withDSA', // 1.2.840.10040.4.3 - '608648016503040301': 'SHA224withDSA', // 2.16.840.1.101.3.4.3.1 - '608648016503040302': 'SHA256withDSA', // 2.16.840.1.101.3.4.3.2 - }; -}; - -/*! base64x-1.1.3 (c) 2012-2014 Kenji Urushima | kjur.github.com/jsjws/license - */ -/* - * base64x.js - Base64url and supplementary functions for Tom Wu's base64.js library - * - * version: 1.1.3 (2014 May 25) - * - * Copyright (c) 2012-2014 Kenji Urushima (kenji.urushima@gmail.com) - * - * This software is licensed under the terms of the MIT License. - * http://kjur.github.com/jsjws/license/ - * - * The above copyright and license notice shall be - * included in all copies or substantial portions of the Software. - * - * DEPENDS ON: - * - base64.js - Tom Wu's Base64 library - */ - -/** - * Base64URL and supplementary functions for Tom Wu's base64.js library.
- * This class is just provide information about global functions - * defined in 'base64x.js'. The 'base64x.js' script file provides - * global functions for converting following data each other. - *
    - *
  • (ASCII) String
  • - *
  • UTF8 String including CJK, Latin and other characters
  • - *
  • byte array
  • - *
  • hexadecimal encoded String
  • - *
  • Full URIComponent encoded String (such like "%69%94")
  • - *
  • Base64 encoded String
  • - *
  • Base64URL encoded String
  • - *
- * All functions in 'base64x.js' are defined in {@link _global_} and not - * in this class. - * - * @class Base64URL and supplementary functions for Tom Wu's base64.js library - * @author Kenji Urushima - * @version 1.1 (07 May 2012) - * @requires base64.js - * @see 'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/ - * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ - */ -function Base64x() { -} - -// ==== string / byte array ================================ -/** - * convert a string to an array of character codes - * @param {String} s - * @return {Array of Numbers} - */ -function stoBA(s) { - var a = new Array(); - for (var i = 0; i < s.length; i++) { - a[i] = s.charCodeAt(i); - } - return a; -} - -/** - * convert an array of character codes to a string - * @param {Array of Numbers} a array of character codes - * @return {String} s - */ -function BAtos(a) { - var s = ""; - for (var i = 0; i < a.length; i++) { - s = s + String.fromCharCode(a[i]); - } - return s; -} - -// ==== byte array / hex ================================ -/** - * convert an array of bytes(Number) to hexadecimal string.
- * @param {Array of Numbers} a array of bytes - * @return {String} hexadecimal string - */ -function BAtohex(a) { - var s = ""; - for (var i = 0; i < a.length; i++) { - var hex1 = a[i].toString(16); - if (hex1.length == 1) hex1 = "0" + hex1; - s = s + hex1; - } - return s; -} - -// ==== string / hex ================================ -/** - * convert a ASCII string to a hexadecimal string of ASCII codes.
- * NOTE: This can't be used for non ASCII characters. - * @param {s} s ASCII string - * @return {String} hexadecimal string - */ -function stohex(s) { - return BAtohex(stoBA(s)); -} - -// ==== string / base64 ================================ -/** - * convert a ASCII string to a Base64 encoded string.
- * NOTE: This can't be used for non ASCII characters. - * @param {s} s ASCII string - * @return {String} Base64 encoded string - */ -function stob64(s) { - return hex2b64(stohex(s)); -} - -// ==== string / base64url ================================ -/** - * convert a ASCII string to a Base64URL encoded string.
- * NOTE: This can't be used for non ASCII characters. - * @param {s} s ASCII string - * @return {String} Base64URL encoded string - */ -function stob64u(s) { - return b64tob64u(hex2b64(stohex(s))); -} - -/** - * convert a Base64URL encoded string to a ASCII string.
- * NOTE: This can't be used for Base64URL encoded non ASCII characters. - * @param {s} s Base64URL encoded string - * @return {String} ASCII string - */ -function b64utos(s) { - return BAtos(b64toBA(b64utob64(s))); -} - -// ==== base64 / base64url ================================ -/** - * convert a Base64 encoded string to a Base64URL encoded string.
- * Example: "ab+c3f/==" → "ab-c3f_" - * @param {String} s Base64 encoded string - * @return {String} Base64URL encoded string - */ -function b64tob64u(s) { - s = s.replace(/\=/g, ""); - s = s.replace(/\+/g, "-"); - s = s.replace(/\//g, "_"); - return s; -} - -/** - * convert a Base64URL encoded string to a Base64 encoded string.
- * Example: "ab-c3f_" → "ab+c3f/==" - * @param {String} s Base64URL encoded string - * @return {String} Base64 encoded string - */ -function b64utob64(s) { - if (s.length % 4 == 2) s = s + "=="; - else if (s.length % 4 == 3) s = s + "="; - s = s.replace(/-/g, "+"); - s = s.replace(/_/g, "/"); - return s; -} - -// ==== hex / base64url ================================ -/** - * convert a hexadecimal string to a Base64URL encoded string.
- * @param {String} s hexadecimal string - * @return {String} Base64URL encoded string - */ -function hextob64u(s) { - return b64tob64u(hex2b64(s)); -} - -/** - * convert a Base64URL encoded string to a hexadecimal string.
- * @param {String} s Base64URL encoded string - * @return {String} hexadecimal string - */ -function b64utohex(s) { - return b64tohex(b64utob64(s)); -} - -var utf8tob64u, b64utoutf8; - -if (typeof Buffer === 'function') -{ - utf8tob64u = function (s) - { - return b64tob64u(new Buffer(s, 'utf8').toString('base64')); - }; - - b64utoutf8 = function (s) - { - return new Buffer(b64utob64(s), 'base64').toString('utf8'); - }; -} -else -{ -// ==== utf8 / base64url ================================ -/** - * convert a UTF-8 encoded string including CJK or Latin to a Base64URL encoded string.
- * @param {String} s UTF-8 encoded string - * @return {String} Base64URL encoded string - * @since 1.1 - */ - utf8tob64u = function (s) - { - return hextob64u(uricmptohex(encodeURIComponentAll(s))); - }; - -/** - * convert a Base64URL encoded string to a UTF-8 encoded string including CJK or Latin.
- * @param {String} s Base64URL encoded string - * @return {String} UTF-8 encoded string - * @since 1.1 - */ - b64utoutf8 = function (s) - { - return decodeURIComponent(hextouricmp(b64utohex(s))); - }; -} - -// ==== utf8 / base64url ================================ -/** - * convert a UTF-8 encoded string including CJK or Latin to a Base64 encoded string.
- * @param {String} s UTF-8 encoded string - * @return {String} Base64 encoded string - * @since 1.1.1 - */ -function utf8tob64(s) { - return hex2b64(uricmptohex(encodeURIComponentAll(s))); -} - -/** - * convert a Base64 encoded string to a UTF-8 encoded string including CJK or Latin.
- * @param {String} s Base64 encoded string - * @return {String} UTF-8 encoded string - * @since 1.1.1 - */ -function b64toutf8(s) { - return decodeURIComponent(hextouricmp(b64tohex(s))); -} - -// ==== utf8 / hex ================================ -/** - * convert a UTF-8 encoded string including CJK or Latin to a hexadecimal encoded string.
- * @param {String} s UTF-8 encoded string - * @return {String} hexadecimal encoded string - * @since 1.1.1 - */ -function utf8tohex(s) { - return uricmptohex(encodeURIComponentAll(s)); -} - -/** - * convert a hexadecimal encoded string to a UTF-8 encoded string including CJK or Latin.
- * Note that when input is improper hexadecimal string as UTF-8 string, this function returns - * 'null'. - * @param {String} s hexadecimal encoded string - * @return {String} UTF-8 encoded string or null - * @since 1.1.1 - */ -function hextoutf8(s) { - return decodeURIComponent(hextouricmp(s)); -} - -/** - * convert a hexadecimal encoded string to raw string including non printable characters.
- * @param {String} s hexadecimal encoded string - * @return {String} raw string - * @since 1.1.2 - * @example - * hextorstr("610061") → "a\x00a" - */ -function hextorstr(sHex) { - var s = ""; - for (var i = 0; i < sHex.length - 1; i += 2) { - s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16)); - } - return s; -} - -/** - * convert a raw string including non printable characters to hexadecimal encoded string.
- * @param {String} s raw string - * @return {String} hexadecimal encoded string - * @since 1.1.2 - * @example - * rstrtohex("a\x00a") → "610061" - */ -function rstrtohex(s) { - var result = ""; - for (var i = 0; i < s.length; i++) { - result += ("0" + s.charCodeAt(i).toString(16)).slice(-2); - } - return result; -} - -// ==== hex / b64nl ======================================= - -/* - * since base64x 1.1.3 - */ -function hextob64(s) { - return hex2b64(s); -} - -/* - * since base64x 1.1.3 - */ -function hextob64nl(s) { - var b64 = hextob64(s); - var b64nl = b64.replace(/(.{64})/g, "$1\r\n"); - b64nl = b64nl.replace(/\r\n$/, ''); - return b64nl; -} - -/* - * since base64x 1.1.3 - */ -function b64nltohex(s) { - var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, ''); - var hex = b64tohex(b64); - return hex; -} - -// ==== URIComponent / hex ================================ -/** - * convert a URLComponent string such like "%67%68" to a hexadecimal string.
- * @param {String} s URIComponent string such like "%67%68" - * @return {String} hexadecimal string - * @since 1.1 - */ -function uricmptohex(s) { - return s.replace(/%/g, ""); -} - -/** - * convert a hexadecimal string to a URLComponent string such like "%67%68".
- * @param {String} s hexadecimal string - * @return {String} URIComponent string such like "%67%68" - * @since 1.1 - */ -function hextouricmp(s) { - return s.replace(/(..)/g, "%$1"); -} - -// ==== URIComponent ================================ -/** - * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".
- * Note that these "0-9A-Za-z!'()*-._~" characters will not - * converted to "%xx" format by builtin 'encodeURIComponent()' function. - * However this 'encodeURIComponentAll()' function will convert - * all of characters into "%xx" format. - * @param {String} s hexadecimal string - * @return {String} URIComponent string such like "%67%68" - * @since 1.1 - */ -function encodeURIComponentAll(u8) { - var s = encodeURIComponent(u8); - var s2 = ""; - for (var i = 0; i < s.length; i++) { - if (s[i] == "%") { - s2 = s2 + s.substr(i, 3); - i = i + 2; - } else { - s2 = s2 + "%" + stohex(s[i]); - } - } - return s2; -} - -// ==== new lines ================================ -/** - * convert all DOS new line("\r\n") to UNIX new line("\n") in - * a String "s". - * @param {String} s string - * @return {String} converted string - */ -function newline_toUnix(s) { - s = s.replace(/\r\n/mg, "\n"); - return s; -} - -/** - * convert all UNIX new line("\r\n") to DOS new line("\n") in - * a String "s". - * @param {String} s string - * @return {String} converted string - */ -function newline_toDos(s) { - s = s.replace(/\r\n/mg, "\n"); - s = s.replace(/\n/mg, "\r\n"); - return s; -} - -/*! Mike Samuel (c) 2009 | code.google.com/p/json-sans-eval - */ -// This source code is free for use in the public domain. -// NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - -// http://code.google.com/p/json-sans-eval/ - -/** - * Parses a string of well-formed JSON text. - * - * If the input is not well-formed, then behavior is undefined, but it is - * deterministic and is guaranteed not to modify any object other than its - * return value. - * - * This does not use `eval` so is less likely to have obscure security bugs than - * json2.js. - * It is optimized for speed, so is much faster than json_parse.js. - * - * This library should be used whenever security is a concern (when JSON may - * come from an untrusted source), speed is a concern, and erroring on malformed - * JSON is *not* a concern. - * - * Pros Cons - * +-----------------------+-----------------------+ - * json_sans_eval.js | Fast, secure | Not validating | - * +-----------------------+-----------------------+ - * json_parse.js | Validating, secure | Slow | - * +-----------------------+-----------------------+ - * json2.js | Fast, some validation | Potentially insecure | - * +-----------------------+-----------------------+ - * - * json2.js is very fast, but potentially insecure since it calls `eval` to - * parse JSON data, so an attacker might be able to supply strange JS that - * looks like JSON, but that executes arbitrary javascript. - * If you do have to use json2.js with untrusted data, make sure you keep - * your version of json2.js up to date so that you get patches as they're - * released. - * - * @param {string} json per RFC 4627 - * @param {function (this:Object, string, *):*} opt_reviver optional function - * that reworks JSON objects post-parse per Chapter 15.12 of EcmaScript3.1. - * If supplied, the function is called with a string key, and a value. - * The value is the property of 'this'. The reviver should return - * the value to use in its place. So if dates were serialized as - * {@code { "type": "Date", "time": 1234 }}, then a reviver might look like - * {@code - * function (key, value) { - * if (value && typeof value === 'object' && 'Date' === value.type) { - * return new Date(value.time); - * } else { - * return value; - * } - * }}. - * If the reviver returns {@code undefined} then the property named by key - * will be deleted from its container. - * {@code this} is bound to the object containing the specified property. - * @return {Object|Array} - * @author Mike Samuel - */ -var jsonParse = (function () { - var number - = '(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)'; - var oneChar = '(?:[^\\0-\\x08\\x0a-\\x1f\"\\\\]' - + '|\\\\(?:[\"/\\\\bfnrt]|u[0-9A-Fa-f]{4}))'; - var string = '(?:\"' + oneChar + '*\")'; - - // Will match a value in a well-formed JSON file. - // If the input is not well-formed, may match strangely, but not in an unsafe - // way. - // Since this only matches value tokens, it does not match whitespace, colons, - // or commas. - var jsonToken = new RegExp( - '(?:false|true|null|[\\{\\}\\[\\]]' - + '|' + number - + '|' + string - + ')', 'g'); - - // Matches escape sequences in a string literal - var escapeSequence = new RegExp('\\\\(?:([^u])|u(.{4}))', 'g'); - - // Decodes escape sequences in object literals - var escapes = { - '"': '"', - '/': '/', - '\\': '\\', - 'b': '\b', - 'f': '\f', - 'n': '\n', - 'r': '\r', - 't': '\t' - }; - function unescapeOne(_, ch, hex) { - return ch ? escapes[ch] : String.fromCharCode(parseInt(hex, 16)); - } - - // A non-falsy value that coerces to the empty string when used as a key. - var EMPTY_STRING = new String(''); - var SLASH = '\\'; - - // Constructor to use based on an open token. - var firstTokenCtors = { '{': Object, '[': Array }; - - var hop = Object.hasOwnProperty; - - return function (json, opt_reviver) { - // Split into tokens - var toks = json.match(jsonToken); - // Construct the object to return - var result; - var tok = toks[0]; - var topLevelPrimitive = false; - if ('{' === tok) { - result = {}; - } else if ('[' === tok) { - result = []; - } else { - // The RFC only allows arrays or objects at the top level, but the JSON.parse - // defined by the EcmaScript 5 draft does allow strings, booleans, numbers, and null - // at the top level. - result = []; - topLevelPrimitive = true; - } - - // If undefined, the key in an object key/value record to use for the next - // value parsed. - var key; - // Loop over remaining tokens maintaining a stack of uncompleted objects and - // arrays. - var stack = [result]; - for (var i = 1 - topLevelPrimitive, n = toks.length; i < n; ++i) { - tok = toks[i]; - - var cont; - switch (tok.charCodeAt(0)) { - default: // sign or digit - cont = stack[0]; - cont[key || cont.length] = +(tok); - key = void 0; - break; - case 0x22: // '"' - tok = tok.substring(1, tok.length - 1); - if (tok.indexOf(SLASH) !== -1) { - tok = tok.replace(escapeSequence, unescapeOne); - } - cont = stack[0]; - if (!key) { - if (cont instanceof Array) { - key = cont.length; - } else { - key = tok || EMPTY_STRING; // Use as key for next value seen. - break; - } - } - cont[key] = tok; - key = void 0; - break; - case 0x5b: // '[' - cont = stack[0]; - stack.unshift(cont[key || cont.length] = []); - key = void 0; - break; - case 0x5d: // ']' - stack.shift(); - break; - case 0x66: // 'f' - cont = stack[0]; - cont[key || cont.length] = false; - key = void 0; - break; - case 0x6e: // 'n' - cont = stack[0]; - cont[key || cont.length] = null; - key = void 0; - break; - case 0x74: // 't' - cont = stack[0]; - cont[key || cont.length] = true; - key = void 0; - break; - case 0x7b: // '{' - cont = stack[0]; - stack.unshift(cont[key || cont.length] = {}); - key = void 0; - break; - case 0x7d: // '}' - stack.shift(); - break; - } - } - // Fail if we've got an uncompleted object. - if (topLevelPrimitive) { - if (stack.length !== 1) { throw new Error(); } - result = result[0]; - } else { - if (stack.length) { throw new Error(); } - } - - if (opt_reviver) { - // Based on walk as implemented in http://www.json.org/json2.js - var walk = function (holder, key) { - var value = holder[key]; - if (value && typeof value === 'object') { - var toDelete = null; - for (var k in value) { - if (hop.call(value, k) && value !== holder) { - // Recurse to properties first. This has the effect of causing - // the reviver to be called on the object graph depth-first. - - // Since 'this' is bound to the holder of the property, the - // reviver can access sibling properties of k including ones - // that have not yet been revived. - - // The value returned by the reviver is used in place of the - // current value of property k. - // If it returns undefined then the property is deleted. - var v = walk(value, k); - if (v !== void 0) { - value[k] = v; - } else { - // Deleting properties inside the loop has vaguely defined - // semantics in ES3 and ES3.1. - if (!toDelete) { toDelete = []; } - toDelete.push(k); - } - } - } - if (toDelete) { - for (var i = toDelete.length; --i >= 0;) { - delete value[toDelete[i]]; - } - } - } - return opt_reviver.call(holder, key, value); - }; - result = walk({ '': result }, ''); - } - - return result; - }; -})(); + var params = {}, + regex = /([^&=]+)=([^&]*)/g, + m; + + var counter = 0; + while (m = regex.exec(queryString)) { + params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]); + if (counter++ > 50) { + return { + error: "Response exceeded expected number of parameters" + }; + } + } + + for (var prop in params) { + return params; + } + } + + function getJson(url, token) { + log("getJson", url); + + var config = {}; + + if (token) { + config.headers = { "Authorization": "Bearer " + token }; + } + + return _httpRequest.getJSON(url, config); + } + + function OidcClient(settings) { + this._settings = settings || {}; + + if (!this._settings.request_state_key) { + this._settings.request_state_key = "OidcClient.request_state"; + } + + if (!this._settings.request_state_store) { + this._settings.request_state_store = window.localStorage; + } + + if (typeof this._settings.load_user_profile === 'undefined') { + this._settings.load_user_profile = true; + } + + if (typeof this._settings.filter_protocol_claims === 'undefined') { + this._settings.filter_protocol_claims = true; + } + + if (this._settings.authority && this._settings.authority.indexOf('.well-known/openid-configuration') < 0) { + if (this._settings.authority[this._settings.authority.length - 1] !== '/') { + this._settings.authority += '/'; + } + this._settings.authority += '.well-known/openid-configuration'; + } + + if (!this._settings.response_type) { + this._settings.response_type = "id_token token"; + } + + Object.defineProperty(this, "isOidc", { + get: function () { + if (this._settings.response_type) { + var result = this._settings.response_type.split(/\s+/g).filter(function (item) { + return item === "id_token"; + }); + return !!(result[0]); + } + return false; + } + }); + + Object.defineProperty(this, "isOAuth", { + get: function () { + if (this._settings.response_type) { + var result = this._settings.response_type.split(/\s+/g).filter(function (item) { + return item === "token"; + }); + return !!(result[0]); + } + return false; + } + }); + } + + OidcClient.parseOidcResult = parseOidcResult; + + OidcClient.prototype.loadMetadataAsync = function () { + log("OidcClient.loadMetadataAsync"); + + var settings = this._settings; + + if (settings.metadata) { + return resolve(settings.metadata); + } + + if (!settings.authority) { + return error("No authority configured"); + } + + return getJson(settings.authority) + .then(function (metadata) { + settings.metadata = metadata; + return metadata; + }, function (err) { + return error("Failed to load metadata (" + err && err.message + ")"); + }); + }; + + OidcClient.prototype.loadX509SigningKeyAsync = function () { + log("OidcClient.loadX509SigningKeyAsync"); + + var settings = this._settings; + + function getKeyAsync(jwks) { + if (!jwks.keys || !jwks.keys.length) { + return error("Signing keys empty"); + } + + var key = jwks.keys[0]; + if (key.kty !== "RSA") { + return error("Signing key not RSA"); + } + + if (!key.x5c || !key.x5c.length) { + return error("RSA keys empty"); + } + + return resolve(key.x5c[0]); + } + + if (settings.jwks) { + return getKeyAsync(settings.jwks); + } + + return this.loadMetadataAsync().then(function (metadata) { + if (!metadata.jwks_uri) { + return error("Metadata does not contain jwks_uri"); + } + + return getJson(metadata.jwks_uri).then(function (jwks) { + settings.jwks = jwks; + return getKeyAsync(jwks); + }, function (err) { + return error("Failed to load signing keys (" + err && err.message + ")"); + }); + }); + }; -/*! jws-3.0.2 (c) 2013 Kenji Urushima | kjur.github.com/jsjws/license - */ -/* - * jws.js - JSON Web Signature Class - * - * version: 3.0.2 (2013 Sep 24) - * - * Copyright (c) 2010-2013 Kenji Urushima (kenji.urushima@gmail.com) - * - * This software is licensed under the terms of the MIT License. - * http://kjur.github.com/jsjws/license/ - * - * The above copyright and license notice shall be - * included in all copies or substantial portions of the Software. - */ - -/** - * @fileOverview - * @name jws-3.0.js - * @author Kenji Urushima kenji.urushima@gmail.com - * @version 3.0.1 (2013-Sep-24) - * @since jsjws 1.0 - * @license MIT License - */ - -if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; -if (typeof KJUR.jws == "undefined" || !KJUR.jws) KJUR.jws = {}; - -/** - * JSON Web Signature(JWS) class.
- * @name KJUR.jws.JWS - * @class JSON Web Signature(JWS) class - * @property {Dictionary} parsedJWS This property is set after JWS signature verification.
- * Following "parsedJWS_*" properties can be accessed as "parsedJWS.*" because of - * JsDoc restriction. - * @property {String} parsedJWS_headB64U string of Encrypted JWS Header - * @property {String} parsedJWS_payloadB64U string of Encrypted JWS Payload - * @property {String} parsedJWS_sigvalB64U string of Encrypted JWS signature value - * @property {String} parsedJWS_si string of Signature Input - * @property {String} parsedJWS_sigvalH hexadecimal string of JWS signature value - * @property {String} parsedJWS_sigvalBI BigInteger(defined in jsbn.js) object of JWS signature value - * @property {String} parsedJWS_headS string of decoded JWS Header - * @property {String} parsedJWS_headS string of decoded JWS Payload - * @requires base64x.js, json-sans-eval.js and jsrsasign library - * @see 'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/ - * @see 'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/ - * @see IETF I-D JSON Web Algorithms (JWA) - * @since jsjws 1.0 - * @description - *

Supported Algorithms

- * Here is supported algorithm names for {@link KJUR.jws.JWS.sign} and {@link KJUR.jws.JWS.verify} - * methods. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
alg valuespec requirementjsjws support
HS256REQUIREDSUPPORTED
HS384OPTIONALSUPPORTED
HS512OPTIONALSUPPORTED
RS256RECOMMENDEDSUPPORTED
RS384OPTIONALSUPPORTED
RS512OPTIONALSUPPORTED
ES256RECOMMENDED+SUPPORTED
ES384OPTIONALSUPPORTED
ES512OPTIONAL-
PS256OPTIONALSUPPORTED
PS384OPTIONALSUPPORTED
PS512OPTIONALSUPPORTED
noneREQUIREDSUPPORTED
- * NOTE: HS384 is supported since jsjws 3.0.2 with jsrsasign 4.1.4. - */ -KJUR.jws.JWS = function() { - - // === utility ============================================================= - - /** - * parse JWS string and set public property 'parsedJWS' dictionary.
- * @name parseJWS - * @memberOf KJUR.jws.JWS - * @function - * @param {String} sJWS JWS signature string to be parsed. - * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". - * @throws if JWS Header is a malformed JSON string. - * @since jws 1.1 - */ - this.parseJWS = function(sJWS, sigValNotNeeded) { - if ((this.parsedJWS !== undefined) && - (sigValNotNeeded || (this.parsedJWS.sigvalH !== undefined))) { - return; - } - if (sJWS.match(/^([^.]+)\.([^.]+)\.([^.]+)$/) == null) { - throw "JWS signature is not a form of 'Head.Payload.SigValue'."; - } - var b6Head = RegExp.$1; - var b6Payload = RegExp.$2; - var b6SigVal = RegExp.$3; - var sSI = b6Head + "." + b6Payload; - this.parsedJWS = {}; - this.parsedJWS.headB64U = b6Head; - this.parsedJWS.payloadB64U = b6Payload; - this.parsedJWS.sigvalB64U = b6SigVal; - this.parsedJWS.si = sSI; - - if (!sigValNotNeeded) { - var hSigVal = b64utohex(b6SigVal); - var biSigVal = parseBigInt(hSigVal, 16); - this.parsedJWS.sigvalH = hSigVal; - this.parsedJWS.sigvalBI = biSigVal; - } - - var sHead = b64utoutf8(b6Head); - var sPayload = b64utoutf8(b6Payload); - this.parsedJWS.headS = sHead; - this.parsedJWS.payloadS = sPayload; - - if (!KJUR.jws.JWS.isSafeJSONString(sHead, this.parsedJWS, 'headP')) - throw "malformed JSON string for JWS Head: " + sHead; - }; - - // ==== JWS Validation ========================================================= - function _getSignatureInputByString(sHead, sPayload) { - return utf8tob64u(sHead) + "." + utf8tob64u(sPayload); - }; - - function _getHashBySignatureInput(sSignatureInput, sHashAlg) { - var hashfunc = function(s) { return KJUR.crypto.Util.hashString(s, sHashAlg); }; - if (hashfunc == null) throw "hash function not defined in jsrsasign: " + sHashAlg; - return hashfunc(sSignatureInput); - }; - - function _jws_verifySignature(sHead, sPayload, hSig, hN, hE) { - var sSignatureInput = _getSignatureInputByString(sHead, sPayload); - var biSig = parseBigInt(hSig, 16); - return _rsasign_verifySignatureWithArgs(sSignatureInput, biSig, hN, hE); - }; - - /** - * verify JWS signature with naked RSA public key.
- * This only supports "RS256" and "RS512" algorithm. - * @name verifyJWSByNE - * @memberOf KJUR.jws.JWS - * @function - * @param {String} sJWS JWS signature string to be verified - * @param {String} hN hexadecimal string for modulus of RSA public key - * @param {String} hE hexadecimal string for public exponent of RSA public key - * @return {String} returns 1 when JWS signature is valid, otherwise returns 0 - * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". - * @throws if JWS Header is a malformed JSON string. - * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} - */ - this.verifyJWSByNE = function(sJWS, hN, hE) { - this.parseJWS(sJWS); - return _rsasign_verifySignatureWithArgs(this.parsedJWS.si, this.parsedJWS.sigvalBI, hN, hE); - }; - - /** - * verify JWS signature with RSA public key.
- * This only supports "RS256", "RS512", "PS256" and "PS512" algorithms. - * @name verifyJWSByKey - * @memberOf KJUR.jws.JWS - * @function - * @param {String} sJWS JWS signature string to be verified - * @param {RSAKey} key RSA public key - * @return {Boolean} returns true when JWS signature is valid, otherwise returns false - * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". - * @throws if JWS Header is a malformed JSON string. - * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} - */ - this.verifyJWSByKey = function(sJWS, key) { - this.parseJWS(sJWS); - var hashAlg = _jws_getHashAlgFromParsedHead(this.parsedJWS.headP); - var isPSS = this.parsedJWS.headP['alg'].substr(0, 2) == "PS"; - - if (key.hashAndVerify) { - return key.hashAndVerify(hashAlg, - new Buffer(this.parsedJWS.si, 'utf8').toString('base64'), - b64utob64(this.parsedJWS.sigvalB64U), - 'base64', - isPSS); - } else if (isPSS) { - return key.verifyStringPSS(this.parsedJWS.si, - this.parsedJWS.sigvalH, hashAlg); - } else { - return key.verifyString(this.parsedJWS.si, - this.parsedJWS.sigvalH); - } - }; - - /** - * verify JWS signature by PEM formatted X.509 certificate.
- * This only supports "RS256" and "RS512" algorithm. - * @name verifyJWSByPemX509Cert - * @memberOf KJUR.jws.JWS - * @function - * @param {String} sJWS JWS signature string to be verified - * @param {String} sPemX509Cert string of PEM formatted X.509 certificate - * @return {String} returns 1 when JWS signature is valid, otherwise returns 0 - * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". - * @throws if JWS Header is a malformed JSON string. - * @since 1.1 - * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.verify} - */ - this.verifyJWSByPemX509Cert = function(sJWS, sPemX509Cert) { - this.parseJWS(sJWS); - var x509 = new X509(); - x509.readCertPEM(sPemX509Cert); - return x509.subjectPublicKeyRSA.verifyString(this.parsedJWS.si, this.parsedJWS.sigvalH); - }; - - // ==== JWS Generation ========================================================= - function _jws_getHashAlgFromParsedHead(head) { - var sigAlg = head["alg"]; - var hashAlg = ""; - - if (sigAlg != "RS256" && sigAlg != "RS512" && - sigAlg != "PS256" && sigAlg != "PS512") - throw "JWS signature algorithm not supported: " + sigAlg; - if (sigAlg.substr(2) == "256") hashAlg = "sha256"; - if (sigAlg.substr(2) == "512") hashAlg = "sha512"; - return hashAlg; - }; - - function _jws_getHashAlgFromHead(sHead) { - return _jws_getHashAlgFromParsedHead(jsonParse(sHead)); - }; - - function _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD) { - var rsa = new RSAKey(); - rsa.setPrivate(hN, hE, hD); - - var hashAlg = _jws_getHashAlgFromHead(sHead); - var sigValue = rsa.signString(sSI, hashAlg); - return sigValue; - }; - - function _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, head) { - var hashAlg = null; - if (typeof head == "undefined") { - hashAlg = _jws_getHashAlgFromHead(sHead); - } else { - hashAlg = _jws_getHashAlgFromParsedHead(head); - } - - var isPSS = head['alg'].substr(0, 2) == "PS"; - - if (key.hashAndSign) { - return b64tob64u(key.hashAndSign(hashAlg, sSI, 'binary', 'base64', isPSS)); - } else if (isPSS) { - return hextob64u(key.signStringPSS(sSI, hashAlg)); - } else { - return hextob64u(key.signString(sSI, hashAlg)); - } - }; - - function _jws_generateSignatureValueByNED(sHead, sPayload, hN, hE, hD) { - var sSI = _getSignatureInputByString(sHead, sPayload); - return _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD); - }; - - /** - * generate JWS signature by Header, Payload and a naked RSA private key.
- * This only supports "RS256" and "RS512" algorithm. - * @name generateJWSByNED - * @memberOf KJUR.jws.JWS - * @function - * @param {String} sHead string of JWS Header - * @param {String} sPayload string of JWS Payload - * @param {String} hN hexadecimal string for modulus of RSA public key - * @param {String} hE hexadecimal string for public exponent of RSA public key - * @param {String} hD hexadecimal string for private exponent of RSA private key - * @return {String} JWS signature string - * @throws if sHead is a malformed JSON string. - * @throws if supported signature algorithm was not specified in JSON Header. - * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} - */ - this.generateJWSByNED = function(sHead, sPayload, hN, hE, hD) { - if (!KJUR.jws.JWS.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead; - var sSI = _getSignatureInputByString(sHead, sPayload); - var hSigValue = _jws_generateSignatureValueBySI_NED(sHead, sPayload, sSI, hN, hE, hD); - var b64SigValue = hextob64u(hSigValue); - - this.parsedJWS = {}; - this.parsedJWS.headB64U = sSI.split(".")[0]; - this.parsedJWS.payloadB64U = sSI.split(".")[1]; - this.parsedJWS.sigvalB64U = b64SigValue; - - return sSI + "." + b64SigValue; - }; - - /** - * generate JWS signature by Header, Payload and a RSA private key.
- * This only supports "RS256", "RS512", "PS256" and "PS512" algorithms. - * @name generateJWSByKey - * @memberOf KJUR.jws.JWS - * @function - * @param {String} sHead string of JWS Header - * @param {String} sPayload string of JWS Payload - * @param {RSAKey} RSA private key - * @return {String} JWS signature string - * @throws if sHead is a malformed JSON string. - * @throws if supported signature algorithm was not specified in JSON Header. - * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} - */ - this.generateJWSByKey = function(sHead, sPayload, key) { - var obj = {}; - if (!KJUR.jws.JWS.isSafeJSONString(sHead, obj, 'headP')) - throw "JWS Head is not safe JSON string: " + sHead; - var sSI = _getSignatureInputByString(sHead, sPayload); - var b64SigValue = _jws_generateSignatureValueBySI_Key(sHead, sPayload, sSI, key, obj.headP); - - this.parsedJWS = {}; - this.parsedJWS.headB64U = sSI.split(".")[0]; - this.parsedJWS.payloadB64U = sSI.split(".")[1]; - this.parsedJWS.sigvalB64U = b64SigValue; - - return sSI + "." + b64SigValue; - }; - - // === sign with PKCS#1 RSA private key ===================================================== - function _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey) { - var rsa = new RSAKey(); - rsa.readPrivateKeyFromPEMString(sPemPrvKey); - var hashAlg = _jws_getHashAlgFromHead(sHead); - var sigValue = rsa.signString(sSI, hashAlg); - return sigValue; - }; - - /** - * generate JWS signature by Header, Payload and a PEM formatted PKCS#1 RSA private key.
- * This only supports "RS256" and "RS512" algorithm. - * @name generateJWSByP1PrvKey - * @memberOf KJUR.jws.JWS - * @function - * @param {String} sHead string of JWS Header - * @param {String} sPayload string of JWS Payload - * @param {String} string for sPemPrvKey PEM formatted PKCS#1 RSA private key
- * Heading and trailing space characters in PEM key will be ignored. - * @return {String} JWS signature string - * @throws if sHead is a malformed JSON string. - * @throws if supported signature algorithm was not specified in JSON Header. - * @since 1.1 - * @deprecated from 3.0.0 please move to {@link KJUR.jws.JWS.sign} - */ - this.generateJWSByP1PrvKey = function(sHead, sPayload, sPemPrvKey) { - if (!KJUR.jws.JWS.isSafeJSONString(sHead)) throw "JWS Head is not safe JSON string: " + sHead; - var sSI = _getSignatureInputByString(sHead, sPayload); - var hSigValue = _jws_generateSignatureValueBySI_PemPrvKey(sHead, sPayload, sSI, sPemPrvKey); - var b64SigValue = hextob64u(hSigValue); - - this.parsedJWS = {}; - this.parsedJWS.headB64U = sSI.split(".")[0]; - this.parsedJWS.payloadB64U = sSI.split(".")[1]; - this.parsedJWS.sigvalB64U = b64SigValue; - - return sSI + "." + b64SigValue; - }; -}; - -// === major static method ======================================================== - -/** - * generate JWS signature by specified key
- * @name sign - * @memberOf KJUR.jws.JWS - * @function - * @static - * @param {String} alg JWS algorithm name to sign and force set to sHead or null - * @param {String} sHead string of JWS Header - * @param {String} sPayload string of JWS Payload - * @param {String} key string of private key or key object to sign - * @param {String} pass (OPTION)passcode to use encrypted private key - * @return {String} JWS signature string - * @since jws 3.0.0 - * @see jsrsasign KJUR.crypto.Signature method - * @see jsrsasign KJUR.crypto.Mac method - * @description - * This method supports following algorithms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
alg valuespec requirementjsjws support
HS256REQUIREDSUPPORTED
HS384OPTIONAL-
HS512OPTIONALSUPPORTED
RS256RECOMMENDEDSUPPORTED
RS384OPTIONALSUPPORTED
RS512OPTIONALSUPPORTED
ES256RECOMMENDED+SUPPORTED
ES384OPTIONALSUPPORTED
ES512OPTIONAL-
PS256OPTIONALSUPPORTED
PS384OPTIONALSUPPORTED
PS512OPTIONALSUPPORTED
noneREQUIREDSUPPORTED
- *
- *
NOTE1: - *
salt length of RSAPSS signature is the same as the hash algorithm length - * because of IETF JOSE ML discussion. - *
NOTE2: - *
The reason of HS384 unsupport is - * CryptoJS HmacSHA384 bug. - *
- */ -KJUR.jws.JWS.sign = function(alg, sHeader, sPayload, key, pass) { - var ns1 = KJUR.jws.JWS; - - if (! ns1.isSafeJSONString(sHeader)) - throw "JWS Head is not safe JSON string: " + sHead; - - var pHeader = ns1.readSafeJSONString(sHeader); - - // 1. use alg if defined in sHeader - if ((alg == '' || alg == null) && - pHeader['alg'] !== undefined) { - alg = pHeader['alg']; - } - - // 2. set alg in sHeader if undefined - if ((alg != '' && alg != null) && - pHeader['alg'] === undefined) { - pHeader['alg'] = alg; - sHeader = JSON.stringify(pHeader); - } - - // 3. set signature algorithm like SHA1withRSA - var sigAlg = null; - if (ns1.jwsalg2sigalg[alg] === undefined) { - throw "unsupported alg name: " + alg; - } else { - sigAlg = ns1.jwsalg2sigalg[alg]; - } - - var uHeader = utf8tob64u(sHeader); - var uPayload = utf8tob64u(sPayload); - var uSignatureInput = uHeader + "." + uPayload - - // 4. sign - var hSig = ""; - if (sigAlg.substr(0, 4) == "Hmac") { - if (key === undefined) - throw "hexadecimal key shall be specified for HMAC"; - var mac = new KJUR.crypto.Mac({'alg': sigAlg, 'pass': hextorstr(key)}); - mac.updateString(uSignatureInput); - hSig = mac.doFinal(); - } else if (sigAlg.indexOf("withECDSA") != -1) { - var sig = new KJUR.crypto.Signature({'alg': sigAlg}); - sig.init(key, pass); - sig.updateString(uSignatureInput); - hASN1Sig = sig.sign(); - hSig = KJUR.crypto.ECDSA.asn1SigToConcatSig(hASN1Sig); - } else if (sigAlg != "none") { - var sig = new KJUR.crypto.Signature({'alg': sigAlg}); - sig.init(key, pass); - sig.updateString(uSignatureInput); - hSig = sig.sign(); - } - - var uSig = hextob64u(hSig); - return uSignatureInput + "." + uSig; -}; - -/** - * verify JWS signature by specified key or certificate
- * @name verify - * @memberOf KJUR.jws.JWS - * @function - * @static - * @param {String} sJWS string of JWS signature to verify - * @param {String} key string of public key, certificate or key object to verify - * @return {Boolean} true if the signature is valid otherwise false - * @since jws 3.0.0 - * @see jsrsasign KJUR.crypto.Signature method - * @see jsrsasign KJUR.crypto.Mac method - */ -KJUR.jws.JWS.verify = function(sJWS, key) { - var jws = KJUR.jws.JWS; - var a = sJWS.split("."); - var uHeader = a[0]; - var uPayload = a[1]; - var uSignatureInput = uHeader + "." + uPayload; - var hSig = b64utohex(a[2]); - - var pHeader = jws.readSafeJSONString(b64utoutf8(a[0])); - var alg = null; - if (pHeader.alg === undefined) { - throw "algorithm not specified in header"; - } else { - alg = pHeader.alg; - } - - var sigAlg = null; - if (jws.jwsalg2sigalg[pHeader.alg] === undefined) { - throw "unsupported alg name: " + alg; - } else { - sigAlg = jws.jwsalg2sigalg[alg]; - } - - // x. verify - if (sigAlg == "none") { - return true; - } else if (sigAlg.substr(0, 4) == "Hmac") { - if (key === undefined) - throw "hexadecimal key shall be specified for HMAC"; - var mac = new KJUR.crypto.Mac({'alg': sigAlg, 'pass': hextorstr(key)}); - mac.updateString(uSignatureInput); - hSig2 = mac.doFinal(); - return hSig == hSig2; - } else if (sigAlg.indexOf("withECDSA") != -1) { - var hASN1Sig = null; - try { - hASN1Sig = KJUR.crypto.ECDSA.concatSigToASN1Sig(hSig); - } catch (ex) { - return false; - } - var sig = new KJUR.crypto.Signature({'alg': sigAlg}); - sig.init(key) - sig.updateString(uSignatureInput); - return sig.verify(hASN1Sig); - } else { - var sig = new KJUR.crypto.Signature({'alg': sigAlg}); - sig.init(key) - sig.updateString(uSignatureInput); - return sig.verify(hSig); - } -}; - -/* - * @since jws 3.0.0 - */ -KJUR.jws.JWS.jwsalg2sigalg = { - "HS256": "HmacSHA256", - //"HS384": "HmacSHA384", // unsupported because of CryptoJS bug - "HS512": "HmacSHA512", - "RS256": "SHA256withRSA", - "RS384": "SHA384withRSA", - "RS512": "SHA512withRSA", - "ES256": "SHA256withECDSA", - "ES384": "SHA384withECDSA", - //"ES512": "SHA512withECDSA", // unsupported because of jsrsasign's bug - "PS256": "SHA256withRSAandMGF1", - "PS384": "SHA384withRSAandMGF1", - "PS512": "SHA512withRSAandMGF1", - "none": "none", -}; - -// === utility static method ====================================================== - -/** - * check whether a String "s" is a safe JSON string or not.
- * If a String "s" is a malformed JSON string or an other object type - * this returns 0, otherwise this returns 1. - * @name isSafeJSONString - * @memberOf KJUR.jws.JWS - * @function - * @static - * @param {String} s JSON string - * @return {Number} 1 or 0 - */ -KJUR.jws.JWS.isSafeJSONString = function(s, h, p) { - var o = null; - try { - o = jsonParse(s); - if (typeof o != "object") return 0; - if (o.constructor === Array) return 0; - if (h) h[p] = o; - return 1; - } catch (ex) { - return 0; - } -}; - -/** - * read a String "s" as JSON object if it is safe.
- * If a String "s" is a malformed JSON string or not JSON string, - * this returns null, otherwise returns JSON object. - * @name readSafeJSONString - * @memberOf KJUR.jws.JWS - * @function - * @static - * @param {String} s JSON string - * @return {Object} JSON object or null - * @since 1.1.1 - */ -KJUR.jws.JWS.readSafeJSONString = function(s) { - var o = null; - try { - o = jsonParse(s); - if (typeof o != "object") return null; - if (o.constructor === Array) return null; - return o; - } catch (ex) { - return null; - } -}; - -/** - * get Encoed Signature Value from JWS string.
- * @name getEncodedSignatureValueFromJWS - * @memberOf KJUR.jws.JWS - * @function - * @static - * @param {String} sJWS JWS signature string to be verified - * @return {String} string of Encoded Signature Value - * @throws if sJWS is not comma separated string such like "Header.Payload.Signature". - */ -KJUR.jws.JWS.getEncodedSignatureValueFromJWS = function(sJWS) { - if (sJWS.match(/^[^.]+\.[^.]+\.([^.]+)$/) == null) { - throw "JWS signature is not a form of 'Head.Payload.SigValue'."; - } - return RegExp.$1; -}; - -/** - * IntDate class for time representation for JSON Web Token(JWT) - * @class KJUR.jws.IntDate class - * @name KJUR.jws.IntDate - * @since jws 3.0.1 - * @description - * Utility class for IntDate which is integer representation of UNIX origin time - * used in JSON Web Token(JWT). - */ -KJUR.jws.IntDate = function() { -}; - -/** - * @name get - * @memberOf KJUR.jws.IntDate - * @function - * @static - * @param {String} s string of time representation - * @return {Integer} UNIX origin time in seconds for argument 's' - * @since jws 3.0.1 - * @throws "unsupported format: s" when malformed format - * @description - * This method will accept following representation of time. - *
    - *
  • now - current time
  • - *
  • now + 1hour - after 1 hour from now
  • - *
  • now + 1day - after 1 day from now
  • - *
  • now + 1month - after 30 days from now
  • - *
  • now + 1year - after 365 days from now
  • - *
  • YYYYmmDDHHMMSSZ - UTC time (ex. 20130828235959Z)
  • - *
  • number - UNIX origin time (seconds from 1970-01-01 00:00:00) (ex. 1377714748)
  • - *
- */ -KJUR.jws.IntDate.get = function(s) { - if (s == "now") { - return KJUR.jws.IntDate.getNow(); - } else if (s == "now + 1hour") { - return KJUR.jws.IntDate.getNow() + 60 * 60; - } else if (s == "now + 1day") { - return KJUR.jws.IntDate.getNow() + 60 * 60 * 24; - } else if (s == "now + 1month") { - return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 30; - } else if (s == "now + 1year") { - return KJUR.jws.IntDate.getNow() + 60 * 60 * 24 * 365; - } else if (s.match(/Z$/)) { - return KJUR.jws.IntDate.getZulu(s); - } else if (s.match(/^[0-9]+$/)) { - return parseInt(s); - } - throw "unsupported format: " + s; -}; - -KJUR.jws.IntDate.getZulu = function(s) { - if (a = s.match(/(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)Z/)) { - var year = parseInt(RegExp.$1); - var month = parseInt(RegExp.$2) - 1; - var day = parseInt(RegExp.$3); - var hour = parseInt(RegExp.$4); - var min = parseInt(RegExp.$5); - var sec = parseInt(RegExp.$6); - var d = new Date(Date.UTC(year, month, day, hour, min, sec)); - return ~~(d / 1000); - } - throw "unsupported format: " + s; -}; - -/* - * @since jws 3.0.1 - */ -KJUR.jws.IntDate.getNow = function() { - var d = ~~(new Date() / 1000); - return d; -}; - -/* - * @since jws 3.0.1 - */ -KJUR.jws.IntDate.intDate2UTCString = function(intDate) { - var d = new Date(intDate * 1000); - return d.toUTCString(); -}; - -/* - * @since jws 3.0.1 - */ -KJUR.jws.IntDate.intDate2Zulu = function(intDate) { - var d = new Date(intDate * 1000); - var year = ("0000" + d.getUTCFullYear()).slice(-4); - var mon = ("00" + (d.getUTCMonth() + 1)).slice(-2); - var day = ("00" + d.getUTCDate()).slice(-2); - var hour = ("00" + d.getUTCHours()).slice(-2); - var min = ("00" + d.getUTCMinutes()).slice(-2); - var sec = ("00" + d.getUTCSeconds()).slice(-2); - return year + mon + day + hour + min + sec + "Z"; -}; - -/*! - * @overview es6-promise - a tiny implementation of Promises/A+. - * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) - * @license Licensed under MIT license - * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE - * @version 3.0.2 - */ - -(function() { - "use strict"; - function lib$es6$promise$utils$$objectOrFunction(x) { - return typeof x === 'function' || (typeof x === 'object' && x !== null); - } - - function lib$es6$promise$utils$$isFunction(x) { - return typeof x === 'function'; - } - - function lib$es6$promise$utils$$isMaybeThenable(x) { - return typeof x === 'object' && x !== null; - } - - var lib$es6$promise$utils$$_isArray; - if (!Array.isArray) { - lib$es6$promise$utils$$_isArray = function (x) { - return Object.prototype.toString.call(x) === '[object Array]'; - }; - } else { - lib$es6$promise$utils$$_isArray = Array.isArray; - } - - var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray; - var lib$es6$promise$asap$$len = 0; - var lib$es6$promise$asap$$toString = {}.toString; - var lib$es6$promise$asap$$vertxNext; - var lib$es6$promise$asap$$customSchedulerFn; - - var lib$es6$promise$asap$$asap = function asap(callback, arg) { - lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback; - lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg; - lib$es6$promise$asap$$len += 2; - if (lib$es6$promise$asap$$len === 2) { - // If len is 2, that means that we need to schedule an async flush. - // If additional callbacks are queued before the queue is flushed, they - // will be processed by this flush that we are scheduling. - if (lib$es6$promise$asap$$customSchedulerFn) { - lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush); - } else { - lib$es6$promise$asap$$scheduleFlush(); - } - } - } - - function lib$es6$promise$asap$$setScheduler(scheduleFn) { - lib$es6$promise$asap$$customSchedulerFn = scheduleFn; - } - - function lib$es6$promise$asap$$setAsap(asapFn) { - lib$es6$promise$asap$$asap = asapFn; - } - - var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined; - var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {}; - var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver; - var lib$es6$promise$asap$$isNode = typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; - - // test for web worker but not in IE10 - var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' && - typeof importScripts !== 'undefined' && - typeof MessageChannel !== 'undefined'; - - // node - function lib$es6$promise$asap$$useNextTick() { - // node version 0.10.x displays a deprecation warning when nextTick is used recursively - // see https://github.com/cujojs/when/issues/410 for details - return function() { - process.nextTick(lib$es6$promise$asap$$flush); - }; - } - - // vertx - function lib$es6$promise$asap$$useVertxTimer() { - return function() { - lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush); - }; - } - - function lib$es6$promise$asap$$useMutationObserver() { - var iterations = 0; - var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush); - var node = document.createTextNode(''); - observer.observe(node, { characterData: true }); - - return function() { - node.data = (iterations = ++iterations % 2); - }; - } - - // web worker - function lib$es6$promise$asap$$useMessageChannel() { - var channel = new MessageChannel(); - channel.port1.onmessage = lib$es6$promise$asap$$flush; - return function () { - channel.port2.postMessage(0); - }; - } - - function lib$es6$promise$asap$$useSetTimeout() { - return function() { - setTimeout(lib$es6$promise$asap$$flush, 1); - }; - } - - var lib$es6$promise$asap$$queue = new Array(1000); - function lib$es6$promise$asap$$flush() { - for (var i = 0; i < lib$es6$promise$asap$$len; i+=2) { - var callback = lib$es6$promise$asap$$queue[i]; - var arg = lib$es6$promise$asap$$queue[i+1]; - - callback(arg); - - lib$es6$promise$asap$$queue[i] = undefined; - lib$es6$promise$asap$$queue[i+1] = undefined; - } - - lib$es6$promise$asap$$len = 0; - } - - function lib$es6$promise$asap$$attemptVertx() { - try { - var r = require; - var vertx = r('vertx'); - lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext; - return lib$es6$promise$asap$$useVertxTimer(); - } catch(e) { - return lib$es6$promise$asap$$useSetTimeout(); - } - } - - var lib$es6$promise$asap$$scheduleFlush; - // Decide what async method to use to triggering processing of queued callbacks: - if (lib$es6$promise$asap$$isNode) { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick(); - } else if (lib$es6$promise$asap$$BrowserMutationObserver) { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver(); - } else if (lib$es6$promise$asap$$isWorker) { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel(); - } else if (lib$es6$promise$asap$$browserWindow === undefined && typeof require === 'function') { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertx(); - } else { - lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout(); - } - - function lib$es6$promise$$internal$$noop() {} - - var lib$es6$promise$$internal$$PENDING = void 0; - var lib$es6$promise$$internal$$FULFILLED = 1; - var lib$es6$promise$$internal$$REJECTED = 2; - - var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject(); - - function lib$es6$promise$$internal$$selfFulfillment() { - return new TypeError("You cannot resolve a promise with itself"); - } - - function lib$es6$promise$$internal$$cannotReturnOwn() { - return new TypeError('A promises callback cannot return that same promise.'); - } - - function lib$es6$promise$$internal$$getThen(promise) { - try { - return promise.then; - } catch(error) { - lib$es6$promise$$internal$$GET_THEN_ERROR.error = error; - return lib$es6$promise$$internal$$GET_THEN_ERROR; - } - } - - function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) { - try { - then.call(value, fulfillmentHandler, rejectionHandler); - } catch(e) { - return e; - } - } - - function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) { - lib$es6$promise$asap$$asap(function(promise) { - var sealed = false; - var error = lib$es6$promise$$internal$$tryThen(then, thenable, function(value) { - if (sealed) { return; } - sealed = true; - if (thenable !== value) { - lib$es6$promise$$internal$$resolve(promise, value); - } else { - lib$es6$promise$$internal$$fulfill(promise, value); - } - }, function(reason) { - if (sealed) { return; } - sealed = true; - - lib$es6$promise$$internal$$reject(promise, reason); - }, 'Settle: ' + (promise._label || ' unknown promise')); - - if (!sealed && error) { - sealed = true; - lib$es6$promise$$internal$$reject(promise, error); - } - }, promise); - } - - function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) { - if (thenable._state === lib$es6$promise$$internal$$FULFILLED) { - lib$es6$promise$$internal$$fulfill(promise, thenable._result); - } else if (thenable._state === lib$es6$promise$$internal$$REJECTED) { - lib$es6$promise$$internal$$reject(promise, thenable._result); - } else { - lib$es6$promise$$internal$$subscribe(thenable, undefined, function(value) { - lib$es6$promise$$internal$$resolve(promise, value); - }, function(reason) { - lib$es6$promise$$internal$$reject(promise, reason); - }); - } - } - - function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable) { - if (maybeThenable.constructor === promise.constructor) { - lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable); - } else { - var then = lib$es6$promise$$internal$$getThen(maybeThenable); - - if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) { - lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error); - } else if (then === undefined) { - lib$es6$promise$$internal$$fulfill(promise, maybeThenable); - } else if (lib$es6$promise$utils$$isFunction(then)) { - lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then); - } else { - lib$es6$promise$$internal$$fulfill(promise, maybeThenable); - } - } - } - - function lib$es6$promise$$internal$$resolve(promise, value) { - if (promise === value) { - lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFulfillment()); - } else if (lib$es6$promise$utils$$objectOrFunction(value)) { - lib$es6$promise$$internal$$handleMaybeThenable(promise, value); - } else { - lib$es6$promise$$internal$$fulfill(promise, value); - } - } - - function lib$es6$promise$$internal$$publishRejection(promise) { - if (promise._onerror) { - promise._onerror(promise._result); - } - - lib$es6$promise$$internal$$publish(promise); - } - - function lib$es6$promise$$internal$$fulfill(promise, value) { - if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } - - promise._result = value; - promise._state = lib$es6$promise$$internal$$FULFILLED; - - if (promise._subscribers.length !== 0) { - lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, promise); - } - } - - function lib$es6$promise$$internal$$reject(promise, reason) { - if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } - promise._state = lib$es6$promise$$internal$$REJECTED; - promise._result = reason; - - lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publishRejection, promise); - } - - function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) { - var subscribers = parent._subscribers; - var length = subscribers.length; - - parent._onerror = null; - - subscribers[length] = child; - subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment; - subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection; - - if (length === 0 && parent._state) { - lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, parent); - } - } - - function lib$es6$promise$$internal$$publish(promise) { - var subscribers = promise._subscribers; - var settled = promise._state; - - if (subscribers.length === 0) { return; } - - var child, callback, detail = promise._result; - - for (var i = 0; i < subscribers.length; i += 3) { - child = subscribers[i]; - callback = subscribers[i + settled]; - - if (child) { - lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail); - } else { - callback(detail); - } - } - - promise._subscribers.length = 0; - } - - function lib$es6$promise$$internal$$ErrorObject() { - this.error = null; - } - - var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject(); - - function lib$es6$promise$$internal$$tryCatch(callback, detail) { - try { - return callback(detail); - } catch(e) { - lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e; - return lib$es6$promise$$internal$$TRY_CATCH_ERROR; - } - } - - function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) { - var hasCallback = lib$es6$promise$utils$$isFunction(callback), - value, error, succeeded, failed; - - if (hasCallback) { - value = lib$es6$promise$$internal$$tryCatch(callback, detail); - - if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) { - failed = true; - error = value.error; - value = null; - } else { - succeeded = true; - } - - if (promise === value) { - lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn()); - return; - } - - } else { - value = detail; - succeeded = true; - } - - if (promise._state !== lib$es6$promise$$internal$$PENDING) { - // noop - } else if (hasCallback && succeeded) { - lib$es6$promise$$internal$$resolve(promise, value); - } else if (failed) { - lib$es6$promise$$internal$$reject(promise, error); - } else if (settled === lib$es6$promise$$internal$$FULFILLED) { - lib$es6$promise$$internal$$fulfill(promise, value); - } else if (settled === lib$es6$promise$$internal$$REJECTED) { - lib$es6$promise$$internal$$reject(promise, value); - } - } - - function lib$es6$promise$$internal$$initializePromise(promise, resolver) { - try { - resolver(function resolvePromise(value){ - lib$es6$promise$$internal$$resolve(promise, value); - }, function rejectPromise(reason) { - lib$es6$promise$$internal$$reject(promise, reason); - }); - } catch(e) { - lib$es6$promise$$internal$$reject(promise, e); - } - } - - function lib$es6$promise$enumerator$$Enumerator(Constructor, input) { - var enumerator = this; - - enumerator._instanceConstructor = Constructor; - enumerator.promise = new Constructor(lib$es6$promise$$internal$$noop); - - if (enumerator._validateInput(input)) { - enumerator._input = input; - enumerator.length = input.length; - enumerator._remaining = input.length; - - enumerator._init(); - - if (enumerator.length === 0) { - lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); - } else { - enumerator.length = enumerator.length || 0; - enumerator._enumerate(); - if (enumerator._remaining === 0) { - lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); - } - } - } else { - lib$es6$promise$$internal$$reject(enumerator.promise, enumerator._validationError()); - } - } - - lib$es6$promise$enumerator$$Enumerator.prototype._validateInput = function(input) { - return lib$es6$promise$utils$$isArray(input); - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._validationError = function() { - return new Error('Array Methods must be provided an Array'); - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._init = function() { - this._result = new Array(this.length); - }; - - var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator; - - lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function() { - var enumerator = this; - - var length = enumerator.length; - var promise = enumerator.promise; - var input = enumerator._input; - - for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { - enumerator._eachEntry(input[i], i); - } - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) { - var enumerator = this; - var c = enumerator._instanceConstructor; - - if (lib$es6$promise$utils$$isMaybeThenable(entry)) { - if (entry.constructor === c && entry._state !== lib$es6$promise$$internal$$PENDING) { - entry._onerror = null; - enumerator._settledAt(entry._state, i, entry._result); - } else { - enumerator._willSettleAt(c.resolve(entry), i); - } - } else { - enumerator._remaining--; - enumerator._result[i] = entry; - } - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) { - var enumerator = this; - var promise = enumerator.promise; - - if (promise._state === lib$es6$promise$$internal$$PENDING) { - enumerator._remaining--; - - if (state === lib$es6$promise$$internal$$REJECTED) { - lib$es6$promise$$internal$$reject(promise, value); - } else { - enumerator._result[i] = value; - } - } - - if (enumerator._remaining === 0) { - lib$es6$promise$$internal$$fulfill(promise, enumerator._result); - } - }; - - lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) { - var enumerator = this; - - lib$es6$promise$$internal$$subscribe(promise, undefined, function(value) { - enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value); - }, function(reason) { - enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason); - }); - }; - function lib$es6$promise$promise$all$$all(entries) { - return new lib$es6$promise$enumerator$$default(this, entries).promise; - } - var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all; - function lib$es6$promise$promise$race$$race(entries) { - /*jshint validthis:true */ - var Constructor = this; - - var promise = new Constructor(lib$es6$promise$$internal$$noop); - - if (!lib$es6$promise$utils$$isArray(entries)) { - lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.')); - return promise; - } - - var length = entries.length; - - function onFulfillment(value) { - lib$es6$promise$$internal$$resolve(promise, value); - } - - function onRejection(reason) { - lib$es6$promise$$internal$$reject(promise, reason); - } - - for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { - lib$es6$promise$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); - } - - return promise; - } - var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race; - function lib$es6$promise$promise$resolve$$resolve(object) { - /*jshint validthis:true */ - var Constructor = this; - - if (object && typeof object === 'object' && object.constructor === Constructor) { - return object; - } - - var promise = new Constructor(lib$es6$promise$$internal$$noop); - lib$es6$promise$$internal$$resolve(promise, object); - return promise; - } - var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve; - function lib$es6$promise$promise$reject$$reject(reason) { - /*jshint validthis:true */ - var Constructor = this; - var promise = new Constructor(lib$es6$promise$$internal$$noop); - lib$es6$promise$$internal$$reject(promise, reason); - return promise; - } - var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject; - - var lib$es6$promise$promise$$counter = 0; - - function lib$es6$promise$promise$$needsResolver() { - throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); - } - - function lib$es6$promise$promise$$needsNew() { - throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); - } - - var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise; - /** - Promise objects represent the eventual result of an asynchronous operation. The - primary way of interacting with a promise is through its `then` method, which - registers callbacks to receive either a promise's eventual value or the reason - why the promise cannot be fulfilled. - - Terminology - ----------- - - - `promise` is an object or function with a `then` method whose behavior conforms to this specification. - - `thenable` is an object or function that defines a `then` method. - - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). - - `exception` is a value that is thrown using the throw statement. - - `reason` is a value that indicates why a promise was rejected. - - `settled` the final resting state of a promise, fulfilled or rejected. - - A promise can be in one of three states: pending, fulfilled, or rejected. - - Promises that are fulfilled have a fulfillment value and are in the fulfilled - state. Promises that are rejected have a rejection reason and are in the - rejected state. A fulfillment value is never a thenable. - - Promises can also be said to *resolve* a value. If this value is also a - promise, then the original promise's settled state will match the value's - settled state. So a promise that *resolves* a promise that rejects will - itself reject, and a promise that *resolves* a promise that fulfills will - itself fulfill. - - - Basic Usage: - ------------ - - ```js - var promise = new Promise(function(resolve, reject) { - // on success - resolve(value); - - // on failure - reject(reason); - }); - - promise.then(function(value) { - // on fulfillment - }, function(reason) { - // on rejection - }); - ``` - - Advanced Usage: - --------------- - - Promises shine when abstracting away asynchronous interactions such as - `XMLHttpRequest`s. - - ```js - function getJSON(url) { - return new Promise(function(resolve, reject){ - var xhr = new XMLHttpRequest(); - - xhr.open('GET', url); - xhr.onreadystatechange = handler; - xhr.responseType = 'json'; - xhr.setRequestHeader('Accept', 'application/json'); - xhr.send(); - - function handler() { - if (this.readyState === this.DONE) { - if (this.status === 200) { - resolve(this.response); - } else { - reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); - } - } - }; - }); - } - - getJSON('/posts.json').then(function(json) { - // on fulfillment - }, function(reason) { - // on rejection - }); - ``` - - Unlike callbacks, promises are great composable primitives. - - ```js - Promise.all([ - getJSON('/posts'), - getJSON('/comments') - ]).then(function(values){ - values[0] // => postsJSON - values[1] // => commentsJSON - - return values; - }); - ``` - - @class Promise - @param {function} resolver - Useful for tooling. - @constructor - */ - function lib$es6$promise$promise$$Promise(resolver) { - this._id = lib$es6$promise$promise$$counter++; - this._state = undefined; - this._result = undefined; - this._subscribers = []; - - if (lib$es6$promise$$internal$$noop !== resolver) { - if (!lib$es6$promise$utils$$isFunction(resolver)) { - lib$es6$promise$promise$$needsResolver(); - } - - if (!(this instanceof lib$es6$promise$promise$$Promise)) { - lib$es6$promise$promise$$needsNew(); - } - - lib$es6$promise$$internal$$initializePromise(this, resolver); - } - } - - lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default; - lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default; - lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default; - lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default; - lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler; - lib$es6$promise$promise$$Promise._setAsap = lib$es6$promise$asap$$setAsap; - lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$asap; - - lib$es6$promise$promise$$Promise.prototype = { - constructor: lib$es6$promise$promise$$Promise, - - /** - The primary way of interacting with a promise is through its `then` method, - which registers callbacks to receive either a promise's eventual value or the - reason why the promise cannot be fulfilled. - - ```js - findUser().then(function(user){ - // user is available - }, function(reason){ - // user is unavailable, and you are given the reason why - }); - ``` - - Chaining - -------- - - The return value of `then` is itself a promise. This second, 'downstream' - promise is resolved with the return value of the first promise's fulfillment - or rejection handler, or rejected if the handler throws an exception. - - ```js - findUser().then(function (user) { - return user.name; - }, function (reason) { - return 'default name'; - }).then(function (userName) { - // If `findUser` fulfilled, `userName` will be the user's name, otherwise it - // will be `'default name'` - }); - - findUser().then(function (user) { - throw new Error('Found user, but still unhappy'); - }, function (reason) { - throw new Error('`findUser` rejected and we're unhappy'); - }).then(function (value) { - // never reached - }, function (reason) { - // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. - // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. - }); - ``` - If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. - - ```js - findUser().then(function (user) { - throw new PedagogicalException('Upstream error'); - }).then(function (value) { - // never reached - }).then(function (value) { - // never reached - }, function (reason) { - // The `PedgagocialException` is propagated all the way down to here - }); - ``` - - Assimilation - ------------ - - Sometimes the value you want to propagate to a downstream promise can only be - retrieved asynchronously. This can be achieved by returning a promise in the - fulfillment or rejection handler. The downstream promise will then be pending - until the returned promise is settled. This is called *assimilation*. - - ```js - findUser().then(function (user) { - return findCommentsByAuthor(user); - }).then(function (comments) { - // The user's comments are now available - }); - ``` - - If the assimliated promise rejects, then the downstream promise will also reject. - - ```js - findUser().then(function (user) { - return findCommentsByAuthor(user); - }).then(function (comments) { - // If `findCommentsByAuthor` fulfills, we'll have the value here - }, function (reason) { - // If `findCommentsByAuthor` rejects, we'll have the reason here - }); - ``` - - Simple Example - -------------- - - Synchronous Example - - ```javascript - var result; - - try { - result = findResult(); - // success - } catch(reason) { - // failure - } - ``` - - Errback Example - - ```js - findResult(function(result, err){ - if (err) { - // failure - } else { - // success - } - }); - ``` - - Promise Example; - - ```javascript - findResult().then(function(result){ - // success - }, function(reason){ - // failure - }); - ``` - - Advanced Example - -------------- - - Synchronous Example - - ```javascript - var author, books; - - try { - author = findAuthor(); - books = findBooksByAuthor(author); - // success - } catch(reason) { - // failure - } - ``` - - Errback Example - - ```js - - function foundBooks(books) { - - } - - function failure(reason) { - - } - - findAuthor(function(author, err){ - if (err) { - failure(err); - // failure - } else { - try { - findBoooksByAuthor(author, function(books, err) { - if (err) { - failure(err); - } else { - try { - foundBooks(books); - } catch(reason) { - failure(reason); - } - } - }); - } catch(error) { - failure(err); - } - // success - } - }); - ``` - - Promise Example; - - ```javascript - findAuthor(). - then(findBooksByAuthor). - then(function(books){ - // found books - }).catch(function(reason){ - // something went wrong - }); - ``` - - @method then - @param {Function} onFulfilled - @param {Function} onRejected - Useful for tooling. - @return {Promise} - */ - then: function(onFulfillment, onRejection) { - var parent = this; - var state = parent._state; - - if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) { - return this; - } - - var child = new this.constructor(lib$es6$promise$$internal$$noop); - var result = parent._result; - - if (state) { - var callback = arguments[state - 1]; - lib$es6$promise$asap$$asap(function(){ - lib$es6$promise$$internal$$invokeCallback(state, child, callback, result); - }); - } else { - lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection); - } - - return child; - }, - - /** - `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same - as the catch block of a try/catch statement. - - ```js - function findAuthor(){ - throw new Error('couldn't find that author'); - } - - // synchronous - try { - findAuthor(); - } catch(reason) { - // something went wrong - } - - // async with promises - findAuthor().catch(function(reason){ - // something went wrong - }); - ``` - - @method catch - @param {Function} onRejection - Useful for tooling. - @return {Promise} - */ - 'catch': function(onRejection) { - return this.then(null, onRejection); - } - }; - function lib$es6$promise$polyfill$$polyfill() { - var local; - - if (typeof global !== 'undefined') { - local = global; - } else if (typeof self !== 'undefined') { - local = self; - } else { - try { - local = Function('return this')(); - } catch (e) { - throw new Error('polyfill failed because global object is unavailable in this environment'); - } - } - - var P = local.Promise; - - if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) { - return; - } - - local.Promise = lib$es6$promise$promise$$default; - } - var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill; - - var lib$es6$promise$umd$$ES6Promise = { - 'Promise': lib$es6$promise$promise$$default, - 'polyfill': lib$es6$promise$polyfill$$default - }; - - /* global define:true module:true window: true */ - if (typeof define === 'function' && define['amd']) { - define(function() { return lib$es6$promise$umd$$ES6Promise; }); - } else if (typeof module !== 'undefined' && module['exports']) { - module['exports'] = lib$es6$promise$umd$$ES6Promise; - } else if (typeof this !== 'undefined') { - this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise; - } - - lib$es6$promise$polyfill$$default(); -}).call(this); - - -/** - * @constructor - */ -function DefaultHttpRequest() { - - /** - * @name _promiseFactory - * @type DefaultPromiseFactory - */ - - /** - * @param {XMLHttpRequest} xhr - * @param {object.} headers - */ - function setHeaders(xhr, headers) { - var keys = Object.keys(headers); - - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - var value = headers[key]; - - xhr.setRequestHeader(key, value); - } - } - - /** - * @param {string} url - * @param {{ headers: object. }} [config] - * @returns {Promise} - */ - this.getJSON = function (url, config) { - return _promiseFactory.create(function (resolve, reject) { - - try { - var xhr = new XMLHttpRequest(); - xhr.open("GET", url); - xhr.responseType = "json"; - - if (config) { - if (config.headers) { - setHeaders(xhr, config.headers); - } - } - - xhr.onload = function () { - try { - if (xhr.status === 200) { - var response = ""; - // To support IE9 get the response from xhr.responseText not xhr.response - if (window.XDomainRequest) { - response = xhr.responseText; - } else { - response = xhr.response; - } - if (typeof response === "string") { - response = JSON.parse(response); - } - resolve(response); - } - else { - reject(Error(xhr.statusText + "(" + xhr.status + ")")); - } - } - catch (err) { - reject(err); - } - }; - - xhr.onerror = function () { - reject(Error("Network error")); - }; - - xhr.send(); - } - catch (err) { - return reject(err); - } - }); - }; -} - -_httpRequest = new DefaultHttpRequest(); - -/** - * @constructor - * @param {Promise} promise - */ -function DefaultPromise(promise) { - - /** - * @param {function(*):*} successCallback - * @param {function(*):*} errorCallback - * @returns {DefaultPromise} - */ - this.then = function (successCallback, errorCallback) { - var childPromise = promise.then(successCallback, errorCallback); - - return new DefaultPromise(childPromise); - }; - - /** - * - * @param {function(*):*} errorCallback - * @returns {DefaultPromise} - */ - this.catch = function (errorCallback) { - var childPromise = promise.catch(errorCallback); - - return new DefaultPromise(childPromise); - }; -} - -/** - * @constructor - */ -function DefaultPromiseFactory() { - - this.resolve = function (value) { - return new DefaultPromise(Promise.resolve(value)); - }; - - this.reject = function (reason) { - return new DefaultPromise(Promise.reject(reason)); - }; - - /** - * @param {function(resolve:function, reject:function)} callback - * @returns {DefaultPromise} - */ - this.create = function (callback) { - return new DefaultPromise(new Promise(callback)); - }; -} - -_promiseFactory = new DefaultPromiseFactory(); -/* - * Copyright 2015 Dominick Baier, Brock Allen - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -function log() { - //var param = [].join.call(arguments); - //console.log(param); -} - -function copy(obj, target) { - target = target || {}; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - target[key] = obj[key]; - } - } - return target; -} - -function rand() { - return ((Date.now() + Math.random()) * Math.random()).toString().replace(".", ""); -} - -function resolve(param) { - return _promiseFactory.resolve(param); -} - -function error(message) { - return _promiseFactory.reject(Error(message)); -} - -function parseOidcResult(queryString) { - log("parseOidcResult"); - - queryString = queryString || location.hash; - - var idx = queryString.lastIndexOf("#"); - if (idx >= 0) { - queryString = queryString.substr(idx + 1); - } - - var params = {}, - regex = /([^&=]+)=([^&]*)/g, - m; - - var counter = 0; - while (m = regex.exec(queryString)) { - params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]); - if (counter++ > 50) { - return { - error: "Response exceeded expected number of parameters" - }; - } - } - - for (var prop in params) { - return params; - } -} - -function getJson(url, token) { - log("getJson", url); - - var config = {}; - - if (token) { - config.headers = {"Authorization": "Bearer " + token}; - } - - return _httpRequest.getJSON(url, config); -} - -function OidcClient(settings) { - this._settings = settings || {}; - - if (!this._settings.request_state_key) { - this._settings.request_state_key = "OidcClient.request_state"; - } - - if (!this._settings.request_state_store) { - this._settings.request_state_store = window.localStorage; - } - - if (typeof this._settings.load_user_profile === 'undefined') { - this._settings.load_user_profile = true; - } - - if (typeof this._settings.filter_protocol_claims === 'undefined') { - this._settings.filter_protocol_claims = true; - } - - if (this._settings.authority && this._settings.authority.indexOf('.well-known/openid-configuration') < 0) { - if (this._settings.authority[this._settings.authority.length - 1] !== '/') { - this._settings.authority += '/'; - } - this._settings.authority += '.well-known/openid-configuration'; - } - - if (!this._settings.response_type) { - this._settings.response_type = "id_token token"; - } - - Object.defineProperty(this, "isOidc", { - get: function () { - if (this._settings.response_type) { - var result = this._settings.response_type.split(/\s+/g).filter(function (item) { - return item === "id_token"; - }); - return !!(result[0]); - } - return false; - } - }); - - Object.defineProperty(this, "isOAuth", { - get: function () { - if (this._settings.response_type) { - var result = this._settings.response_type.split(/\s+/g).filter(function (item) { - return item === "token"; - }); - return !!(result[0]); - } - return false; - } - }); -} - -OidcClient.parseOidcResult = parseOidcResult; - -OidcClient.prototype.loadMetadataAsync = function () { - log("OidcClient.loadMetadataAsync"); - - var settings = this._settings; - - if (settings.metadata) { - return resolve(settings.metadata); - } - - if (!settings.authority) { - return error("No authority configured"); - } - - return getJson(settings.authority) - .then(function (metadata) { - settings.metadata = metadata; - return metadata; - }, function (err) { - return error("Failed to load metadata (" + err && err.message + ")"); - }); -}; - -OidcClient.prototype.loadX509SigningKeyAsync = function () { - log("OidcClient.loadX509SigningKeyAsync"); - - var settings = this._settings; - - function getKeyAsync(jwks) { - if (!jwks.keys || !jwks.keys.length) { - return error("Signing keys empty"); - } - - var key = jwks.keys[0]; - if (key.kty !== "RSA") { - return error("Signing key not RSA"); - } - - if (!key.x5c || !key.x5c.length) { - return error("RSA keys empty"); - } - - return resolve(key.x5c[0]); - } - - if (settings.jwks) { - return getKeyAsync(settings.jwks); - } - - return this.loadMetadataAsync().then(function (metadata) { - if (!metadata.jwks_uri) { - return error("Metadata does not contain jwks_uri"); - } - - return getJson(metadata.jwks_uri).then(function (jwks) { - settings.jwks = jwks; - return getKeyAsync(jwks); - }, function (err) { - return error("Failed to load signing keys (" + err && err.message + ")"); - }); - }); -}; - -OidcClient.prototype.loadUserProfile = function (access_token) { - log("OidcClient.loadUserProfile"); - - return this.loadMetadataAsync().then(function (metadata) { - - if (!metadata.userinfo_endpoint) { - return error("Metadata does not contain userinfo_endpoint"); - } - - return getJson(metadata.userinfo_endpoint, access_token); - }); -} - -OidcClient.prototype.loadAuthorizationEndpoint = function () { - log("OidcClient.loadAuthorizationEndpoint"); - - if (this._settings.authorization_endpoint) { - return resolve(this._settings.authorization_endpoint); - } - - if (!this._settings.authority) { - return error("No authorization_endpoint configured"); - } - - return this.loadMetadataAsync().then(function (metadata) { - if (!metadata.authorization_endpoint) { - return error("Metadata does not contain authorization_endpoint"); - } - - return metadata.authorization_endpoint; - }); -}; - -OidcClient.prototype.createTokenRequestAsync = function () { - log("OidcClient.createTokenRequestAsync"); - - var client = this; - var settings = client._settings; - - return client.loadAuthorizationEndpoint().then(function (authorization_endpoint) { - - var state = rand(); - var url = authorization_endpoint + "?state=" + encodeURIComponent(state); - - if (client.isOidc) { - var nonce = rand(); - url += "&nonce=" + encodeURIComponent(nonce); - } - - var required = ["client_id", "redirect_uri", "response_type", "scope"]; - required.forEach(function (key) { - var value = settings[key]; - if (value) { - url += "&" + key + "=" + encodeURIComponent(value); - } - }); - - var optional = ["prompt", "display", "max_age", "ui_locales", "id_token_hint", "login_hint", "acr_values"]; - optional.forEach(function (key) { - var value = settings[key]; - if (value) { - url += "&" + key + "=" + encodeURIComponent(value); - } - }); - - var request_state = { - oidc: client.isOidc, - oauth: client.isOAuth, - state: state - }; - - if (nonce) { - request_state["nonce"] = nonce; - } - - settings.request_state_store.setItem(settings.request_state_key, JSON.stringify(request_state)); - - return { - request_state: request_state, - url: url - }; - }); -} - -OidcClient.prototype.createLogoutRequestAsync = function (id_token_hint) { - log("OidcClient.createLogoutRequestAsync"); - - var settings = this._settings; - return this.loadMetadataAsync().then(function (metadata) { - if (!metadata.end_session_endpoint) { - return error("No end_session_endpoint in metadata"); - } + OidcClient.prototype.loadUserProfile = function (access_token) { + log("OidcClient.loadUserProfile"); - var url = metadata.end_session_endpoint; - if (id_token_hint && settings.post_logout_redirect_uri) { - url += "?post_logout_redirect_uri=" + encodeURIComponent(settings.post_logout_redirect_uri); - url += "&id_token_hint=" + encodeURIComponent(id_token_hint); - } - return url; - }); -} + return this.loadMetadataAsync().then(function (metadata) { -OidcClient.prototype.validateIdTokenAsync = function (id_token, nonce, access_token) { - log("OidcClient.validateIdTokenAsync"); + if (!metadata.userinfo_endpoint) { + return error("Metadata does not contain userinfo_endpoint"); + } - var client = this; - var settings = client._settings; + return getJson(metadata.userinfo_endpoint, access_token); + }); + } + + OidcClient.prototype.loadAuthorizationEndpoint = function () { + log("OidcClient.loadAuthorizationEndpoint"); + + if (this._settings.authorization_endpoint) { + return resolve(this._settings.authorization_endpoint); + } + + if (!this._settings.authority) { + return error("No authorization_endpoint configured"); + } + + return this.loadMetadataAsync().then(function (metadata) { + if (!metadata.authorization_endpoint) { + return error("Metadata does not contain authorization_endpoint"); + } + + return metadata.authorization_endpoint; + }); + }; + + OidcClient.prototype.createTokenRequestAsync = function () { + log("OidcClient.createTokenRequestAsync"); + + var client = this; + var settings = client._settings; + + return client.loadAuthorizationEndpoint().then(function (authorization_endpoint) { + + var state = rand(); + var url = authorization_endpoint + "?state=" + encodeURIComponent(state); + + if (client.isOidc) { + var nonce = rand(); + url += "&nonce=" + encodeURIComponent(nonce); + } + + var required = ["client_id", "redirect_uri", "response_type", "scope"]; + required.forEach(function (key) { + var value = settings[key]; + if (value) { + url += "&" + key + "=" + encodeURIComponent(value); + } + }); + + var optional = ["prompt", "display", "max_age", "ui_locales", "id_token_hint", "login_hint", "acr_values"]; + optional.forEach(function (key) { + var value = settings[key]; + if (value) { + url += "&" + key + "=" + encodeURIComponent(value); + } + }); + + var request_state = { + oidc: client.isOidc, + oauth: client.isOAuth, + state: state + }; + + if (nonce) { + request_state["nonce"] = nonce; + } + + settings.request_state_store.setItem(settings.request_state_key, JSON.stringify(request_state)); + + return { + request_state: request_state, + url: url + }; + }); + } + + OidcClient.prototype.createLogoutRequestAsync = function (id_token_hint) { + log("OidcClient.createLogoutRequestAsync"); + + var settings = this._settings; + return this.loadMetadataAsync().then(function (metadata) { + if (!metadata.end_session_endpoint) { + return error("No end_session_endpoint in metadata"); + } + + var url = metadata.end_session_endpoint; + if (id_token_hint && settings.post_logout_redirect_uri) { + url += "?post_logout_redirect_uri=" + encodeURIComponent(settings.post_logout_redirect_uri); + url += "&id_token_hint=" + encodeURIComponent(id_token_hint); + } + return url; + }); + } + + OidcClient.prototype.validateIdTokenAsync = function (id_token, nonce, access_token) { + log("OidcClient.validateIdTokenAsync"); + + var client = this; + var settings = client._settings; + + return client.loadX509SigningKeyAsync().then(function (cert) { + + var jws = new KJUR.jws.JWS(); + if (jws.verifyJWSByPemX509Cert(id_token, cert)) { + var id_token_contents = JSON.parse(jws.parsedJWS.payloadS); + + if (nonce !== id_token_contents.nonce) { + return error("Invalid nonce"); + } + + return client.loadMetadataAsync().then(function (metadata) { + + if (id_token_contents.iss !== metadata.issuer) { + return error("Invalid issuer"); + } + + if (id_token_contents.aud !== settings.client_id) { + return error("Invalid audience"); + } + + var now = parseInt(Date.now() / 1000); + + // accept tokens issues up to 5 mins ago + var diff = now - id_token_contents.iat; + if (diff > (5 * 60)) { + return error("Token issued too long ago"); + } + + if (id_token_contents.exp < now) { + return error("Token expired"); + } + + if (access_token && settings.load_user_profile) { + // if we have an access token, then call user info endpoint + return client.loadUserProfile(access_token, id_token_contents).then(function (profile) { + return copy(profile, id_token_contents); + }); + } + else { + // no access token, so we have all our claims + return id_token_contents; + } + + }); + } + else { + return error("JWT failed to validate"); + } + + }); + + }; + + OidcClient.prototype.validateAccessTokenAsync = function (id_token_contents, access_token) { + log("OidcClient.validateAccessTokenAsync"); + + if (!id_token_contents.at_hash) { + return error("No at_hash in id_token"); + } + + var hash = KJUR.crypto.Util.sha256(access_token); + var left = hash.substr(0, hash.length / 2); + var left_b64u = hextob64u(left); + + if (left_b64u !== id_token_contents.at_hash) { + return error("at_hash failed to validate"); + } + + return resolve(); + }; - return client.loadX509SigningKeyAsync().then(function (cert) { + OidcClient.prototype.validateIdTokenAndAccessTokenAsync = function (id_token, nonce, access_token) { + log("OidcClient.validateIdTokenAndAccessTokenAsync"); - var jws = new KJUR.jws.JWS(); - if (jws.verifyJWSByPemX509Cert(id_token, cert)) { - var id_token_contents = JSON.parse(jws.parsedJWS.payloadS); + var client = this; - if (nonce !== id_token_contents.nonce) { - return error("Invalid nonce"); - } + return client.validateIdTokenAsync(id_token, nonce, access_token).then(function (id_token_contents) { - return client.loadMetadataAsync().then(function (metadata) { + return client.validateAccessTokenAsync(id_token_contents, access_token).then(function () { - if (id_token_contents.iss !== metadata.issuer) { - return error("Invalid issuer"); - } + return id_token_contents; - if (id_token_contents.aud !== settings.client_id) { - return error("Invalid audience"); - } + }); - var now = parseInt(Date.now() / 1000); + }); + } + + OidcClient.prototype.processResponseAsync = function (queryString) { + log("OidcClient.processResponseAsync"); + + var client = this; + var settings = client._settings; + + var request_state = settings.request_state_store.getItem(settings.request_state_key); + settings.request_state_store.removeItem(settings.request_state_key); + + if (!request_state) { + return error("No request state loaded"); + } + + request_state = JSON.parse(request_state); + if (!request_state) { + return error("No request state loaded"); + } + + if (!request_state.state) { + return error("No state loaded"); + } + + var result = parseOidcResult(queryString); + if (!result) { + return error("No OIDC response"); + } + + if (result.error) { + return error(result.error); + } + + if (result.state !== request_state.state) { + return error("Invalid state"); + } - // accept tokens issues up to 5 mins ago - var diff = now - id_token_contents.iat; - if (diff > (5 * 60)) { - return error("Token issued too long ago"); - } + if (request_state.oidc) { + if (!result.id_token) { + return error("No identity token"); + } - if (id_token_contents.exp < now) { - return error("Token expired"); - } + if (!request_state.nonce) { + return error("No nonce loaded"); + } + } + + if (request_state.oauth) { + if (!result.access_token) { + return error("No access token"); + } + + if (!result.token_type || result.token_type.toLowerCase() !== "bearer") { + return error("Invalid token type"); + } + + if (!result.expires_in) { + return error("No token expiration"); + } + } - if (access_token && settings.load_user_profile) { - // if we have an access token, then call user info endpoint - return client.loadUserProfile(access_token, id_token_contents).then(function (profile) { - return copy(profile, id_token_contents); - }); - } - else { - // no access token, so we have all our claims - return id_token_contents; - } - - }); - } - else { - return error("JWT failed to validate"); - } + var promise = resolve(); + if (request_state.oidc && request_state.oauth) { + promise = client.validateIdTokenAndAccessTokenAsync(result.id_token, request_state.nonce, result.access_token); + } + else if (request_state.oidc) { + promise = client.validateIdTokenAsync(result.id_token, request_state.nonce); + } - }); - -}; - -OidcClient.prototype.validateAccessTokenAsync = function (id_token_contents, access_token) { - log("OidcClient.validateAccessTokenAsync"); + return promise.then(function (profile) { + if (profile && settings.filter_protocol_claims) { + var remove = ["nonce", "at_hash", "iat", "nbf", "exp", "aud", "iss"]; + remove.forEach(function (key) { + delete profile[key]; + }); + } + + return { + profile: profile, + id_token: result.id_token, + access_token: result.access_token, + expires_in: result.expires_in, + scope: result.scope, + session_state: result.session_state + }; + }); + } - if (!id_token_contents.at_hash) { - return error("No at_hash in id_token"); - } - - var hash = KJUR.crypto.Util.sha256(access_token); - var left = hash.substr(0, hash.length / 2); - var left_b64u = hextob64u(left); - - if (left_b64u !== id_token_contents.at_hash) { - return error("at_hash failed to validate"); - } - - return resolve(); -}; - -OidcClient.prototype.validateIdTokenAndAccessTokenAsync = function (id_token, nonce, access_token) { - log("OidcClient.validateIdTokenAndAccessTokenAsync"); - - var client = this; - - return client.validateIdTokenAsync(id_token, nonce, access_token).then(function (id_token_contents) { - - return client.validateAccessTokenAsync(id_token_contents, access_token).then(function () { - - return id_token_contents; - - }); - - }); -} - -OidcClient.prototype.processResponseAsync = function (queryString) { - log("OidcClient.processResponseAsync"); - - var client = this; - var settings = client._settings; - - var request_state = settings.request_state_store.getItem(settings.request_state_key); - settings.request_state_store.removeItem(settings.request_state_key); - - if (!request_state) { - return error("No request state loaded"); - } - - request_state = JSON.parse(request_state); - if (!request_state) { - return error("No request state loaded"); - } - - if (!request_state.state) { - return error("No state loaded"); - } - - var result = parseOidcResult(queryString); - if (!result) { - return error("No OIDC response"); - } - - if (result.error) { - return error(result.error); - } - - if (result.state !== request_state.state) { - return error("Invalid state"); - } - - if (request_state.oidc) { - if (!result.id_token) { - return error("No identity token"); - } - - if (!request_state.nonce) { - return error("No nonce loaded"); - } - } - - if (request_state.oauth) { - if (!result.access_token) { - return error("No access token"); - } - - if (!result.token_type || result.token_type.toLowerCase() !== "bearer") { - return error("Invalid token type"); - } - - if (!result.expires_in) { - return error("No token expiration"); - } - } - - var promise = resolve(); - if (request_state.oidc && request_state.oauth) { - promise = client.validateIdTokenAndAccessTokenAsync(result.id_token, request_state.nonce, result.access_token); - } - else if (request_state.oidc) { - promise = client.validateIdTokenAsync(result.id_token, request_state.nonce); - } - - return promise.then(function (profile) { - if (profile && settings.filter_protocol_claims) { - var remove = ["nonce", "at_hash", "iat", "nbf", "exp", "aud", "iss"]; - remove.forEach(function (key) { - delete profile[key]; - }); - } - - return { - profile: profile, - id_token: result.id_token, - access_token: result.access_token, - expires_in: result.expires_in, - scope: result.scope, - session_state : result.session_state - }; - }); -} - - // exports - OidcClient._promiseFactory = _promiseFactory; - OidcClient._httpRequest = _httpRequest; - window.OidcClient = OidcClient; + // exports + OidcClient._promiseFactory = _promiseFactory; + OidcClient._httpRequest = _httpRequest; + window.OidcClient = OidcClient; })(); (function () { -/* -* Copyright 2014-2016 Dominick Baier, Brock Allen -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -// globals -var _promiseFactory = OidcClient._promiseFactory; -var _httpRequest = OidcClient._httpRequest; - -function copy(obj, target) { - target = target || {}; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - target[key] = obj[key]; - } - } - return target; -} - -function Token(other) { - if (other) { - this.profile = other.profile; - this.id_token = other.id_token; - this.access_token = other.access_token; - if (other.access_token) { - this.expires_at = parseInt(other.expires_at); - } - else if (other.id_token) { - this.expires_at = other.profile.exp; - } - else { - throw Error("Either access_token or id_token required."); - } - this.scope = other.scope; - this.session_state = other.session_state; - } - else { - this.expires_at = 0; - } - - Object.defineProperty(this, "scopes", { - get: function () { - return (this.scope || "").split(" "); - } - }); - - Object.defineProperty(this, "expired", { - get: function () { - var now = parseInt(Date.now() / 1000); - return this.expires_at < now; - } - }); - - Object.defineProperty(this, "expires_in", { - get: function () { - var now = parseInt(Date.now() / 1000); - return this.expires_at - now; - } - }); -} - -Token.fromResponse = function (response) { - if (response.access_token) { - var now = parseInt(Date.now() / 1000); - response.expires_at = now + parseInt(response.expires_in); - } - return new Token(response); -} - -Token.fromJSON = function (json) { - if (json) { - try { - var obj = JSON.parse(json); - return new Token(obj); - } - catch (e) { - } - } - return new Token(null); -} - -Token.prototype.toJSON = function () { - return JSON.stringify({ - profile: this.profile, - id_token: this.id_token, - access_token: this.access_token, - expires_at: this.expires_at, - scope: this.scopes.join(" "), - session_state: this.session_state - }); -} - -function FrameLoader(url, config) { - this.url = url; - config = config || {}; - config.cancelDelay = config.cancelDelay || 5000; - this.config = config; -} - -FrameLoader.prototype.loadAsync = function (url) { - var self = this; - url = url || this.url; - - if (!url) { - return _promiseFactory.reject(Error("No url provided")); - } - - return _promiseFactory.create(function (resolve, reject) { - var frame = window.document.createElement("iframe"); - frame.style.display = "none"; - - function cleanup() { - window.removeEventListener("message", message, false); - if (handle) { - window.clearTimeout(handle); - } - handle = null; - window.document.body.removeChild(frame); - } - - function cancel(e) { - cleanup(); - reject(); - } - - function message(e) { - if (handle && e.origin === location.protocol + "//" + location.host && e.source == frame.contentWindow) { - cleanup(); - resolve(e.data); - } - } - - var handle = window.setTimeout(cancel, self.config.cancelDelay); - window.addEventListener("message", message, false); - window.document.body.appendChild(frame); - frame.src = url; - }); -} - -function loadToken(mgr) { - mgr._token = null; - if (mgr._settings.persist) { - var tokenJson = mgr._settings.store.getItem(mgr._settings.persistKey); - if (tokenJson) { - var token = Token.fromJSON(tokenJson); - if (!token.expired) { - mgr._token = token; - } - } - } -} - -function configureTokenExpiring(mgr) { - - function callback() { - handle = null; - mgr._callTokenExpiring(); - } - - var handle = null; - - function cancel() { - if (handle) { - window.clearTimeout(handle); - handle = null; - } - } - - function setup(duration) { - handle = window.setTimeout(callback, duration * 1000); - } - - function configure() { - cancel(); - - if (!mgr.expired) { - var duration = mgr.expires_in; - if (duration > 60) { - setup(duration - 60); - } - else { - callback(); - } - } - } - - configure(); - - mgr.addOnTokenObtained(configure); - mgr.addOnTokenRemoved(cancel); -} - -function configureAutoRenewToken(mgr) { - - if (mgr._settings.silent_redirect_uri && mgr._settings.silent_renew) { - - mgr.addOnTokenExpiring(function () { - mgr.renewTokenSilentAsync().catch(function (e) { - mgr._callSilentTokenRenewFailed(); - console.error(e && e.message || "Unknown error"); - }); - }); - - } -} - -function configureTokenExpired(mgr) { - - function callback() { - handle = null; - - if (mgr._token) { - mgr.saveToken(null); - } - - mgr._callTokenExpired(); - } - - var handle = null; - - function cancel() { - if (handle) { - window.clearTimeout(handle); - handle = null; - } - } - - function setup(duration) { - handle = window.setTimeout(callback, duration * 1000); - } - - function configure() { - cancel(); - if (mgr.expires_in > 0) { - // register 1 second beyond expiration so we don't get into edge conditions for expiration - setup(mgr.expires_in + 1); - } - } - - configure(); - - mgr.addOnTokenObtained(configure); - mgr.addOnTokenRemoved(cancel); -} - -function TokenManager(settings) { - this._settings = settings || {}; - - if (typeof this._settings.persist === 'undefined') { - this._settings.persist = true; - } - this._settings.store = this._settings.store || window.localStorage; - this._settings.persistKey = this._settings.persistKey || "TokenManager.token"; - - this.oidcClient = new OidcClient(this._settings); - - this._callbacks = { - tokenRemovedCallbacks: [], - tokenExpiringCallbacks: [], - tokenExpiredCallbacks: [], - tokenObtainedCallbacks: [], - silentTokenRenewFailedCallbacks: [] - }; - - Object.defineProperty(this, "profile", { - get: function () { - if (this._token) { - return this._token.profile; - } - } - }); - Object.defineProperty(this, "id_token", { - get: function () { - if (this._token) { - return this._token.id_token; - } - } - }); - Object.defineProperty(this, "access_token", { - get: function () { - if (this._token && !this._token.expired) { - return this._token.access_token; - } - } - }); - Object.defineProperty(this, "expired", { - get: function () { - if (this._token) { - return this._token.expired; - } - return true; - } - }); - Object.defineProperty(this, "expires_in", { - get: function () { - if (this._token) { - return this._token.expires_in; - } - return 0; - } - }); - Object.defineProperty(this, "expires_at", { - get: function () { - if (this._token) { - return this._token.expires_at; - } - return 0; - } - }); - Object.defineProperty(this, "scope", { - get: function () { - return this._token && this._token.scope; - } - }); - Object.defineProperty(this, "scopes", { - get: function () { - if (this._token) { - return [].concat(this._token.scopes); - } - return []; - } - }); - Object.defineProperty(this, "session_state", { - get: function () { - if (this._token) { - return this._token.session_state; - } - } - }); - - var mgr = this; - loadToken(mgr); - if (mgr._settings.store instanceof window.localStorage.constructor) { - window.addEventListener("storage", function (e) { - if (e.key === mgr._settings.persistKey) { - loadToken(mgr); - - if (mgr._token) { - mgr._callTokenObtained(); - } - else { - mgr._callTokenRemoved(); - } - } - }); - } - configureTokenExpired(mgr); - configureAutoRenewToken(mgr); - - // delay this so consuming apps can register for callbacks first - window.setTimeout(function () { - configureTokenExpiring(mgr); - }, 0); -} - -/** - * @param {{ create:function(successCallback:function(), errorCallback:function()):Promise, resolve:function(value:*):Promise, reject:function():Promise}} promiseFactory - */ -TokenManager.setPromiseFactory = function (promiseFactory) { - _promiseFactory = promiseFactory; -}; - -/** - * @param {{getJSON:function(url:string, config:{ headers: object. })}} httpRequest - */ -TokenManager.setHttpRequest = function (httpRequest) { - if ((typeof httpRequest !== 'object') || (typeof httpRequest.getJSON !== 'function')) { - throw Error('The provided value is not a valid http request.'); - } - - _httpRequest = httpRequest; -}; - -TokenManager.prototype._callTokenRemoved = function () { - this._callbacks.tokenRemovedCallbacks.forEach(function (cb) { - cb(); - }); -} - -TokenManager.prototype._callTokenExpiring = function () { - this._callbacks.tokenExpiringCallbacks.forEach(function (cb) { - cb(); - }); -} - -TokenManager.prototype._callTokenExpired = function () { - this._callbacks.tokenExpiredCallbacks.forEach(function (cb) { - cb(); - }); -} - -TokenManager.prototype._callTokenObtained = function () { - this._callbacks.tokenObtainedCallbacks.forEach(function (cb) { - cb(); - }); -} - -TokenManager.prototype._callSilentTokenRenewFailed = function () { - this._callbacks.silentTokenRenewFailedCallbacks.forEach(function (cb) { - cb(); - }); -} - -TokenManager.prototype.saveToken = function (token) { - if (token && !(token instanceof Token)) { - token = Token.fromResponse(token); - } - - this._token = token; - - if (this._settings.persist && !this.expired) { - this._settings.store.setItem(this._settings.persistKey, token.toJSON()); - } - else { - this._settings.store.removeItem(this._settings.persistKey); - } - - if (token) { - this._callTokenObtained(); - } - else { - this._callTokenRemoved(); - } -} - -TokenManager.prototype.addOnTokenRemoved = function (cb) { - this._callbacks.tokenRemovedCallbacks.push(cb); -} - -TokenManager.prototype.addOnTokenObtained = function (cb) { - this._callbacks.tokenObtainedCallbacks.push(cb); -} - -TokenManager.prototype.addOnTokenExpiring = function (cb) { - this._callbacks.tokenExpiringCallbacks.push(cb); -} - -TokenManager.prototype.addOnTokenExpired = function (cb) { - this._callbacks.tokenExpiredCallbacks.push(cb); -} - -TokenManager.prototype.addOnSilentTokenRenewFailed = function (cb) { - this._callbacks.silentTokenRenewFailedCallbacks.push(cb); -} - -TokenManager.prototype.removeToken = function () { - this.saveToken(null); -} - -TokenManager.prototype.redirectForToken = function () { - var oidc = this.oidcClient; - return oidc.createTokenRequestAsync().then(function (request) { - window.location = request.url; - }, function (err) { - console.error("TokenManager.redirectForToken error: " + (err && err.message || "Unknown error")); - return _promiseFactory.reject(err); - }); -} - -TokenManager.prototype.redirectForLogout = function () { - var mgr = this; - return mgr.oidcClient.createLogoutRequestAsync(mgr.id_token).then(function (url) { - mgr.removeToken(); - window.location = url; - }, function (err) { - console.error("TokenManager.redirectForLogout error: " + (err && err.message || "Unknown error")); - return _promiseFactory.reject(err); - }); -} - -TokenManager.prototype.processTokenCallbackAsync = function (queryString) { - var mgr = this; - return mgr.oidcClient.processResponseAsync(queryString).then(function (token) { - mgr.saveToken(token); - }); -} - -TokenManager.prototype.renewTokenSilentAsync = function () { - var mgr = this; - - if (!mgr._settings.silent_redirect_uri) { - return _promiseFactory.reject(Error("silent_redirect_uri not configured")); - } - - var settings = copy(mgr._settings); - settings.redirect_uri = settings.silent_redirect_uri; - if (!settings.prompt) { - settings.prompt = "none"; - } - - var oidc = new OidcClient(settings); - return oidc.createTokenRequestAsync().then(function (request) { - var frame = new FrameLoader(request.url, { cancelDelay: mgr._settings.silent_renew_timeout }); - return frame.loadAsync().then(function (hash) { - return oidc.processResponseAsync(hash).then(function (token) { - mgr.saveToken(token); - }); - }); - }); -} - -TokenManager.prototype.processTokenCallbackSilent = function (hash) { - if (window.parent && window !== window.parent) { - var hash = hash || window.location.hash; - if (hash) { - window.parent.postMessage(hash, location.protocol + "//" + location.host); - } - } -} - -TokenManager.prototype.openPopupForTokenAsync = function (popupSettings) { - popupSettings = popupSettings || {}; - popupSettings.features = popupSettings.features || "location=no,toolbar=no"; - popupSettings.target = popupSettings.target || "_blank"; - - var callback_prefix = "tokenmgr_callback_"; - - // this is a shared callback - if (!window.openPopupForTokenAsyncCallback) { - window.openPopupForTokenAsyncCallback = function (hash) { - var result = OidcClient.parseOidcResult(hash); - if (result && result.state && window[callback_prefix + result.state]) { - window[callback_prefix + result.state](hash); - } - } - } - - var mgr = this; - var settings = copy(mgr._settings); - settings.redirect_uri = settings.popup_redirect_uri || settings.redirect_uri; - - if (mgr._pendingPopup) { - return _promiseFactory.create(function (resolve, reject) { - reject(Error("Already a pending popup token request.")); - }); - } - - var popup = window.open(settings.redirect_uri, popupSettings.target, popupSettings.features); - if (!popup) { - return _promiseFactory.create(function (resolve, reject) { - reject(Error("Error opening popup.")); - }); - } - - mgr._pendingPopup = true; - - function cleanup(name) { - if (handle) { - window.clearInterval(handle); - } - popup.close(); - delete mgr._pendingPopup; - if (name) { - delete window[name]; - } - } - - var reject_popup; - function checkClosed() { - if (!popup.window) { - cleanup(); - reject_popup(Error("Popup closed")); - } - } - var handle = window.setInterval(checkClosed, 1000); - - return _promiseFactory.create(function (resolve, reject) { - reject_popup = reject; - - var oidc = new OidcClient(settings); - oidc.createTokenRequestAsync().then(function (request) { - - var callback_name = callback_prefix + request.request_state.state; - window[callback_name] = function (hash) { - cleanup(callback_name); - - oidc.processResponseAsync(hash).then(function (token) { - mgr.saveToken(token); - resolve(); - }, function (err) { - reject(err); - }); - }; - - // give the popup 5 seconds to ready itself, otherwise fail - var seconds_to_wait = 5; - var interval = 500; - var total_times = (seconds_to_wait*1000) / interval; - var count = 0; - function redirectPopup() { - if (popup.setUrl) { - popup.setUrl(request.url); - } - else if (count < total_times) { - count++; - window.setTimeout(redirectPopup, interval); - } - else { - cleanup(callback_name); - reject(Error("Timeout error on popup")); - } - } - redirectPopup(); - }, function (err) { - cleanup(); - reject(err); - }); - }); -} - -TokenManager.prototype.processTokenPopup = function (hash) { - hash = hash || window.location.hash; - - window.setUrl = function (url) { - window.location = url; - } - - if (hash) { - window.opener.openPopupForTokenAsyncCallback(hash); - } -} - - - // exports - window.OidcTokenManager = TokenManager; + /* + * Copyright 2014-2016 Dominick Baier, Brock Allen + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // globals + var _promiseFactory = OidcClient._promiseFactory; + var _httpRequest = OidcClient._httpRequest; + + function copy(obj, target) { + target = target || {}; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + target[key] = obj[key]; + } + } + return target; + } + + function Token(other) { + if (other) { + this.profile = other.profile; + this.id_token = other.id_token; + this.access_token = other.access_token; + if (other.access_token) { + this.expires_at = parseInt(other.expires_at); + } + else if (other.id_token) { + this.expires_at = other.profile.exp; + } + else { + throw Error("Either access_token or id_token required."); + } + this.scope = other.scope; + this.session_state = other.session_state; + } + else { + this.expires_at = 0; + } + + Object.defineProperty(this, "scopes", { + get: function () { + return (this.scope || "").split(" "); + } + }); + + Object.defineProperty(this, "expired", { + get: function () { + var now = parseInt(Date.now() / 1000); + return this.expires_at < now; + } + }); + + Object.defineProperty(this, "expires_in", { + get: function () { + var now = parseInt(Date.now() / 1000); + return this.expires_at - now; + } + }); + } + + Token.fromResponse = function (response) { + if (response.access_token) { + var now = parseInt(Date.now() / 1000); + response.expires_at = now + parseInt(response.expires_in); + } + return new Token(response); + } + + Token.fromJSON = function (json) { + if (json) { + try { + var obj = JSON.parse(json); + return new Token(obj); + } + catch (e) { + } + } + return new Token(null); + } + + Token.prototype.toJSON = function () { + return JSON.stringify({ + profile: this.profile, + id_token: this.id_token, + access_token: this.access_token, + expires_at: this.expires_at, + scope: this.scopes.join(" "), + session_state: this.session_state + }); + } + + function FrameLoader(url, config) { + this.url = url; + config = config || {}; + config.cancelDelay = config.cancelDelay || 5000; + this.config = config; + } + + FrameLoader.prototype.loadAsync = function (url) { + var self = this; + url = url || this.url; + + if (!url) { + return _promiseFactory.reject(Error("No url provided")); + } + + return _promiseFactory.create(function (resolve, reject) { + var frame = window.document.createElement("iframe"); + frame.style.display = "none"; + + function cleanup() { + window.removeEventListener("message", message, false); + if (handle) { + window.clearTimeout(handle); + } + handle = null; + window.document.body.removeChild(frame); + } + + function cancel(e) { + cleanup(); + reject(); + } + + function message(e) { + if (handle && e.origin === location.protocol + "//" + location.host && e.source == frame.contentWindow) { + cleanup(); + resolve(e.data); + } + } + + var handle = window.setTimeout(cancel, self.config.cancelDelay); + window.addEventListener("message", message, false); + window.document.body.appendChild(frame); + frame.src = url; + }); + } + + function loadToken(mgr) { + mgr._token = null; + if (mgr._settings.persist) { + var tokenJson = mgr._settings.store.getItem(mgr._settings.persistKey); + if (tokenJson) { + var token = Token.fromJSON(tokenJson); + if (!token.expired) { + mgr._token = token; + } + } + } + } + + function configureTokenExpiring(mgr) { + + function callback() { + handle = null; + mgr._callTokenExpiring(); + } + + var handle = null; + + function cancel() { + if (handle) { + window.clearTimeout(handle); + handle = null; + } + } + + function setup(duration) { + handle = window.setTimeout(callback, duration * 1000); + } + + function configure() { + cancel(); + + if (!mgr.expired) { + var duration = mgr.expires_in; + if (duration > 60) { + setup(duration - 60); + } + else { + callback(); + } + } + } + + configure(); + + mgr.addOnTokenObtained(configure); + mgr.addOnTokenRemoved(cancel); + } + + function configureAutoRenewToken(mgr) { + + if (mgr._settings.silent_redirect_uri && mgr._settings.silent_renew) { + + mgr.addOnTokenExpiring(function () { + mgr.renewTokenSilentAsync().catch(function (e) { + mgr._callSilentTokenRenewFailed(); + console.error(e && e.message || "Unknown error"); + }); + }); + + } + } + + function configureTokenExpired(mgr) { + + function callback() { + handle = null; + + if (mgr._token) { + mgr.saveToken(null); + } + + mgr._callTokenExpired(); + } + + var handle = null; + + function cancel() { + if (handle) { + window.clearTimeout(handle); + handle = null; + } + } + + function setup(duration) { + handle = window.setTimeout(callback, duration * 1000); + } + + function configure() { + cancel(); + if (mgr.expires_in > 0) { + // register 1 second beyond expiration so we don't get into edge conditions for expiration + setup(mgr.expires_in + 1); + } + } + + configure(); + + mgr.addOnTokenObtained(configure); + mgr.addOnTokenRemoved(cancel); + } + + function TokenManager(settings) { + this._settings = settings || {}; + + if (typeof this._settings.persist === 'undefined') { + this._settings.persist = true; + } + this._settings.store = this._settings.store || window.localStorage; + this._settings.persistKey = this._settings.persistKey || "TokenManager.token"; + + this.oidcClient = new OidcClient(this._settings); + + this._callbacks = { + tokenRemovedCallbacks: [], + tokenExpiringCallbacks: [], + tokenExpiredCallbacks: [], + tokenObtainedCallbacks: [], + silentTokenRenewFailedCallbacks: [] + }; + + Object.defineProperty(this, "profile", { + get: function () { + if (this._token) { + return this._token.profile; + } + } + }); + Object.defineProperty(this, "id_token", { + get: function () { + if (this._token) { + return this._token.id_token; + } + } + }); + Object.defineProperty(this, "access_token", { + get: function () { + if (this._token && !this._token.expired) { + return this._token.access_token; + } + } + }); + Object.defineProperty(this, "expired", { + get: function () { + if (this._token) { + return this._token.expired; + } + return true; + } + }); + Object.defineProperty(this, "expires_in", { + get: function () { + if (this._token) { + return this._token.expires_in; + } + return 0; + } + }); + Object.defineProperty(this, "expires_at", { + get: function () { + if (this._token) { + return this._token.expires_at; + } + return 0; + } + }); + Object.defineProperty(this, "scope", { + get: function () { + return this._token && this._token.scope; + } + }); + Object.defineProperty(this, "scopes", { + get: function () { + if (this._token) { + return [].concat(this._token.scopes); + } + return []; + } + }); + Object.defineProperty(this, "session_state", { + get: function () { + if (this._token) { + return this._token.session_state; + } + } + }); + + var mgr = this; + loadToken(mgr); + if (mgr._settings.store instanceof window.localStorage.constructor) { + window.addEventListener("storage", function (e) { + if (e.key === mgr._settings.persistKey) { + loadToken(mgr); + + if (mgr._token) { + mgr._callTokenObtained(); + } + else { + mgr._callTokenRemoved(); + } + } + }); + } + configureTokenExpired(mgr); + configureAutoRenewToken(mgr); + + // delay this so consuming apps can register for callbacks first + window.setTimeout(function () { + configureTokenExpiring(mgr); + }, 0); + } + + /** + * @param {{ create:function(successCallback:function(), errorCallback:function()):Promise, resolve:function(value:*):Promise, reject:function():Promise}} promiseFactory + */ + TokenManager.setPromiseFactory = function (promiseFactory) { + _promiseFactory = promiseFactory; + }; + + /** + * @param {{getJSON:function(url:string, config:{ headers: object. })}} httpRequest + */ + TokenManager.setHttpRequest = function (httpRequest) { + if ((typeof httpRequest !== 'object') || (typeof httpRequest.getJSON !== 'function')) { + throw Error('The provided value is not a valid http request.'); + } + + _httpRequest = httpRequest; + }; + + TokenManager.prototype._callTokenRemoved = function () { + this._callbacks.tokenRemovedCallbacks.forEach(function (cb) { + cb(); + }); + } + + TokenManager.prototype._callTokenExpiring = function () { + this._callbacks.tokenExpiringCallbacks.forEach(function (cb) { + cb(); + }); + } + + TokenManager.prototype._callTokenExpired = function () { + this._callbacks.tokenExpiredCallbacks.forEach(function (cb) { + cb(); + }); + } + + TokenManager.prototype._callTokenObtained = function () { + this._callbacks.tokenObtainedCallbacks.forEach(function (cb) { + cb(); + }); + } + + TokenManager.prototype._callSilentTokenRenewFailed = function () { + this._callbacks.silentTokenRenewFailedCallbacks.forEach(function (cb) { + cb(); + }); + } + + TokenManager.prototype.saveToken = function (token) { + if (token && !(token instanceof Token)) { + token = Token.fromResponse(token); + } + + this._token = token; + + if (this._settings.persist && !this.expired) { + this._settings.store.setItem(this._settings.persistKey, token.toJSON()); + } + else { + this._settings.store.removeItem(this._settings.persistKey); + } + + if (token) { + this._callTokenObtained(); + } + else { + this._callTokenRemoved(); + } + } + + TokenManager.prototype.addOnTokenRemoved = function (cb) { + this._callbacks.tokenRemovedCallbacks.push(cb); + } + + TokenManager.prototype.addOnTokenObtained = function (cb) { + this._callbacks.tokenObtainedCallbacks.push(cb); + } + + TokenManager.prototype.addOnTokenExpiring = function (cb) { + this._callbacks.tokenExpiringCallbacks.push(cb); + } + + TokenManager.prototype.addOnTokenExpired = function (cb) { + this._callbacks.tokenExpiredCallbacks.push(cb); + } + + TokenManager.prototype.addOnSilentTokenRenewFailed = function (cb) { + this._callbacks.silentTokenRenewFailedCallbacks.push(cb); + } + + TokenManager.prototype.removeToken = function () { + this.saveToken(null); + } + + TokenManager.prototype.redirectForToken = function () { + var oidc = this.oidcClient; + return oidc.createTokenRequestAsync().then(function (request) { + window.location = request.url; + }, function (err) { + console.error("TokenManager.redirectForToken error: " + (err && err.message || "Unknown error")); + return _promiseFactory.reject(err); + }); + } + + TokenManager.prototype.redirectForLogout = function () { + var mgr = this; + return mgr.oidcClient.createLogoutRequestAsync(mgr.id_token).then(function (url) { + mgr.removeToken(); + window.location = url; + }, function (err) { + console.error("TokenManager.redirectForLogout error: " + (err && err.message || "Unknown error")); + return _promiseFactory.reject(err); + }); + } + + TokenManager.prototype.processTokenCallbackAsync = function (queryString) { + var mgr = this; + return mgr.oidcClient.processResponseAsync(queryString).then(function (token) { + mgr.saveToken(token); + }); + } + + TokenManager.prototype.renewTokenSilentAsync = function () { + var mgr = this; + + if (!mgr._settings.silent_redirect_uri) { + return _promiseFactory.reject(Error("silent_redirect_uri not configured")); + } + + var settings = copy(mgr._settings); + settings.redirect_uri = settings.silent_redirect_uri; + if (!settings.prompt) { + settings.prompt = "none"; + } + + var oidc = new OidcClient(settings); + return oidc.createTokenRequestAsync().then(function (request) { + var frame = new FrameLoader(request.url, { cancelDelay: mgr._settings.silent_renew_timeout }); + return frame.loadAsync().then(function (hash) { + return oidc.processResponseAsync(hash).then(function (token) { + mgr.saveToken(token); + }); + }); + }); + } + + TokenManager.prototype.processTokenCallbackSilent = function (hash) { + if (window.parent && window !== window.parent) { + var hash = hash || window.location.hash; + if (hash) { + window.parent.postMessage(hash, location.protocol + "//" + location.host); + } + } + } + + TokenManager.prototype.openPopupForTokenAsync = function (popupSettings) { + popupSettings = popupSettings || {}; + popupSettings.features = popupSettings.features || "location=no,toolbar=no"; + popupSettings.target = popupSettings.target || "_blank"; + + var callback_prefix = "tokenmgr_callback_"; + + // this is a shared callback + if (!window.openPopupForTokenAsyncCallback) { + window.openPopupForTokenAsyncCallback = function (hash) { + var result = OidcClient.parseOidcResult(hash); + if (result && result.state && window[callback_prefix + result.state]) { + window[callback_prefix + result.state](hash); + } + } + } + + var mgr = this; + var settings = copy(mgr._settings); + settings.redirect_uri = settings.popup_redirect_uri || settings.redirect_uri; + + if (mgr._pendingPopup) { + return _promiseFactory.create(function (resolve, reject) { + reject(Error("Already a pending popup token request.")); + }); + } + + var popup = window.open(settings.redirect_uri, popupSettings.target, popupSettings.features); + if (!popup) { + return _promiseFactory.create(function (resolve, reject) { + reject(Error("Error opening popup.")); + }); + } + + mgr._pendingPopup = true; + + function cleanup(name) { + if (handle) { + window.clearInterval(handle); + } + popup.close(); + delete mgr._pendingPopup; + if (name) { + delete window[name]; + } + } + + var reject_popup; + function checkClosed() { + if (!popup.window) { + cleanup(); + reject_popup(Error("Popup closed")); + } + } + var handle = window.setInterval(checkClosed, 1000); + + return _promiseFactory.create(function (resolve, reject) { + reject_popup = reject; + + var oidc = new OidcClient(settings); + oidc.createTokenRequestAsync().then(function (request) { + + var callback_name = callback_prefix + request.request_state.state; + window[callback_name] = function (hash) { + cleanup(callback_name); + + oidc.processResponseAsync(hash).then(function (token) { + mgr.saveToken(token); + resolve(); + }, function (err) { + reject(err); + }); + }; + + // give the popup 5 seconds to ready itself, otherwise fail + var seconds_to_wait = 5; + var interval = 500; + var total_times = (seconds_to_wait * 1000) / interval; + var count = 0; + function redirectPopup() { + if (popup.setUrl) { + popup.setUrl(request.url); + } + else if (count < total_times) { + count++; + window.setTimeout(redirectPopup, interval); + } + else { + cleanup(callback_name); + reject(Error("Timeout error on popup")); + } + } + redirectPopup(); + }, function (err) { + cleanup(); + reject(err); + }); + }); + } + + TokenManager.prototype.processTokenPopup = function (hash) { + hash = hash || window.location.hash; + + window.setUrl = function (url) { + window.location = url; + } + + if (hash) { + window.opener.openPopupForTokenAsyncCallback(hash); + } + } + + + // exports + window.OidcTokenManager = TokenManager; })(); diff --git a/src/Services/Basket/Basket.API/Auth/Client/popup.html b/src/Services/Basket/Basket.API/Auth/Client/popup.html index 364f8d7dd..21609c4c0 100644 --- a/src/Services/Basket/Basket.API/Auth/Client/popup.html +++ b/src/Services/Basket/Basket.API/Auth/Client/popup.html @@ -1,13 +1,13 @@  - - + + - - + + \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs b/src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs index 90aa89322..6607bf29e 100644 --- a/src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs +++ b/src/Services/Basket/Basket.API/Auth/Server/AuthorizationHeaderParameterOperationFilter.cs @@ -6,28 +6,30 @@ using System.Linq; namespace Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server { - public class AuthorizationHeaderParameterOperationFilter : IOperationFilter - { - public void Apply(Operation operation, OperationFilterContext context) - { - var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors; - var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter); - var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter); + public class AuthorizationHeaderParameterOperationFilter : IOperationFilter + { + public void Apply(Operation operation, OperationFilterContext context) + { + var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors; + var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter); + var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter); - if (isAuthorized && !allowAnonymous) - { - if (operation.Parameters == null) - operation.Parameters = new List(); + if (isAuthorized && !allowAnonymous) + { + if (operation.Parameters == null) + { + operation.Parameters = new List(); + } - operation.Parameters.Add(new NonBodyParameter - { - Name = "Authorization", - In = "header", - Description = "access token", - Required = true, - Type = "string" - }); - } - } - } + operation.Parameters.Add(new NonBodyParameter + { + Name = "Authorization", + In = "header", + Description = "access token", + Required = true, + Type = "string" + }); + } + } + } } diff --git a/src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs b/src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs index 397f66db4..b4e612d3e 100644 --- a/src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs +++ b/src/Services/Basket/Basket.API/Auth/Server/IdentitySecurityScheme.cs @@ -3,18 +3,18 @@ using System.Collections.Generic; namespace Microsoft.eShopOnContainers.Services.Basket.API.Auth.Server { - public class IdentitySecurityScheme:SecurityScheme - { - public IdentitySecurityScheme() - { - Type = "IdentitySecurityScheme"; - Description = "Security definition that provides to the user of Swagger a mechanism to obtain a token from the identity service that secures the api"; - Extensions.Add("authorizationUrl", "http://localhost:5103/Auth/Client/popup.html"); - Extensions.Add("flow", "implicit"); - Extensions.Add("scopes", new List - { - "basket" - }); - } - } + public class IdentitySecurityScheme : SecurityScheme + { + public IdentitySecurityScheme() + { + Type = "IdentitySecurityScheme"; + Description = "Security definition that provides to the user of Swagger a mechanism to obtain a token from the identity service that secures the api"; + Extensions.Add("authorizationUrl", "http://localhost:5103/Auth/Client/popup.html"); + Extensions.Add("flow", "implicit"); + Extensions.Add("scopes", new List + { + "basket" + }); + } + } } diff --git a/src/Services/Basket/Basket.API/BasketSettings.cs b/src/Services/Basket/Basket.API/BasketSettings.cs index 9d143545a..931e20214 100644 --- a/src/Services/Basket/Basket.API/BasketSettings.cs +++ b/src/Services/Basket/Basket.API/BasketSettings.cs @@ -1,9 +1,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API { - public class BasketSettings - { - public string ConnectionString { get; set; } + public class BasketSettings + { + public string ConnectionString { get; set; } - public string EventBusConnection { get; set; } - } + public string EventBusConnection { get; set; } + } } diff --git a/src/Services/Basket/Basket.API/Controllers/BasketController.cs b/src/Services/Basket/Basket.API/Controllers/BasketController.cs index c7fdac57d..bbbe94903 100644 --- a/src/Services/Basket/Basket.API/Controllers/BasketController.cs +++ b/src/Services/Basket/Basket.API/Controllers/BasketController.cs @@ -11,86 +11,86 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers { - [Route("api/v1/[controller]")] - [Authorize] - public class BasketController : Controller - { - private readonly IBasketRepository _repository; - private readonly IIdentityService _identitySvc; - private readonly IEventBus _eventBus; - - public BasketController(IBasketRepository repository, - IIdentityService identityService, - IEventBus eventBus) - { - _repository = repository; - _identitySvc = identityService; - _eventBus = eventBus; - } - - // GET /id - [HttpGet("{id}")] - [ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)] - public async Task Get(string id) - { - var basket = await _repository.GetBasketAsync(id); - if (basket == null) - { - return Ok(new CustomerBasket(id) { }); - } - - return Ok(basket); - } - - // POST /value - [HttpPost] - [ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)] - public async Task Post([FromBody]CustomerBasket value) - { - var basket = await _repository.UpdateBasketAsync(value); - - return Ok(basket); - } - - [Route("checkout")] - [HttpPost] - [ProducesResponseType((int)HttpStatusCode.Accepted)] - [ProducesResponseType((int)HttpStatusCode.BadRequest)] - public async Task Checkout([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId) - { - var userId = _identitySvc.GetUserIdentity(); - - - basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ? - guid : basketCheckout.RequestId; - - var basket = await _repository.GetBasketAsync(userId); - - if (basket == null) - { - return BadRequest(); - } - - var userName = User.FindFirst(x => x.Type == "unique_name").Value; - - var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, userName, basketCheckout.City, basketCheckout.Street, - basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName, - basketCheckout.CardExpiration, basketCheckout.CardSecurityNumber, basketCheckout.CardTypeId, basketCheckout.Buyer, basketCheckout.RequestId, basket); - - // Once basket is checkout, sends an integration event to - // ordering.api to convert basket to order and proceeds with - // order creation process - _eventBus.Publish(eventMessage); - - return Accepted(); - } - - // DELETE api/values/5 - [HttpDelete("{id}")] - public void Delete(string id) - { - _repository.DeleteBasketAsync(id); - } - - } + [Route("api/v1/[controller]")] + [Authorize] + public class BasketController : Controller + { + private readonly IBasketRepository _repository; + private readonly IIdentityService _identitySvc; + private readonly IEventBus _eventBus; + + public BasketController(IBasketRepository repository, + IIdentityService identityService, + IEventBus eventBus) + { + _repository = repository; + _identitySvc = identityService; + _eventBus = eventBus; + } + + // GET /id + [HttpGet("{id}")] + [ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)] + public async Task Get(string id) + { + var basket = await _repository.GetBasketAsync(id); + if (basket == null) + { + return Ok(new CustomerBasket(id) { }); + } + + return Ok(basket); + } + + // POST /value + [HttpPost] + [ProducesResponseType(typeof(CustomerBasket), (int)HttpStatusCode.OK)] + public async Task Post([FromBody]CustomerBasket value) + { + var basket = await _repository.UpdateBasketAsync(value); + + return Ok(basket); + } + + [Route("checkout")] + [HttpPost] + [ProducesResponseType((int)HttpStatusCode.Accepted)] + [ProducesResponseType((int)HttpStatusCode.BadRequest)] + public async Task Checkout([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId) + { + var userId = _identitySvc.GetUserIdentity(); + + + basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ? + guid : basketCheckout.RequestId; + + var basket = await _repository.GetBasketAsync(userId); + + if (basket == null) + { + return BadRequest(); + } + + var userName = User.FindFirst(x => x.Type == "unique_name").Value; + + var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, userName, basketCheckout.City, basketCheckout.Street, + basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName, + basketCheckout.CardExpiration, basketCheckout.CardSecurityNumber, basketCheckout.CardTypeId, basketCheckout.Buyer, basketCheckout.RequestId, basket); + + // Once basket is checkout, sends an integration event to + // ordering.api to convert basket to order and proceeds with + // order creation process + _eventBus.Publish(eventMessage); + + return Accepted(); + } + + // DELETE api/values/5 + [HttpDelete("{id}")] + public void Delete(string id) + { + _repository.DeleteBasketAsync(id); + } + + } } diff --git a/src/Services/Basket/Basket.API/Controllers/HomeController.cs b/src/Services/Basket/Basket.API/Controllers/HomeController.cs index d0c37a205..b87863003 100644 --- a/src/Services/Basket/Basket.API/Controllers/HomeController.cs +++ b/src/Services/Basket/Basket.API/Controllers/HomeController.cs @@ -2,12 +2,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers { - public class HomeController : Controller - { - // GET: // - public IActionResult Index() - { - return new RedirectResult("~/swagger"); - } - } + public class HomeController : Controller + { + // GET: // + public IActionResult Index() + => new RedirectResult("~/swagger"); + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/ActionResults/InternalServerErrorObjectResult.cs b/src/Services/Basket/Basket.API/Infrastructure/ActionResults/InternalServerErrorObjectResult.cs index a0b988156..8f13f9eec 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/ActionResults/InternalServerErrorObjectResult.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/ActionResults/InternalServerErrorObjectResult.cs @@ -3,12 +3,10 @@ using Microsoft.AspNetCore.Mvc; namespace Basket.API.Infrastructure.ActionResults { - public class InternalServerErrorObjectResult : ObjectResult - { - public InternalServerErrorObjectResult(object error) - : base(error) - { - StatusCode = StatusCodes.Status500InternalServerError; - } - } + public class InternalServerErrorObjectResult : ObjectResult + { + public InternalServerErrorObjectResult(object error) + : base(error) + => StatusCode = StatusCodes.Status500InternalServerError; + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Exceptions/BasketDomainException.cs b/src/Services/Basket/Basket.API/Infrastructure/Exceptions/BasketDomainException.cs index e0f2df6fa..7fcb27dbb 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Exceptions/BasketDomainException.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Exceptions/BasketDomainException.cs @@ -2,20 +2,20 @@ namespace Basket.API.Infrastructure.Exceptions { - /// - /// Exception type for app exceptions - /// - public class BasketDomainException : Exception - { - public BasketDomainException() - { } + /// + /// Exception type for app exceptions + /// + public class BasketDomainException : Exception + { + public BasketDomainException() + { } - public BasketDomainException(string message) - : base(message) - { } + public BasketDomainException(string message) + : base(message) + { } - public BasketDomainException(string message, Exception innerException) - : base(message, innerException) - { } - } + public BasketDomainException(string message, Exception innerException) + : base(message, innerException) + { } + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs b/src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs index a09f32f76..776c2f890 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs @@ -3,18 +3,16 @@ using System; namespace Basket.API.Infrastructure.Middlewares { - public static class FailingMiddlewareAppBuilderExtensions - { - public static IApplicationBuilder UseFailingMiddleware(this IApplicationBuilder builder) - { - return UseFailingMiddleware(builder, null); - } - public static IApplicationBuilder UseFailingMiddleware(this IApplicationBuilder builder, Action action) - { - var options = new FailingOptions(); - action?.Invoke(options); - builder.UseMiddleware(options); - return builder; - } - } + public static class FailingMiddlewareAppBuilderExtensions + { + public static IApplicationBuilder UseFailingMiddleware(this IApplicationBuilder builder) + => UseFailingMiddleware(builder, null); + public static IApplicationBuilder UseFailingMiddleware(this IApplicationBuilder builder, Action action) + { + var options = new FailingOptions(); + action?.Invoke(options); + builder.UseMiddleware(options); + return builder; + } + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs index 7caa9740d..e263ab713 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Filters/AuthorizeCheckOperationFilter.cs @@ -6,25 +6,25 @@ using System.Linq; namespace Basket.API.Infrastructure.Filters { - public class AuthorizeCheckOperationFilter : IOperationFilter - { - public void Apply(Operation operation, OperationFilterContext context) - { - // Check for authorize attribute - var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType().Any() || - context.ApiDescription.ActionAttributes().OfType().Any(); + public class AuthorizeCheckOperationFilter : IOperationFilter + { + public void Apply(Operation operation, OperationFilterContext context) + { + // Check for authorize attribute + var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType().Any() || + context.ApiDescription.ActionAttributes().OfType().Any(); - if (hasAuthorize) - { - operation.Responses.Add("401", new Response { Description = "Unauthorized" }); - operation.Responses.Add("403", new Response { Description = "Forbidden" }); + if (hasAuthorize) + { + operation.Responses.Add("401", new Response { Description = "Unauthorized" }); + operation.Responses.Add("403", new Response { Description = "Forbidden" }); - operation.Security = new List>>(); - operation.Security.Add(new Dictionary> - { - { "oauth2", new [] { "basketapi" } } - }); - } - } - } + operation.Security = new List>>(); + operation.Security.Add(new Dictionary> + { + { "oauth2", new [] { "basketapi" } } + }); + } + } + } } \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs index dab725915..0d88a8357 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Filters/HttpGlobalExceptionFilter.cs @@ -8,49 +8,49 @@ using System.Net; namespace Basket.API.Infrastructure.Filters { - public partial class HttpGlobalExceptionFilter : IExceptionFilter - { - private readonly IHostingEnvironment env; - private readonly ILogger logger; + public partial class HttpGlobalExceptionFilter : IExceptionFilter + { + private readonly IHostingEnvironment env; + private readonly ILogger logger; - public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger logger) - { - this.env = env; - this.logger = logger; - } + public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger logger) + { + this.env = env; + this.logger = logger; + } - public void OnException(ExceptionContext context) - { - logger.LogError(new EventId(context.Exception.HResult), - context.Exception, - context.Exception.Message); + public void OnException(ExceptionContext context) + { + logger.LogError(new EventId(context.Exception.HResult), + context.Exception, + context.Exception.Message); - if (context.Exception.GetType() == typeof(BasketDomainException)) - { - var json = new JsonErrorResponse - { - Messages = new[] { context.Exception.Message } - }; + if (context.Exception.GetType() == typeof(BasketDomainException)) + { + var json = new JsonErrorResponse + { + Messages = new[] { context.Exception.Message } + }; - context.Result = new BadRequestObjectResult(json); - context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; - } - else - { - var json = new JsonErrorResponse - { - Messages = new[] { "An error occurred. Try it again." } - }; + context.Result = new BadRequestObjectResult(json); + context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; + } + else + { + var json = new JsonErrorResponse + { + Messages = new[] { "An error occurred. Try it again." } + }; - if (env.IsDevelopment()) - { - json.DeveloperMessage = context.Exception; - } + if (env.IsDevelopment()) + { + json.DeveloperMessage = context.Exception; + } - context.Result = new InternalServerErrorObjectResult(json); - context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; - } - context.ExceptionHandled = true; - } - } + context.Result = new InternalServerErrorObjectResult(json); + context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + } + context.ExceptionHandled = true; + } + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Filters/JsonErrorResponse.cs b/src/Services/Basket/Basket.API/Infrastructure/Filters/JsonErrorResponse.cs index bcadc7358..d2a665581 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Filters/JsonErrorResponse.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Filters/JsonErrorResponse.cs @@ -1,9 +1,9 @@ namespace Basket.API.Infrastructure.Filters { - public class JsonErrorResponse - { - public string[] Messages { get; set; } + public class JsonErrorResponse + { + public string[] Messages { get; set; } - public object DeveloperMessage { get; set; } - } + public object DeveloperMessage { get; set; } + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Filters/ValidateModelStateFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Filters/ValidateModelStateFilter.cs index 3e4c3e072..c1e21eb79 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Filters/ValidateModelStateFilter.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Filters/ValidateModelStateFilter.cs @@ -4,27 +4,27 @@ using System.Linq; namespace Basket.API.Infrastructure.Filters { - public class ValidateModelStateFilter : ActionFilterAttribute - { - public override void OnActionExecuting(ActionExecutingContext context) - { - if (context.ModelState.IsValid) - { - return; - } + public class ValidateModelStateFilter : ActionFilterAttribute + { + public override void OnActionExecuting(ActionExecutingContext context) + { + if (context.ModelState.IsValid) + { + return; + } - var validationErrors = context.ModelState - .Keys - .SelectMany(k => context.ModelState[k].Errors) - .Select(e => e.ErrorMessage) - .ToArray(); + var validationErrors = context.ModelState + .Keys + .SelectMany(k => context.ModelState[k].Errors) + .Select(e => e.ErrorMessage) + .ToArray(); - var json = new JsonErrorResponse - { - Messages = validationErrors - }; + var json = new JsonErrorResponse + { + Messages = validationErrors + }; - context.Result = new BadRequestObjectResult(json); - } - } + context.Result = new BadRequestObjectResult(json); + } + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/ByPassAuthMiddleware.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/ByPassAuthMiddleware.cs index dfe690f6f..69362fdb2 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/ByPassAuthMiddleware.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/ByPassAuthMiddleware.cs @@ -1,79 +1,78 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using System; -using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; namespace Basket.API.Infrastructure.Middlewares { - class ByPassAuthMiddleware - { - private readonly RequestDelegate _next; - private string _currentUserId; - public ByPassAuthMiddleware(RequestDelegate next) - { - _next = next; - _currentUserId = null; - } + class ByPassAuthMiddleware + { + private readonly RequestDelegate _next; + private string _currentUserId; + public ByPassAuthMiddleware(RequestDelegate next) + { + _next = next; + _currentUserId = null; + } - public async Task Invoke(HttpContext context) - { - var path = context.Request.Path; - if (path == "/noauth") - { - var userid = context.Request.Query["userid"]; - if (!string.IsNullOrEmpty(userid)) - { - _currentUserId = userid; - } - context.Response.StatusCode = 200; - context.Response.ContentType = "text/string"; - await context.Response.WriteAsync($"User set to {_currentUserId}"); - } + public async Task Invoke(HttpContext context) + { + var path = context.Request.Path; + if (path == "/noauth") + { + var userid = context.Request.Query["userid"]; + if (!string.IsNullOrEmpty(userid)) + { + _currentUserId = userid; + } + context.Response.StatusCode = 200; + context.Response.ContentType = "text/string"; + await context.Response.WriteAsync($"User set to {_currentUserId}"); + } - else if (path == "/noauth/reset") - { - _currentUserId = null; - context.Response.StatusCode = 200; - context.Response.ContentType = "text/string"; - await context.Response.WriteAsync($"User set to none. Token required for protected endpoints."); - } - else - { - var currentUserId = _currentUserId; + else if (path == "/noauth/reset") + { + _currentUserId = null; + context.Response.StatusCode = 200; + context.Response.ContentType = "text/string"; + await context.Response.WriteAsync($"User set to none. Token required for protected endpoints."); + } + else + { + var currentUserId = _currentUserId; - var authHeader = context.Request.Headers["Authorization"]; - if (authHeader != StringValues.Empty) - { - var header = authHeader.FirstOrDefault(); - if (!string.IsNullOrEmpty(header) && header.StartsWith("Email ") && header.Length > "Email ".Length) - { - currentUserId = header.Substring("Email ".Length); - } - } + var authHeader = context.Request.Headers["Authorization"]; + if (authHeader != StringValues.Empty) + { + var header = authHeader.FirstOrDefault(); + if (!string.IsNullOrEmpty(header) && header.StartsWith("Email ") && header.Length > "Email ".Length) + { + currentUserId = header.Substring("Email ".Length); + } + } - if (!string.IsNullOrEmpty(currentUserId)) - { - var user = new ClaimsIdentity(new[] { - new Claim("emails", currentUserId), - new Claim("name", "Test user"), - new Claim("nonce", Guid.NewGuid().ToString()), - new Claim("ttp://schemas.microsoft.com/identity/claims/identityprovider", "ByPassAuthMiddleware"), - new Claim("nonce", Guid.NewGuid().ToString()), - new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname","User"), - new Claim("sub", "1234"), - new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname","Microsoft")} - , "ByPassAuth"); + if (!string.IsNullOrEmpty(currentUserId)) + { + var user = new ClaimsIdentity(new[] { + new Claim("emails", currentUserId), + new Claim("name", "Test user"), + new Claim("nonce", Guid.NewGuid().ToString()), + new Claim("ttp://schemas.microsoft.com/identity/claims/identityprovider", "ByPassAuthMiddleware"), + new Claim("nonce", Guid.NewGuid().ToString()), + new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname","User"), + new Claim("sub", "1234"), + new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname","Microsoft")} + , "ByPassAuth"); - context.User = new ClaimsPrincipal(user); - } + context.User = new ClaimsPrincipal(user); + } - await _next.Invoke(context); - } - } - } + await _next.Invoke(context); + } + } + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs index 875749b5f..db7494c7d 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs @@ -5,78 +5,78 @@ using System.Threading.Tasks; namespace Basket.API.Infrastructure.Middlewares { - public class FailingMiddleware - { - private readonly RequestDelegate _next; - private bool _mustFail; - private readonly FailingOptions _options; - public FailingMiddleware(RequestDelegate next, FailingOptions options) - { - _next = next; - _options = options; - _mustFail = false; - } - public async Task Invoke(HttpContext context) - { - var path = context.Request.Path; - if (path.Equals(_options.ConfigPath, StringComparison.OrdinalIgnoreCase)) - { - await ProcessConfigRequest(context); - return; - } + public class FailingMiddleware + { + private readonly RequestDelegate _next; + private bool _mustFail; + private readonly FailingOptions _options; + public FailingMiddleware(RequestDelegate next, FailingOptions options) + { + _next = next; + _options = options; + _mustFail = false; + } + public async Task Invoke(HttpContext context) + { + var path = context.Request.Path; + if (path.Equals(_options.ConfigPath, StringComparison.OrdinalIgnoreCase)) + { + await ProcessConfigRequest(context); + return; + } - if (MustFail(context)) - { - context.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; - context.Response.ContentType = "text/plain"; - await context.Response.WriteAsync("Failed due to FailingMiddleware enabled."); - } - else - { - await _next.Invoke(context); - } - } + if (MustFail(context)) + { + context.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync("Failed due to FailingMiddleware enabled."); + } + else + { + await _next.Invoke(context); + } + } - private async Task ProcessConfigRequest(HttpContext context) - { - var enable = context.Request.Query.Keys.Any(k => k == "enable"); - var disable = context.Request.Query.Keys.Any(k => k == "disable"); + private async Task ProcessConfigRequest(HttpContext context) + { + var enable = context.Request.Query.Keys.Any(k => k == "enable"); + var disable = context.Request.Query.Keys.Any(k => k == "disable"); - if (enable && disable) - { - throw new ArgumentException("Must use enable or disable querystring values, but not both"); - } + if (enable && disable) + { + throw new ArgumentException("Must use enable or disable querystring values, but not both"); + } - if (disable) - { - _mustFail = false; - await SendOkResponse(context, "FailingMiddleware disabled. Further requests will be processed."); - return; - } - if (enable) - { - _mustFail = true; - await SendOkResponse(context, "FailingMiddleware enabled. Further requests will return HTTP 500"); - return; - } + if (disable) + { + _mustFail = false; + await SendOkResponse(context, "FailingMiddleware disabled. Further requests will be processed."); + return; + } + if (enable) + { + _mustFail = true; + await SendOkResponse(context, "FailingMiddleware enabled. Further requests will return HTTP 500"); + return; + } - // If reach here, that means that no valid parameter has been passed. Just output status - await SendOkResponse(context, string.Format("FailingMiddleware is {0}", _mustFail ? "enabled" : "disabled")); - return; - } + // If reach here, that means that no valid parameter has been passed. Just output status + await SendOkResponse(context, string.Format("FailingMiddleware is {0}", _mustFail ? "enabled" : "disabled")); + return; + } - private async Task SendOkResponse(HttpContext context, string message) - { - context.Response.StatusCode = (int)System.Net.HttpStatusCode.OK; - context.Response.ContentType = "text/plain"; - await context.Response.WriteAsync(message); - } + private async Task SendOkResponse(HttpContext context, string message) + { + context.Response.StatusCode = (int)System.Net.HttpStatusCode.OK; + context.Response.ContentType = "text/plain"; + await context.Response.WriteAsync(message); + } - private bool MustFail(HttpContext context) - { - return _mustFail && - (_options.EndpointPaths.Any(x => x == context.Request.Path.Value) - || _options.EndpointPaths.Count == 0); - } - } + private bool MustFail(HttpContext context) + { + return _mustFail && + (_options.EndpointPaths.Any(x => x == context.Request.Path.Value) + || _options.EndpointPaths.Count == 0); + } + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs index 45989832c..39398c368 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs @@ -2,9 +2,9 @@ namespace Basket.API.Infrastructure.Middlewares { - public class FailingOptions - { - public string ConfigPath = "/Failing"; - public List EndpointPaths { get; set; } = new List(); - } + public class FailingOptions + { + public string ConfigPath = "/Failing"; + public List EndpointPaths { get; set; } = new List(); + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingStartupFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingStartupFilter.cs index 7d3b2ce18..7c28ae648 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingStartupFilter.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingStartupFilter.cs @@ -4,21 +4,21 @@ using System; namespace Basket.API.Infrastructure.Middlewares { - public class FailingStartupFilter : IStartupFilter - { - private readonly Action _options; - public FailingStartupFilter(Action optionsAction) - { - _options = optionsAction; - } + public class FailingStartupFilter : IStartupFilter + { + private readonly Action _options; + public FailingStartupFilter(Action optionsAction) + { + _options = optionsAction; + } - public Action Configure(Action next) - { - return app => - { - app.UseFailingMiddleware(_options); - next(app); - }; - } - } + public Action Configure(Action next) + { + return app => + { + app.UseFailingMiddleware(_options); + next(app); + }; + } + } } diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs index 99be1b182..bbd279e02 100644 --- a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs @@ -4,15 +4,15 @@ using System; namespace Basket.API.Infrastructure.Middlewares { - public static class WebHostBuildertExtensions - { - public static IWebHostBuilder UseFailing(this IWebHostBuilder builder, Action options) - { - builder.ConfigureServices(services => - { - services.AddSingleton(new FailingStartupFilter(options)); - }); - return builder; - } - } + public static class WebHostBuildertExtensions + { + public static IWebHostBuilder UseFailing(this IWebHostBuilder builder, Action options) + { + builder.ConfigureServices(services => + { + services.AddSingleton(new FailingStartupFilter(options)); + }); + return builder; + } + } } diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs index 19ae1b594..3faa9f2fb 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/OrderStartedIntegrationEventHandler.cs @@ -6,20 +6,20 @@ using System.Threading.Tasks; namespace Basket.API.IntegrationEvents.EventHandling { - public class OrderStartedIntegrationEventHandler : IIntegrationEventHandler - { - private readonly IBasketRepository _repository; + public class OrderStartedIntegrationEventHandler : IIntegrationEventHandler + { + private readonly IBasketRepository _repository; - public OrderStartedIntegrationEventHandler(IBasketRepository repository) - { - _repository = repository ?? throw new ArgumentNullException(nameof(repository)); - } + public OrderStartedIntegrationEventHandler(IBasketRepository repository) + { + _repository = repository ?? throw new ArgumentNullException(nameof(repository)); + } - public async Task Handle(OrderStartedIntegrationEvent @event) - { - await _repository.DeleteBasketAsync(@event.UserId.ToString()); - } - } + public async Task Handle(OrderStartedIntegrationEvent @event) + { + await _repository.DeleteBasketAsync(@event.UserId.ToString()); + } + } } diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs index 546483b40..ed6f93811 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/EventHandling/ProductPriceChangedIntegrationEventHandler.cs @@ -7,46 +7,46 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.EventHandling { - public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler - { - private readonly IBasketRepository _repository; - - public ProductPriceChangedIntegrationEventHandler(IBasketRepository repository) - { - _repository = repository ?? throw new ArgumentNullException(nameof(repository)); - } - - public async Task Handle(ProductPriceChangedIntegrationEvent @event) - { - var userIds = _repository.GetUsers(); - - foreach (var id in userIds) - { - var basket = await _repository.GetBasketAsync(id); - - await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, basket); - } - } - - private async Task UpdatePriceInBasketItems(int productId, decimal newPrice, decimal oldPrice, CustomerBasket basket) - { - string match = productId.ToString(); - var itemsToUpdate = basket?.Items?.Where(x => x.ProductId == match).ToList(); - - if (itemsToUpdate != null) - { - foreach (var item in itemsToUpdate) - { - if(item.UnitPrice == oldPrice) - { - var originalPrice = item.UnitPrice; - item.UnitPrice = newPrice; - item.OldUnitPrice = originalPrice; - } - } - await _repository.UpdateBasketAsync(basket); - } - } - } + public class ProductPriceChangedIntegrationEventHandler : IIntegrationEventHandler + { + private readonly IBasketRepository _repository; + + public ProductPriceChangedIntegrationEventHandler(IBasketRepository repository) + { + _repository = repository ?? throw new ArgumentNullException(nameof(repository)); + } + + public async Task Handle(ProductPriceChangedIntegrationEvent @event) + { + var userIds = _repository.GetUsers(); + + foreach (var id in userIds) + { + var basket = await _repository.GetBasketAsync(id); + + await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, basket); + } + } + + private async Task UpdatePriceInBasketItems(int productId, decimal newPrice, decimal oldPrice, CustomerBasket basket) + { + string match = productId.ToString(); + var itemsToUpdate = basket?.Items?.Where(x => x.ProductId == match).ToList(); + + if (itemsToUpdate != null) + { + foreach (var item in itemsToUpdate) + { + if (item.UnitPrice == oldPrice) + { + var originalPrice = item.UnitPrice; + item.UnitPrice = newPrice; + item.OldUnitPrice = originalPrice; + } + } + await _repository.UpdateBasketAsync(basket); + } + } + } } diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/Events/OrderStartedIntegrationEvent.cs b/src/Services/Basket/Basket.API/IntegrationEvents/Events/OrderStartedIntegrationEvent.cs index b78d10c05..ae9689919 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/Events/OrderStartedIntegrationEvent.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/Events/OrderStartedIntegrationEvent.cs @@ -2,14 +2,14 @@ namespace Basket.API.IntegrationEvents.Events { - // Integration Events notes: - // An Event is “something that has happened in the past”, therefore its name has to be - // An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems. - public class OrderStartedIntegrationEvent : IntegrationEvent - { - public string UserId { get; set; } + // Integration Events notes: + // An Event is “something that has happened in the past”, therefore its name has to be + // An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems. + public class OrderStartedIntegrationEvent : IntegrationEvent + { + public string UserId { get; set; } - public OrderStartedIntegrationEvent(string userId) - => UserId = userId; - } + public OrderStartedIntegrationEvent(string userId) + => UserId = userId; + } } diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs b/src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs index 6f51010be..dd3038518 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/Events/ProductPriceChangedIntegrationEvent.cs @@ -2,22 +2,22 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Events { - // Integration Events notes: - // An Event is “something that has happened in the past”, therefore its name has to be - // An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems. - public class ProductPriceChangedIntegrationEvent : IntegrationEvent - { - public int ProductId { get; private set; } + // Integration Events notes: + // An Event is “something that has happened in the past”, therefore its name has to be + // An Integration Event is an event that can cause side effects to other microsrvices, Bounded-Contexts or external systems. + public class ProductPriceChangedIntegrationEvent : IntegrationEvent + { + public int ProductId { get; private set; } - public decimal NewPrice { get; private set; } + public decimal NewPrice { get; private set; } - public decimal OldPrice { get; private set; } + public decimal OldPrice { get; private set; } - public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice, decimal oldPrice) - { - ProductId = productId; - NewPrice = newPrice; - OldPrice = oldPrice; - } - } + public ProductPriceChangedIntegrationEvent(int productId, decimal newPrice, decimal oldPrice) + { + ProductId = productId; + NewPrice = newPrice; + OldPrice = oldPrice; + } + } } diff --git a/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs b/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs index 18d522cf6..0e1b935b6 100644 --- a/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs +++ b/src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs @@ -4,61 +4,61 @@ using System; namespace Basket.API.IntegrationEvents.Events { - public class UserCheckoutAcceptedIntegrationEvent : IntegrationEvent - { - public string UserId { get; } + public class UserCheckoutAcceptedIntegrationEvent : IntegrationEvent + { + public string UserId { get; } - public string UserName { get; } + public string UserName { get; } - public int OrderNumber { get; set; } + public int OrderNumber { get; set; } - public string City { get; set; } + public string City { get; set; } - public string Street { get; set; } + public string Street { get; set; } - public string State { get; set; } + public string State { get; set; } - public string Country { get; set; } + public string Country { get; set; } - public string ZipCode { get; set; } + public string ZipCode { get; set; } - public string CardNumber { get; set; } + public string CardNumber { get; set; } - public string CardHolderName { get; set; } + public string CardHolderName { get; set; } - public DateTime CardExpiration { get; set; } + public DateTime CardExpiration { get; set; } - public string CardSecurityNumber { get; set; } + public string CardSecurityNumber { get; set; } - public int CardTypeId { get; set; } + public int CardTypeId { get; set; } - public string Buyer { get; set; } + public string Buyer { get; set; } - public Guid RequestId { get; set; } + public Guid RequestId { get; set; } - public CustomerBasket Basket { get; } + public CustomerBasket Basket { get; } - public UserCheckoutAcceptedIntegrationEvent(string userId, string userName, string city, string street, - string state, string country, string zipCode, string cardNumber, string cardHolderName, - DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId, - CustomerBasket basket) - { - UserId = userId; - UserName = userName; - City = city; - Street = street; - State = state; - Country = country; - ZipCode = zipCode; - CardNumber = cardNumber; - CardHolderName = cardHolderName; - CardExpiration = cardExpiration; - CardSecurityNumber = cardSecurityNumber; - CardTypeId = cardTypeId; - Buyer = buyer; - Basket = basket; - RequestId = requestId; - } + public UserCheckoutAcceptedIntegrationEvent(string userId, string userName, string city, string street, + string state, string country, string zipCode, string cardNumber, string cardHolderName, + DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId, + CustomerBasket basket) + { + UserId = userId; + UserName = userName; + City = city; + Street = street; + State = state; + Country = country; + ZipCode = zipCode; + CardNumber = cardNumber; + CardHolderName = cardHolderName; + CardExpiration = cardExpiration; + CardSecurityNumber = cardSecurityNumber; + CardTypeId = cardTypeId; + Buyer = buyer; + Basket = basket; + RequestId = requestId; + } - } + } } diff --git a/src/Services/Basket/Basket.API/Model/BasketCheckout.cs b/src/Services/Basket/Basket.API/Model/BasketCheckout.cs index 410700773..1944e1800 100644 --- a/src/Services/Basket/Basket.API/Model/BasketCheckout.cs +++ b/src/Services/Basket/Basket.API/Model/BasketCheckout.cs @@ -2,31 +2,31 @@ namespace Basket.API.Model { - public class BasketCheckout - { - public string City { get; set; } + public class BasketCheckout + { + public string City { get; set; } - public string Street { get; set; } + public string Street { get; set; } - public string State { get; set; } + public string State { get; set; } - public string Country { get; set; } + public string Country { get; set; } - public string ZipCode { get; set; } + public string ZipCode { get; set; } - public string CardNumber { get; set; } + public string CardNumber { get; set; } - public string CardHolderName { get; set; } + public string CardHolderName { get; set; } - public DateTime CardExpiration { get; set; } + public DateTime CardExpiration { get; set; } - public string CardSecurityNumber { get; set; } + public string CardSecurityNumber { get; set; } - public int CardTypeId { get; set; } + public int CardTypeId { get; set; } - public string Buyer { get; set; } + public string Buyer { get; set; } - public Guid RequestId { get; set; } - } + public Guid RequestId { get; set; } + } } diff --git a/src/Services/Basket/Basket.API/Model/BasketItem.cs b/src/Services/Basket/Basket.API/Model/BasketItem.cs index a41945145..ab4b56c31 100644 --- a/src/Services/Basket/Basket.API/Model/BasketItem.cs +++ b/src/Services/Basket/Basket.API/Model/BasketItem.cs @@ -3,25 +3,25 @@ using System.ComponentModel.DataAnnotations; namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { - public class BasketItem : IValidatableObject - { - public string Id { get; set; } - public string ProductId { get; set; } - public string ProductName { get; set; } - public decimal UnitPrice { get; set; } - public decimal OldUnitPrice { get; set; } - public int Quantity { get; set; } - public string PictureUrl { get; set; } - public IEnumerable Validate(ValidationContext validationContext) - { - var results = new List(); + public class BasketItem : IValidatableObject + { + public string Id { get; set; } + public string ProductId { get; set; } + public string ProductName { get; set; } + public decimal UnitPrice { get; set; } + public decimal OldUnitPrice { get; set; } + public int Quantity { get; set; } + public string PictureUrl { get; set; } + public IEnumerable Validate(ValidationContext validationContext) + { + var results = new List(); - if (Quantity < 1) - { - results.Add(new ValidationResult("Invalid number of units", new []{ "Quantity" })); - } + if (Quantity < 1) + { + results.Add(new ValidationResult("Invalid number of units", new[] { "Quantity" })); + } - return results; - } - } + return results; + } + } } diff --git a/src/Services/Basket/Basket.API/Model/CustomerBasket.cs b/src/Services/Basket/Basket.API/Model/CustomerBasket.cs index 3dd034f6c..0cdac89a2 100644 --- a/src/Services/Basket/Basket.API/Model/CustomerBasket.cs +++ b/src/Services/Basket/Basket.API/Model/CustomerBasket.cs @@ -2,15 +2,15 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { - public class CustomerBasket - { - public string BuyerId { get; set; } - public List Items { get; set; } + public class CustomerBasket + { + public string BuyerId { get; set; } + public List Items { get; set; } - public CustomerBasket(string customerId) - { - BuyerId = customerId; - Items = new List(); - } - } + public CustomerBasket(string customerId) + { + BuyerId = customerId; + Items = new List(); + } + } } diff --git a/src/Services/Basket/Basket.API/Model/IBasketRepository.cs b/src/Services/Basket/Basket.API/Model/IBasketRepository.cs index 850b5b637..1a5b64551 100644 --- a/src/Services/Basket/Basket.API/Model/IBasketRepository.cs +++ b/src/Services/Basket/Basket.API/Model/IBasketRepository.cs @@ -3,11 +3,11 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { - public interface IBasketRepository - { - Task GetBasketAsync(string customerId); - IEnumerable GetUsers(); - Task UpdateBasketAsync(CustomerBasket basket); - Task DeleteBasketAsync(string id); - } + public interface IBasketRepository + { + Task GetBasketAsync(string customerId); + IEnumerable GetUsers(); + Task UpdateBasketAsync(CustomerBasket basket); + Task DeleteBasketAsync(string id); + } } diff --git a/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs b/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs index f748d2c25..9ed59beaf 100644 --- a/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs +++ b/src/Services/Basket/Basket.API/Model/RedisBasketRepository.cs @@ -7,61 +7,61 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API.Model { - public class RedisBasketRepository : IBasketRepository - { - private readonly ILogger _logger; + public class RedisBasketRepository : IBasketRepository + { + private readonly ILogger _logger; - private readonly ConnectionMultiplexer _redis; - private readonly IDatabase _database; + private readonly ConnectionMultiplexer _redis; + private readonly IDatabase _database; - public RedisBasketRepository(ILoggerFactory loggerFactory, ConnectionMultiplexer redis) - { - _logger = loggerFactory.CreateLogger(); - _redis = redis; - _database = redis.GetDatabase(); - } + public RedisBasketRepository(ILoggerFactory loggerFactory, ConnectionMultiplexer redis) + { + _logger = loggerFactory.CreateLogger(); + _redis = redis; + _database = redis.GetDatabase(); + } - public async Task DeleteBasketAsync(string id) - { - return await _database.KeyDeleteAsync(id); - } + public async Task DeleteBasketAsync(string id) + { + return await _database.KeyDeleteAsync(id); + } - public IEnumerable GetUsers() - { - var server = GetServer(); - var data = server.Keys(); - return data?.Select(k => k.ToString()); - } + public IEnumerable GetUsers() + { + var server = GetServer(); + var data = server.Keys(); + return data?.Select(k => k.ToString()); + } - public async Task GetBasketAsync(string customerId) - { - var data = await _database.StringGetAsync(customerId); - if (data.IsNullOrEmpty) - { - return null; - } + public async Task GetBasketAsync(string customerId) + { + var data = await _database.StringGetAsync(customerId); + if (data.IsNullOrEmpty) + { + return null; + } - return JsonConvert.DeserializeObject(data); - } + return JsonConvert.DeserializeObject(data); + } - public async Task UpdateBasketAsync(CustomerBasket basket) - { - var created = await _database.StringSetAsync(basket.BuyerId, JsonConvert.SerializeObject(basket)); - if (!created) - { - _logger.LogInformation("Problem occur persisting the item."); - return null; - } + public async Task UpdateBasketAsync(CustomerBasket basket) + { + var created = await _database.StringSetAsync(basket.BuyerId, JsonConvert.SerializeObject(basket)); + if (!created) + { + _logger.LogInformation("Problem occur persisting the item."); + return null; + } - _logger.LogInformation("Basket item persisted succesfully."); + _logger.LogInformation("Basket item persisted succesfully."); - return await GetBasketAsync(basket.BuyerId); - } + return await GetBasketAsync(basket.BuyerId); + } - private IServer GetServer() - { - var endpoint = _redis.GetEndPoints(); - return _redis.GetServer(endpoint.First()); - } - } + private IServer GetServer() + { + var endpoint = _redis.GetEndPoints(); + return _redis.GetServer(endpoint.First()); + } + } } diff --git a/src/Services/Basket/Basket.API/Program.cs b/src/Services/Basket/Basket.API/Program.cs index 303a4625d..ca98660e5 100644 --- a/src/Services/Basket/Basket.API/Program.cs +++ b/src/Services/Basket/Basket.API/Program.cs @@ -1,55 +1,61 @@ using Basket.API.Infrastructure.Middlewares; -using Microsoft.AspNetCore; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using System; -using System.IO; +using static Microsoft.AspNetCore.Hosting.ApplicationInsightsWebHostBuilderExtensions; +using static Microsoft.AspNetCore.Hosting.HealthCheckWebHostBuilderExtension; +using static Microsoft.AspNetCore.Hosting.HostingAbstractionsWebHostBuilderExtensions; +using static Microsoft.AspNetCore.Hosting.WebHostBuilderExtensions; +using static Microsoft.AspNetCore.Hosting.WebHostExtensions; +using static Microsoft.Extensions.Configuration.AzureKeyVaultConfigurationExtensions; +using static Microsoft.Extensions.Configuration.ChainedBuilderExtensions; +using static Microsoft.Extensions.Configuration.EnvironmentVariablesExtensions; +using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder; +using Convert = System.Convert; +using Directory = System.IO.Directory; +using IWebHost = Microsoft.AspNetCore.Hosting.IWebHost; +using WebHost = Microsoft.AspNetCore.WebHost; namespace Microsoft.eShopOnContainers.Services.Basket.API { - public class Program - { - public static void Main(string[] args) - { - BuildWebHost(args).Run(); - } + public class Program + { + public static void Main(string[] args) + => BuildWebHost(args).Run(); - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseFailing(options => - { - options.ConfigPath = "/Failing"; - }) - .UseHealthChecks("/hc") - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseStartup() - .ConfigureAppConfiguration((builderContext, config) => - { - var builtConfig = config.Build(); + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseFailing(options => + { + options.ConfigPath = "/Failing"; + }) + .UseHealthChecks("/hc") + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .ConfigureAppConfiguration((builderContext, config) => + { + var builtConfig = config.Build(); - var configurationBuilder = new ConfigurationBuilder(); + var configurationBuilder = new ConfigurationBuilder(); - if (Convert.ToBoolean(builtConfig["UseVault"])) - { - configurationBuilder.AddAzureKeyVault( - $"https://{builtConfig["Vault:Name"]}.vault.azure.net/", - builtConfig["Vault:ClientId"], - builtConfig["Vault:ClientSecret"]); - } + if (Convert.ToBoolean(builtConfig["UseVault"])) + { + configurationBuilder.AddAzureKeyVault( + $"https://{builtConfig["Vault:Name"]}.vault.azure.net/", + builtConfig["Vault:ClientId"], + builtConfig["Vault:ClientSecret"]); + } - configurationBuilder.AddEnvironmentVariables(); + configurationBuilder.AddEnvironmentVariables(); - config.AddConfiguration(configurationBuilder.Build()); - }) - .ConfigureLogging((hostingContext, builder) => - { - builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); - builder.AddConsole(); - builder.AddDebug(); - }) - .UseApplicationInsights() - .Build(); - } + config.AddConfiguration(configurationBuilder.Build()); + }) + .ConfigureLogging((hostingContext, builder) => + { + builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); + builder.AddConsole(); + builder.AddDebug(); + }) + .UseApplicationInsights() + .Build(); + } } diff --git a/src/Services/Basket/Basket.API/Services/IIdentityService.cs b/src/Services/Basket/Basket.API/Services/IIdentityService.cs index fe84e23d5..1c7c62834 100644 --- a/src/Services/Basket/Basket.API/Services/IIdentityService.cs +++ b/src/Services/Basket/Basket.API/Services/IIdentityService.cs @@ -1,7 +1,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Services { - public interface IIdentityService - { - string GetUserIdentity(); - } + public interface IIdentityService + { + string GetUserIdentity(); + } } diff --git a/src/Services/Basket/Basket.API/Services/IdentityService.cs b/src/Services/Basket/Basket.API/Services/IdentityService.cs index d187be8d6..c1e2d901a 100644 --- a/src/Services/Basket/Basket.API/Services/IdentityService.cs +++ b/src/Services/Basket/Basket.API/Services/IdentityService.cs @@ -4,18 +4,18 @@ using System; namespace Microsoft.eShopOnContainers.Services.Basket.API.Services { - public class IdentityService : IIdentityService - { - private IHttpContextAccessor _context; + public class IdentityService : IIdentityService + { + private IHttpContextAccessor _context; - public IdentityService(IHttpContextAccessor context) - { - _context = context ?? throw new ArgumentNullException(nameof(context)); - } + public IdentityService(IHttpContextAccessor context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + } - public string GetUserIdentity() - { - return _context.HttpContext.User.FindFirst("sub").Value; - } - } + public string GetUserIdentity() + { + return _context.HttpContext.User.FindFirst("sub").Value; + } + } } diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index 7d65ba8b4..5b1719a14 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -34,281 +34,285 @@ using System.Threading.Tasks; namespace Microsoft.eShopOnContainers.Services.Basket.API { - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - - // This method gets called by the runtime. Use this method to add services to the container. - public IServiceProvider ConfigureServices(IServiceCollection services) - { - RegisterAppInsights(services); - - // Add framework services. - services.AddMvc(options => - { - options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - options.Filters.Add(typeof(ValidateModelStateFilter)); - - }).AddControllersAsServices(); - - ConfigureAuthService(services); - - services.AddHealthChecks(checks => - { - checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask(HealthCheckResult.Healthy("Ok")), - TimeSpan.Zero //No cache for this HealthCheck, better just for demos - ); - }); - - services.Configure(Configuration); - - //By connecting here we are making sure that our service - //cannot start until redis is ready. This might slow down startup, - //but given that there is a delay on resolving the ip address - //and then creating the connection it seems reasonable to move - //that cost to startup instead of having the first request pay the - //penalty. - services.AddSingleton(sp => - { - var settings = sp.GetRequiredService>().Value; - var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true); - - configuration.ResolveDns = true; - - return ConnectionMultiplexer.Connect(configuration); - }); - - - if (Configuration.GetValue("AzureServiceBusEnabled")) - { - services.AddSingleton(sp => - { - var logger = sp.GetRequiredService>(); - - var serviceBusConnectionString = Configuration["EventBusConnection"]; - var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString); - - return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger); - }); - } - else - { - services.AddSingleton(sp => - { - var logger = sp.GetRequiredService>(); - - var factory = new ConnectionFactory() - { - HostName = Configuration["EventBusConnection"] - }; - - if (!string.IsNullOrEmpty(Configuration["EventBusUserName"])) - { - factory.UserName = Configuration["EventBusUserName"]; - } - - if (!string.IsNullOrEmpty(Configuration["EventBusPassword"])) - { - factory.Password = Configuration["EventBusPassword"]; - } - - var retryCount = 5; - if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"])) - { - retryCount = int.Parse(Configuration["EventBusRetryCount"]); - } - - return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); - }); - } - - RegisterEventBus(services); - - services.AddSwaggerGen(options => - { - options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Info - { - Title = "Basket HTTP API", - Version = "v1", - Description = "The Basket Service HTTP API", - TermsOfService = "Terms Of Service" - }); - - options.AddSecurityDefinition("oauth2", new OAuth2Scheme - { - Type = "oauth2", - Flow = "implicit", - AuthorizationUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/token", - Scopes = new Dictionary() - { - { "basket", "Basket API" } - } - }); - - options.OperationFilter(); - }); - - services.AddCors(options => - { - options.AddPolicy("CorsPolicy", - builder => builder.AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials()); - }); - services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); - - services.AddOptions(); - - var container = new ContainerBuilder(); - container.Populate(services); - - return new AutofacServiceProvider(container.Build()); - } - - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) - { - loggerFactory.AddAzureWebAppDiagnostics(); - loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); - - var pathBase = Configuration["PATH_BASE"]; - if (!string.IsNullOrEmpty(pathBase)) - { - app.UsePathBase(pathBase); - } + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + + // This method gets called by the runtime. Use this method to add services to the container. + public IServiceProvider ConfigureServices(IServiceCollection services) + { + RegisterAppInsights(services); + + // Add framework services. + services + .AddMvc(options => + { + options.Filters.Add(typeof(HttpGlobalExceptionFilter)); + options.Filters.Add(typeof(ValidateModelStateFilter)); + + }) + .AddControllersAsServices(); + + ConfigureAuthService(services); + + services.AddHealthChecks(checks => + { + checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask(HealthCheckResult.Healthy("Ok")), + TimeSpan.Zero //No cache for this HealthCheck, better just for demos + ); + }); + + services.Configure(Configuration); + + //By connecting here we are making sure that our service + //cannot start until redis is ready. This might slow down startup, + //but given that there is a delay on resolving the ip address + //and then creating the connection it seems reasonable to move + //that cost to startup instead of having the first request pay the + //penalty. + services.AddSingleton(sp => + { + var settings = sp.GetRequiredService>().Value; + var configuration = ConfigurationOptions.Parse(settings.ConnectionString, true); + + configuration.ResolveDns = true; + + return ConnectionMultiplexer.Connect(configuration); + }); + + + if (Configuration.GetValue("AzureServiceBusEnabled")) + { + services.AddSingleton(sp => + { + var logger = sp.GetRequiredService>(); + + var serviceBusConnectionString = Configuration["EventBusConnection"]; + var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString); + + return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger); + }); + } + else + { + services.AddSingleton(sp => + { + var logger = sp.GetRequiredService>(); + + var factory = new ConnectionFactory() + { + HostName = Configuration["EventBusConnection"] + }; + + if (!string.IsNullOrEmpty(Configuration["EventBusUserName"])) + { + factory.UserName = Configuration["EventBusUserName"]; + } + + if (!string.IsNullOrEmpty(Configuration["EventBusPassword"])) + { + factory.Password = Configuration["EventBusPassword"]; + } + + var retryCount = 5; + if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"])) + { + retryCount = int.Parse(Configuration["EventBusRetryCount"]); + } + + return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); + }); + } + + RegisterEventBus(services); + + services.AddSwaggerGen(options => + { + options.DescribeAllEnumsAsStrings(); + options.SwaggerDoc("v1", new Info + { + Title = "Basket HTTP API", + Version = "v1", + Description = "The Basket Service HTTP API", + TermsOfService = "Terms Of Service" + }); + + options.AddSecurityDefinition("oauth2", new OAuth2Scheme + { + Type = "oauth2", + Flow = "implicit", + AuthorizationUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize", + TokenUrl = $"{Configuration.GetValue("IdentityUrlExternal")}/connect/token", + Scopes = new Dictionary() + { + { "basket", "Basket API" } + } + }); + + options.OperationFilter(); + }); + + services.AddCors(options => + { + options.AddPolicy("CorsPolicy", + builder => builder.AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials()); + }); + services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); + + services.AddOptions(); + + var container = new ContainerBuilder(); + container.Populate(services); + + return new AutofacServiceProvider(container.Build()); + } + + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + loggerFactory.AddAzureWebAppDiagnostics(); + loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); + + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + app.UsePathBase(pathBase); + } #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200)); + app.Map("/liveness", lapp => lapp.Run(async ctx => ctx.Response.StatusCode = 200)); #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously - app.UseStaticFiles(); - app.UseCors("CorsPolicy"); - - ConfigureAuth(app); - - app.UseMvcWithDefaultRoute(); - - app.UseSwagger() - .UseSwaggerUI(c => - { - c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1"); - c.OAuthClientId ("basketswaggerui"); - c.OAuthAppName("Basket Swagger UI"); - }); - - ConfigureEventBus(app); - - } - - private void RegisterAppInsights(IServiceCollection services) - { - services.AddApplicationInsightsTelemetry(Configuration); - var orchestratorType = Configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.EnableKubernetes(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } - } - - private void ConfigureAuthService(IServiceCollection services) - { - // prevent from mapping "sub" claim to nameidentifier. - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); - - var identityUrl = Configuration.GetValue("IdentityUrl"); - - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - - }).AddJwtBearer(options => - { - options.Authority = identityUrl; - options.RequireHttpsMetadata = false; - options.Audience = "basket"; - }); - } - - protected virtual void ConfigureAuth(IApplicationBuilder app) - { - if (Configuration.GetValue("UseLoadTest")) - { - app.UseMiddleware(); - } - - app.UseAuthentication(); - } - - private void RegisterEventBus(IServiceCollection services) - { - var subscriptionClientName = Configuration["SubscriptionClientName"]; - - if (Configuration.GetValue("AzureServiceBusEnabled")) - { - services.AddSingleton(sp => - { - var serviceBusPersisterConnection = sp.GetRequiredService(); - var iLifetimeScope = sp.GetRequiredService(); - var logger = sp.GetRequiredService>(); - var eventBusSubcriptionsManager = sp.GetRequiredService(); - - return new EventBusServiceBus(serviceBusPersisterConnection, logger, - eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); - }); - } - else - { - services.AddSingleton(sp => - { - var rabbitMQPersistentConnection = sp.GetRequiredService(); - var iLifetimeScope = sp.GetRequiredService(); - var logger = sp.GetRequiredService>(); - var eventBusSubcriptionsManager = sp.GetRequiredService(); - - var retryCount = 5; - if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"])) - { - retryCount = int.Parse(Configuration["EventBusRetryCount"]); - } - - return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); - }); - } - - services.AddSingleton(); - - services.AddTransient(); - services.AddTransient(); - } - - private void ConfigureEventBus(IApplicationBuilder app) - { - var eventBus = app.ApplicationServices.GetRequiredService(); - - eventBus.Subscribe(); - eventBus.Subscribe(); - } - } + app.UseStaticFiles(); + app.UseCors("CorsPolicy"); + + ConfigureAuth(app); + + app.UseMvcWithDefaultRoute(); + + app.UseSwagger() + .UseSwaggerUI(c => + { + c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1"); + c.OAuthClientId("basketswaggerui"); + c.OAuthAppName("Basket Swagger UI"); + }); + + ConfigureEventBus(app); + + } + + private void RegisterAppInsights(IServiceCollection services) + { + services.AddApplicationInsightsTelemetry(Configuration); + var orchestratorType = Configuration.GetValue("OrchestratorType"); + + if (orchestratorType?.ToUpper() == "K8S") + { + // Enable K8s telemetry initializer + services.EnableKubernetes(); + } + if (orchestratorType?.ToUpper() == "SF") + { + // Enable SF telemetry initializer + services.AddSingleton((serviceProvider) => + new FabricTelemetryInitializer()); + } + } + + private void ConfigureAuthService(IServiceCollection services) + { + // prevent from mapping "sub" claim to nameidentifier. + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + + var identityUrl = Configuration.GetValue("IdentityUrl"); + + services + .AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + + }) + .AddJwtBearer(options => + { + options.Authority = identityUrl; + options.RequireHttpsMetadata = false; + options.Audience = "basket"; + }); + } + + protected virtual void ConfigureAuth(IApplicationBuilder app) + { + if (Configuration.GetValue("UseLoadTest")) + { + app.UseMiddleware(); + } + + app.UseAuthentication(); + } + + private void RegisterEventBus(IServiceCollection services) + { + var subscriptionClientName = Configuration["SubscriptionClientName"]; + + if (Configuration.GetValue("AzureServiceBusEnabled")) + { + services.AddSingleton(sp => + { + var serviceBusPersisterConnection = sp.GetRequiredService(); + var iLifetimeScope = sp.GetRequiredService(); + var logger = sp.GetRequiredService>(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); + + return new EventBusServiceBus(serviceBusPersisterConnection, logger, + eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); + }); + } + else + { + services.AddSingleton(sp => + { + var rabbitMQPersistentConnection = sp.GetRequiredService(); + var iLifetimeScope = sp.GetRequiredService(); + var logger = sp.GetRequiredService>(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); + + var retryCount = 5; + if (!string.IsNullOrEmpty(Configuration["EventBusRetryCount"])) + { + retryCount = int.Parse(Configuration["EventBusRetryCount"]); + } + + return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); + }); + } + + services.AddSingleton(); + + services.AddTransient(); + services.AddTransient(); + } + + private void ConfigureEventBus(IApplicationBuilder app) + { + var eventBus = app.ApplicationServices.GetRequiredService(); + + eventBus.Subscribe(); + eventBus.Subscribe(); + } + } } diff --git a/src/Services/Basket/Basket.API/appsettings.json b/src/Services/Basket/Basket.API/appsettings.json index 4bff4d70d..9518e16eb 100644 --- a/src/Services/Basket/Basket.API/appsettings.json +++ b/src/Services/Basket/Basket.API/appsettings.json @@ -1,24 +1,24 @@ { - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - }, - "IdentityUrl": "http://localhost:5105", - "ConnectionString": "127.0.0.1", - "AzureServiceBusEnabled": false, - "SubscriptionClientName": "Basket", - "ApplicationInsights": { - "InstrumentationKey": "" - }, - "EventBusRetryCount": 5, - "UseVault": false, - "Vault": { - "Name": "eshop", - "ClientId": "your-clien-id", - "ClientSecret": "your-client-secret" - } + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + }, + "IdentityUrl": "http://localhost:5105", + "ConnectionString": "127.0.0.1", + "AzureServiceBusEnabled": false, + "SubscriptionClientName": "Basket", + "ApplicationInsights": { + "InstrumentationKey": "" + }, + "EventBusRetryCount": 5, + "UseVault": false, + "Vault": { + "Name": "eshop", + "ClientId": "your-clien-id", + "ClientSecret": "your-client-secret" + } } \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/web.config b/src/Services/Basket/Basket.API/web.config index dc0514fca..b720536cb 100644 --- a/src/Services/Basket/Basket.API/web.config +++ b/src/Services/Basket/Basket.API/web.config @@ -1,14 +1,14 @@  - - - - - - - + + + + + +