openpay-js
Version:
Openpay JS interface library
965 lines (918 loc) • 35.7 kB
JavaScript
//"use strict";
(function(){
var _deviceData = function() {};
var _deviceDataSC = function() {};
var _getBeaconKey = function() {};
_deviceData._hostname = "https://api.openpay.mx/";
_deviceData._sandboxHostname = "https://sandbox-api.openpay.mx/";
_deviceData._developHostname = "https://dev-api.openpay.mx/";
_deviceData._deviceDataId = undefined;
/* Get current deviceDataId or generate new one */
function getDeviceDataId() {
if (_deviceData._deviceDataId === undefined) {
_deviceData._deviceDataId = sjcl.codec.base64.fromBits(sjcl.random.randomWords(6, 0)).replace(/[\+\/]/g,'0');
}
return _deviceData._deviceDataId;
}
/* GET ANTI-FRAUD COMPONENTS */
function get_antifraud_comp(hostname, merchant, sessionId){
var antifraudURL = hostname+'antifraud/'+merchant+'/components?s='+sessionId;
if (window.XDomainRequest) {
var xdr = new XDomainRequest();
xdr.open("GET", antifraudURL);
xdr.onload = function() {
document.body.insertAdjacentHTML("beforeend",xdr.responseText);
}
setTimeout(function () {xdr.send();}, 0);
}else{
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.body.insertAdjacentHTML("beforeend",xmlhttp.responseText);
}
}
xmlhttp.open('GET', antifraudURL , true);
xmlhttp.send();
}
}
/* Collect device data */
function collect() {
var hostname;
var sessionId = getDeviceDataId();
if (OpenPay.developMode) {
hostname = _deviceData._developHostname;
} else if (OpenPay.sandboxMode) {
hostname = _deviceData._sandboxHostname;
} else {
hostname = _deviceData._hostname;
}
var merchant = OpenPay.getId();
get_antifraud_comp(hostname,merchant,sessionId);
return getDeviceDataId();
}
/* Collect device data, and add a hidden field to the form with the given ID if specified. */
_deviceData['setup'] = function(_formId, _hiddenFieldName) {
var sessionId = getDeviceDataId();
if(_formId && document.getElementById(_formId)){
var input = document.createElement("input");
input.setAttribute('type', 'hidden');
input.value = sessionId;
input.name = _hiddenFieldName ? _hiddenFieldName : 'deviceDataId';
input.id = _hiddenFieldName ? _hiddenFieldName : 'deviceDataId';
document.getElementById(_formId).appendChild(input);
}
var isNewLibraryOpenPay = true;
try {
OpenPay.getId();
OpenPay.getApiKey();
} catch (e) {
isNewLibraryOpenPay = false;
}
if(isNewLibraryOpenPay){
console.log("executing sift mode");
var publicId = OpenPay.getId();
var apiKey = OpenPay.getApiKey();
var hostname;
if (OpenPay.developMode) {
hostname = _deviceData._developHostname;
} else if (OpenPay.sandboxMode) {
hostname = _deviceData._sandboxHostname;
} else {
hostname = _deviceData._hostname;
}
var url = hostname + "v1/" + publicId +"/antifraudkeys";
//se obtiene el beaconKey de siftscience
try {
OpenPay.getBeaconKey.beaconKey(url, apiKey, "", sessionId,hostname);
} catch(e){
console.log("continue without beaconkey" + e);
}
}
return collect();
};
_getBeaconKey['beaconKey'] = function(endpoint, publicKey, userId, sessionId, hostname) {
var _rhr = null, _timer = null, _url = endpoint, _headers = {}, _timeout = 0, _auth = btoa(publicKey + ":");
var _data = {};
function handleError(_message, _status, _responseText) {
clearTimeout(_timer);
var _data = null;
_message = _message || 'Unknown error';
_status = _status || 0;
_responseText = _responseText || '{}';
try {
_data = JSON.parse(_responseText);
} catch (e) {
_message = 'Response error';
}
};
if (typeof JSON === 'undefined') {
handleError('Browser error (JSON library not found)');
return;
}
_timeout = 4e4;
var hasCors = XMLHttpRequest && ("withCredentials" in new XMLHttpRequest());
if(!hasCors){
if (typeof XDomainRequest !== 'undefined') {
// Inicia jsonp
_data.apiKey = _auth;
var handleResponse = function(data){
if(data.error){
handleError('Request error', data.httpStatus, JSON.stringify(data));
} else {
try {
var beaconKey = data.data;
console.log("beaconKey ok");
if(beaconKey.length > 0){
//Se lanza el script siftScience con el beaconKey obtenido
OpenPay.deviceDataSC.setupSC(userId, sessionId, beaconKey,hostname);
}else{
console.log("Empty beaconKey normal in Sandbox");
}
} catch (e) {
handleError('Response error (Unknown final status)', _rhr.status, '{}');
}
}
};
var request = {
callbackName:"getResultData",
onSuccess:handleResponse,
onError:handleError,
timeout:_timeout,
url:_url+ "/jsonp",
data:_data
};
$jsonp.send(request);
// Finaliza jsonp
}else{
handleError('Browser error (CORS not supported)');
return;
}
} else{
function getXhr(){
if (isHostMethod(window, "XMLHttpRequest")) {
return new XMLHttpRequest();
}
};
function isHostMethod(object, property){
var t = typeof object[property];
return t == 'function' ||
(!!(t == 'object' && object[property])) ||
t == 'unknown';
};
function handleResponseBK(){
// handle only if request has finished
if (typeof _rhr.readyState !== 'undefined' && _rhr.readyState == 4 || !hasCors) {
clearTimeout(_timer);
if (_rhr.status < 200 || _rhr.status >= 300) {
handleError('Request error NO IE', _rhr.status, _rhr.responseText);
} else {
try {
var rt = _rhr.responseText;
rt = rt.replace("(","");
rt = rt.replace(")","");
var jsonResponse = JSON.parse(rt);
var beaconKey = jsonResponse.data;
console.log("beaconKey ok");
if(beaconKey.length > 0){
//Se lanza el script siftScience con el beaconKey obtenido
OpenPay.deviceDataSC.setupSC(userId, sessionId, beaconKey, hostname);
}else{
console.log("Empty beaconKey normal in Sandbox");
}
} catch (e) {
handleError('Response error (Unknown final status) NO IE', _rhr.status, '{}');
}
}
}
};
if (!(_rhr = getXhr())) {
handleError('Browser error (CORS not supported)');
return;
}
_headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': "Basic " + _auth
};
_rhr.open('GET', _url, true);
if ('withCredentials' in _rhr) {
_rhr.withCredentials = true;
}
for (var prop in _headers) {
if (_headers.hasOwnProperty(prop) && _headers[prop]) {
if ('setRequestHeader' in _rhr) {
_rhr.setRequestHeader(prop, _headers[prop]);
}
}
}
if ('onreadystatechange' in _rhr) {
_rhr.onreadystatechange = handleResponseBK;
} else if ('onload' in _rhr && 'onerror' in _rhr) {
_rhr.onload = handleResponseBK;
_rhr.onerror = handleError;
}
_timer = setTimeout(function(){
if ('onload' in _rhr) {
_rhr.onload = Function.prototype;
} else {
_rhr.onreadystatechange = Function.prototype;
}
_rhr.abort();
_rhr = null;
handleError('Timeout after ' + _timeout + ' milliseconds');
}, _timeout);
_rhr.send();
}
}
/* Initialize the siftscience snippet for device detection */
_deviceDataSC['setupSC'] = function(userId, sessionId, beaconKey, hostname) {
console.log("Sift Snippet");
var _sift = window._sift = window._sift || [];
_sift.push(['_setAccount', beaconKey]);
_sift.push(['_setSessionId', sessionId]);
_sift.push(['_trackPageview']);
var e = document.createElement('script');
e.type = 'text/javascript';
e.async = true;
e.src = hostname+'antifraud/sc.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(e, s);
};
OpenPay['deviceData'] = _deviceData;
OpenPay['getBeaconKey'] = _getBeaconKey;
OpenPay['deviceDataSC'] = _deviceDataSC;
/* Bundled SJCL library with modules CodecBase64 and Random */
/*
* Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh. All rights
* reserved. Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of the authors.
*/
var sjcl = {cipher:{}, hash:{}, keyexchange:{}, mode:{}, misc:{}, codec:{}, exception:{corrupt:function(message) {
this.toString = function() {
return"CORRUPT: " + this.message
};
this.message = message
}, invalid:function(message) {
this.toString = function() {
return"INVALID: " + this.message
};
this.message = message
}, bug:function(message) {
this.toString = function() {
return"BUG: " + this.message
};
this.message = message
}, notReady:function(message) {
this.toString = function() {
return"NOT READY: " + this.message
};
this.message = message
}}};
if(typeof module !== "undefined" && module.exports) {
module.exports = sjcl
}
sjcl.cipher.aes = function(key) {
if(!this._tables[0][0][0]) {
this._precompute()
}
var i, j, tmp, encKey, decKey, sbox = this._tables[0][4], decTable = this._tables[1], keyLen = key.length, rcon = 1;
if(keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
throw new sjcl.exception.invalid("invalid aes key size");
}
this._key = [encKey = key.slice(0), decKey = []];
for(i = keyLen;i < 4 * keyLen + 28;i++) {
tmp = encKey[i - 1];
if(i % keyLen === 0 || keyLen === 8 && i % keyLen === 4) {
tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255];
if(i % keyLen === 0) {
tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
rcon = rcon << 1 ^ (rcon >> 7) * 283
}
}
encKey[i] = encKey[i - keyLen] ^ tmp
}
for(j = 0;i;j++, i--) {
tmp = encKey[j & 3 ? i : i - 4];
if(i <= 4 || j < 4) {
decKey[j] = tmp
}else {
decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ decTable[1][sbox[tmp >> 16 & 255]] ^ decTable[2][sbox[tmp >> 8 & 255]] ^ decTable[3][sbox[tmp & 255]]
}
}
};
sjcl.cipher.aes.prototype = {encrypt:function(data) {
return this._crypt(data, 0)
}, decrypt:function(data) {
return this._crypt(data, 1)
}, _tables:[[[], [], [], [], []], [[], [], [], [], []]], _precompute:function() {
var encTable = this._tables[0], decTable = this._tables[1], sbox = encTable[4], sboxInv = decTable[4], i, x, xInv, d = [], th = [], x2, x4, x8, s, tEnc, tDec;
for(i = 0;i < 0x100;i++) {
th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i
}
for(x = xInv = 0;!sbox[x];x ^= x2 || 1, xInv = th[xInv] || 1) {
s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
s = s >> 8 ^ s & 255 ^ 99;
sbox[x] = s;
sboxInv[s] = x;
x8 = d[x4 = d[x2 = d[x]]];
tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
tEnc = d[s] * 0x101 ^ s * 0x1010100;
for(i = 0;i < 4;i++) {
encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8
}
}
for(i = 0;i < 5;i++) {
encTable[i] = encTable[i].slice(0);
decTable[i] = decTable[i].slice(0)
}
}, _crypt:function(input, dir) {
if(input.length !== 4) {
throw new sjcl.exception.invalid("invalid aes block size");
}
var key = this._key[dir], a = input[0] ^ key[0], b = input[dir ? 3 : 1] ^ key[1], c = input[2] ^ key[2], d = input[dir ? 1 : 3] ^ key[3], a2, b2, c2, nInnerRounds = key.length / 4 - 2, i, kIndex = 4, out = [0, 0, 0, 0], table = this._tables[dir], t0 = table[0], t1 = table[1], t2 = table[2], t3 = table[3], sbox = table[4];
for(i = 0;i < nInnerRounds;i++) {
a2 = t0[a >>> 24] ^ t1[b >> 16 & 255] ^ t2[c >> 8 & 255] ^ t3[d & 255] ^ key[kIndex];
b2 = t0[b >>> 24] ^ t1[c >> 16 & 255] ^ t2[d >> 8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
c2 = t0[c >>> 24] ^ t1[d >> 16 & 255] ^ t2[a >> 8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
d = t0[d >>> 24] ^ t1[a >> 16 & 255] ^ t2[b >> 8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
kIndex += 4;
a = a2;
b = b2;
c = c2
}
for(i = 0;i < 4;i++) {
out[dir ? 3 & -i : i] = sbox[a >>> 24] << 24 ^ sbox[b >> 16 & 255] << 16 ^ sbox[c >> 8 & 255] << 8 ^ sbox[d & 255] ^ key[kIndex++];
a2 = a;
a = b;
b = c;
c = d;
d = a2
}
return out
}};
sjcl.bitArray = {bitSlice:function(a, bstart, bend) {
a = sjcl.bitArray._shiftRight(a.slice(bstart / 32), 32 - (bstart & 31)).slice(1);
return bend === undefined ? a : sjcl.bitArray.clamp(a, bend - bstart)
}, extract:function(a, bstart, blength) {
var x, sh = Math.floor(-bstart - blength & 31);
if((bstart + blength - 1 ^ bstart) & -32) {
x = a[bstart / 32 | 0] << 32 - sh ^ a[bstart / 32 + 1 | 0] >>> sh
}else {
x = a[bstart / 32 | 0] >>> sh
}
return x & (1 << blength) - 1
}, concat:function(a1, a2) {
if(a1.length === 0 || a2.length === 0) {
return a1.concat(a2)
}
var out, i, last = a1[a1.length - 1], shift = sjcl.bitArray.getPartial(last);
if(shift === 32) {
return a1.concat(a2)
}else {
return sjcl.bitArray._shiftRight(a2, shift, last | 0, a1.slice(0, a1.length - 1))
}
}, bitLength:function(a) {
var l = a.length, x;
if(l === 0) {
return 0
}
x = a[l - 1];
return(l - 1) * 32 + sjcl.bitArray.getPartial(x)
}, clamp:function(a, len) {
if(a.length * 32 < len) {
return a
}
a = a.slice(0, Math.ceil(len / 32));
var l = a.length;
len = len & 31;
if(l > 0 && len) {
a[l - 1] = sjcl.bitArray.partial(len, a[l - 1] & 2147483648 >> len - 1, 1)
}
return a
}, partial:function(len, x, _end) {
if(len === 32) {
return x
}
return(_end ? x | 0 : x << 32 - len) + len * 0x10000000000
}, getPartial:function(x) {
return Math.round(x / 0x10000000000) || 32
}, equal:function(a, b) {
if(sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) {
return false
}
var x = 0, i;
for(i = 0;i < a.length;i++) {
x |= a[i] ^ b[i]
}
return x === 0
}, _shiftRight:function(a, shift, carry, out) {
var i, last2 = 0, shift2;
if(out === undefined) {
out = []
}
for(;shift >= 32;shift -= 32) {
out.push(carry);
carry = 0
}
if(shift === 0) {
return out.concat(a)
}
for(i = 0;i < a.length;i++) {
out.push(carry | a[i] >>> shift);
carry = a[i] << 32 - shift
}
last2 = a.length ? a[a.length - 1] : 0;
shift2 = sjcl.bitArray.getPartial(last2);
out.push(sjcl.bitArray.partial(shift + shift2 & 31, shift + shift2 > 32 ? carry : out.pop(), 1));
return out
}, _xor4:function(x, y) {
return[x[0] ^ y[0], x[1] ^ y[1], x[2] ^ y[2], x[3] ^ y[3]]
}};
sjcl.codec.utf8String = {fromBits:function(arr) {
var out = "", bl = sjcl.bitArray.bitLength(arr), i, tmp;
for(i = 0;i < bl / 8;i++) {
if((i & 3) === 0) {
tmp = arr[i / 4]
}
out += String.fromCharCode(tmp >>> 24);
tmp <<= 8
}
return decodeURIComponent(escape(out))
}, toBits:function(str) {
str = unescape(encodeURIComponent(str));
var out = [], i, tmp = 0;
for(i = 0;i < str.length;i++) {
tmp = tmp << 8 | str.charCodeAt(i);
if((i & 3) === 3) {
out.push(tmp);
tmp = 0
}
}
if(i & 3) {
out.push(sjcl.bitArray.partial(8 * (i & 3), tmp))
}
return out
}};
sjcl.codec.base64 = {_chars:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", fromBits:function(arr, _noEquals, _url) {
var out = "", i, bits = 0, c = sjcl.codec.base64._chars, ta = 0, bl = sjcl.bitArray.bitLength(arr);
if(_url) {
c = c.substr(0, 62) + "-_"
}
for(i = 0;out.length * 6 < bl;) {
out += c.charAt((ta ^ arr[i] >>> bits) >>> 26);
if(bits < 6) {
ta = arr[i] << 6 - bits;
bits += 26;
i++
}else {
ta <<= 6;
bits -= 6
}
}
while(out.length & 3 && !_noEquals) {
out += "="
}
return out
}, toBits:function(str, _url) {
str = str.replace(/\s|=/g, "");
var out = [], i, bits = 0, c = sjcl.codec.base64._chars, ta = 0, x;
if(_url) {
c = c.substr(0, 62) + "-_"
}
for(i = 0;i < str.length;i++) {
x = c.indexOf(str.charAt(i));
if(x < 0) {
throw new sjcl.exception.invalid("this isn't base64!");
}
if(bits > 26) {
bits -= 26;
out.push(ta ^ x >>> bits);
ta = x << 32 - bits
}else {
bits += 6;
ta ^= x << 32 - bits
}
}
if(bits & 56) {
out.push(sjcl.bitArray.partial(bits & 56, ta, 1))
}
return out
}};
sjcl.codec.base64url = {fromBits:function(arr) {
return sjcl.codec.base64.fromBits(arr, 1, 1)
}, toBits:function(str) {
return sjcl.codec.base64.toBits(str, 1)
}};
sjcl.hash.sha256 = function(hash) {
if(!this._key[0]) {
this._precompute()
}
if(hash) {
this._h = hash._h.slice(0);
this._buffer = hash._buffer.slice(0);
this._length = hash._length
}else {
this.reset()
}
};
sjcl.hash.sha256.hash = function(data) {
return(new sjcl.hash.sha256).update(data).finalize()
};
sjcl.hash.sha256.prototype = {blockSize:512, reset:function() {
this._h = this._init.slice(0);
this._buffer = [];
this._length = 0;
return this
}, update:function(data) {
if(typeof data === "string") {
data = sjcl.codec.utf8String.toBits(data)
}
var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data), ol = this._length, nl = this._length = ol + sjcl.bitArray.bitLength(data);
for(i = 512 + ol & -512;i <= nl;i += 512) {
this._block(b.splice(0, 16))
}
return this
}, finalize:function() {
var i, b = this._buffer, h = this._h;
b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1, 1)]);
for(i = b.length + 2;i & 15;i++) {
b.push(0)
}
b.push(Math.floor(this._length / 0x100000000));
b.push(this._length | 0);
while(b.length) {
this._block(b.splice(0, 16))
}
this.reset();
return h
}, _init:[], _key:[], _precompute:function() {
var i = 0, prime = 2, factor;
function frac(x) {
return(x - Math.floor(x)) * 0x100000000 | 0
}
outer:for(;i < 64;prime++) {
for(factor = 2;factor * factor <= prime;factor++) {
if(prime % factor === 0) {
continue outer
}
}
if(i < 8) {
this._init[i] = frac(Math.pow(prime, 1 / 2))
}
this._key[i] = frac(Math.pow(prime, 1 / 3));
i++
}
}, _block:function(words) {
var i, tmp, a, b, w = words.slice(0), h = this._h, k = this._key, h0 = h[0], h1 = h[1], h2 = h[2], h3 = h[3], h4 = h[4], h5 = h[5], h6 = h[6], h7 = h[7];
for(i = 0;i < 64;i++) {
if(i < 16) {
tmp = w[i]
}else {
a = w[i + 1 & 15];
b = w[i + 14 & 15];
tmp = w[i & 15] = (a >>> 7 ^ a >>> 18 ^ a >>> 3 ^ a << 25 ^ a << 14) + (b >>> 17 ^ b >>> 19 ^ b >>> 10 ^ b << 15 ^ b << 13) + w[i & 15] + w[i + 9 & 15] | 0
}
tmp = tmp + h7 + (h4 >>> 6 ^ h4 >>> 11 ^ h4 >>> 25 ^ h4 << 26 ^ h4 << 21 ^ h4 << 7) + (h6 ^ h4 & (h5 ^ h6)) + k[i];
h7 = h6;
h6 = h5;
h5 = h4;
h4 = h3 + tmp | 0;
h3 = h2;
h2 = h1;
h1 = h0;
h0 = tmp + (h1 & h2 ^ h3 & (h1 ^ h2)) + (h1 >>> 2 ^ h1 >>> 13 ^ h1 >>> 22 ^ h1 << 30 ^ h1 << 19 ^ h1 << 10) | 0
}
h[0] = h[0] + h0 | 0;
h[1] = h[1] + h1 | 0;
h[2] = h[2] + h2 | 0;
h[3] = h[3] + h3 | 0;
h[4] = h[4] + h4 | 0;
h[5] = h[5] + h5 | 0;
h[6] = h[6] + h6 | 0;
h[7] = h[7] + h7 | 0
}};
sjcl.prng = function(defaultParanoia) {
this._pools = [new sjcl.hash.sha256];
this._poolEntropy = [0];
this._reseedCount = 0;
this._robins = {};
this._eventId = 0;
this._collectorIds = {};
this._collectorIdNext = 0;
this._strength = 0;
this._poolStrength = 0;
this._nextReseed = 0;
this._key = [0, 0, 0, 0, 0, 0, 0, 0];
this._counter = [0, 0, 0, 0];
this._cipher = undefined;
this._defaultParanoia = defaultParanoia;
this._collectorsStarted = false;
this._callbacks = {progress:{}, seeded:{}};
this._callbackI = 0;
this._NOT_READY = 0;
this._READY = 1;
this._REQUIRES_RESEED = 2;
this._MAX_WORDS_PER_BURST = 0x10000;
this._PARANOIA_LEVELS = [0, 48, 64, 96, 128, 192, 0x100, 384, 512, 768, 1024];
this._MILLISECONDS_PER_RESEED = 3E4;
this._BITS_PER_RESEED = 80
};
sjcl.prng.prototype = {randomWords:function(nwords, paranoia) {
var out = [], i, readiness = this.isReady(paranoia), g;
if(readiness === this._NOT_READY) {
throw new sjcl.exception.notReady("generator isn't seeded");
}else {
if(readiness & this._REQUIRES_RESEED) {
this._reseedFromPools(!(readiness & this._READY))
}
}
for(i = 0;i < nwords;i += 4) {
if((i + 1) % this._MAX_WORDS_PER_BURST === 0) {
this._gate()
}
g = this._gen4words();
out.push(g[0], g[1], g[2], g[3])
}
this._gate();
return out.slice(0, nwords)
}, setDefaultParanoia:function(paranoia, allowZeroParanoia) {
if(paranoia === 0 && allowZeroParanoia !== "Setting paranoia=0 will ruin your security; use it only for testing") {
throw"Setting paranoia=0 will ruin your security; use it only for testing";
}
this._defaultParanoia = paranoia
}, addEntropy:function(data, estimatedEntropy, source) {
source = source || "user";
var id, i, tmp, t = (new Date).valueOf(), robin = this._robins[source], oldReady = this.isReady(), err = 0, objName;
id = this._collectorIds[source];
if(id === undefined) {
id = this._collectorIds[source] = this._collectorIdNext++
}
if(robin === undefined) {
robin = this._robins[source] = 0
}
this._robins[source] = (this._robins[source] + 1) % this._pools.length;
switch(typeof data) {
case "number":
if(estimatedEntropy === undefined) {
estimatedEntropy = 1
}
this._pools[robin].update([id, this._eventId++, 1, estimatedEntropy, t, 1, data | 0]);
break;
case "object":
objName = Object.prototype.toString.call(data);
if(objName === "[object Uint32Array]") {
tmp = [];
for(i = 0;i < data.length;i++) {
tmp.push(data[i])
}
data = tmp
}else {
if(objName !== "[object Array]") {
err = 1
}
for(i = 0;i < data.length && !err;i++) {
if(typeof data[i] !== "number") {
err = 1
}
}
}
if(!err) {
if(estimatedEntropy === undefined) {
estimatedEntropy = 0;
for(i = 0;i < data.length;i++) {
tmp = data[i];
while(tmp > 0) {
estimatedEntropy++;
tmp = tmp >>> 1
}
}
}
this._pools[robin].update([id, this._eventId++, 2, estimatedEntropy, t, data.length].concat(data))
}
break;
case "string":
if(estimatedEntropy === undefined) {
estimatedEntropy = data.length
}
this._pools[robin].update([id, this._eventId++, 3, estimatedEntropy, t, data.length]);
this._pools[robin].update(data);
break;
default:
err = 1
}
if(err) {
throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");
}
this._poolEntropy[robin] += estimatedEntropy;
this._poolStrength += estimatedEntropy;
if(oldReady === this._NOT_READY) {
if(this.isReady() !== this._NOT_READY) {
this._fireEvent("seeded", Math.max(this._strength, this._poolStrength))
}
this._fireEvent("progress", this.getProgress())
}
}, isReady:function(paranoia) {
var entropyRequired = this._PARANOIA_LEVELS[paranoia !== undefined ? paranoia : this._defaultParanoia];
if(this._strength && this._strength >= entropyRequired) {
return this._poolEntropy[0] > this._BITS_PER_RESEED && (new Date).valueOf() > this._nextReseed ? this._REQUIRES_RESEED | this._READY : this._READY
}else {
return this._poolStrength >= entropyRequired ? this._REQUIRES_RESEED | this._NOT_READY : this._NOT_READY
}
}, getProgress:function(paranoia) {
var entropyRequired = this._PARANOIA_LEVELS[paranoia ? paranoia : this._defaultParanoia];
if(this._strength >= entropyRequired) {
return 1
}else {
return this._poolStrength > entropyRequired ? 1 : this._poolStrength / entropyRequired
}
}, startCollectors:function() {
if(this._collectorsStarted) {
return
}
this._eventListener = {loadTimeCollector:this._bind(this._loadTimeCollector), mouseCollector:this._bind(this._mouseCollector), keyboardCollector:this._bind(this._keyboardCollector), accelerometerCollector:this._bind(this._accelerometerCollector)};
if(window.addEventListener) {
window.addEventListener("load", this._eventListener.loadTimeCollector, false);
window.addEventListener("mousemove", this._eventListener.mouseCollector, false);
window.addEventListener("keypress", this._eventListener.keyboardCollector, false);
window.addEventListener("devicemotion", this._eventListener.accelerometerCollector, false)
}else {
if(document.attachEvent) {
document.attachEvent("onload", this._eventListener.loadTimeCollector);
document.attachEvent("onmousemove", this._eventListener.mouseCollector);
document.attachEvent("keypress", this._eventListener.keyboardCollector)
}else {
throw new sjcl.exception.bug("can't attach event");
}
}
this._collectorsStarted = true
}, stopCollectors:function() {
if(!this._collectorsStarted) {
return
}
if(window.removeEventListener) {
window.removeEventListener("load", this._eventListener.loadTimeCollector, false);
window.removeEventListener("mousemove", this._eventListener.mouseCollector, false);
window.removeEventListener("keypress", this._eventListener.keyboardCollector, false);
window.removeEventListener("devicemotion", this._eventListener.accelerometerCollector, false)
}else {
if(document.detachEvent) {
document.detachEvent("onload", this._eventListener.loadTimeCollector);
document.detachEvent("onmousemove", this._eventListener.mouseCollector);
document.detachEvent("keypress", this._eventListener.keyboardCollector)
}
}
this._collectorsStarted = false
}, addEventListener:function(name, callback) {
this._callbacks[name][this._callbackI++] = callback
}, removeEventListener:function(name, cb) {
var i, j, cbs = this._callbacks[name], jsTemp = [];
for(j in cbs) {
if(cbs.hasOwnProperty(j) && cbs[j] === cb) {
jsTemp.push(j)
}
}
for(i = 0;i < jsTemp.length;i++) {
j = jsTemp[i];
delete cbs[j]
}
}, _bind:function(func) {
var that = this;
return function() {
func.apply(that, arguments)
}
}, _gen4words:function() {
for(var i = 0;i < 4;i++) {
this._counter[i] = this._counter[i] + 1 | 0;
if(this._counter[i]) {
break
}
}
return this._cipher.encrypt(this._counter)
}, _gate:function() {
this._key = this._gen4words().concat(this._gen4words());
this._cipher = new sjcl.cipher.aes(this._key)
}, _reseed:function(seedWords) {
this._key = sjcl.hash.sha256.hash(this._key.concat(seedWords));
this._cipher = new sjcl.cipher.aes(this._key);
for(var i = 0;i < 4;i++) {
this._counter[i] = this._counter[i] + 1 | 0;
if(this._counter[i]) {
break
}
}
}, _reseedFromPools:function(full) {
var reseedData = [], strength = 0, i;
this._nextReseed = reseedData[0] = (new Date).valueOf() + this._MILLISECONDS_PER_RESEED;
for(i = 0;i < 16;i++) {
reseedData.push(Math.random() * 0x100000000 | 0)
}
for(i = 0;i < this._pools.length;i++) {
reseedData = reseedData.concat(this._pools[i].finalize());
strength += this._poolEntropy[i];
this._poolEntropy[i] = 0;
if(!full && this._reseedCount & 1 << i) {
break
}
}
if(this._reseedCount >= 1 << this._pools.length) {
this._pools.push(new sjcl.hash.sha256);
this._poolEntropy.push(0)
}
this._poolStrength -= strength;
if(strength > this._strength) {
this._strength = strength
}
this._reseedCount++;
this._reseed(reseedData)
}, _keyboardCollector:function() {
this._addCurrentTimeToEntropy(1)
}, _mouseCollector:function(ev) {
var x = ev.x || ev.clientX || ev.offsetX || 0, y = ev.y || ev.clientY || ev.offsetY || 0;
sjcl.random.addEntropy([x, y], 2, "mouse");
this._addCurrentTimeToEntropy(0)
}, _loadTimeCollector:function() {
this._addCurrentTimeToEntropy(2)
}, _addCurrentTimeToEntropy:function(estimatedEntropy) {
if(window && window.performance && typeof window.performance.now === "function") {
sjcl.random.addEntropy(window.performance.now(), estimatedEntropy, "loadtime")
}else {
sjcl.random.addEntropy((new Date).valueOf(), estimatedEntropy, "loadtime")
}
}, _accelerometerCollector:function(ev) {
var ac = ev.accelerationIncludingGravity.x || ev.accelerationIncludingGravity.y || ev.accelerationIncludingGravity.z;
if(window.orientation) {
var or = window.orientation;
if(typeof or === "number") {
sjcl.random.addEntropy(or, 1, "accelerometer")
}
}
if(ac) {
sjcl.random.addEntropy(ac, 2, "accelerometer")
}
this._addCurrentTimeToEntropy(0)
}, _fireEvent:function(name, arg) {
var j, cbs = sjcl.random._callbacks[name], cbsTemp = [];
for(j in cbs) {
if(cbs.hasOwnProperty(j)) {
cbsTemp.push(cbs[j])
}
}
for(j = 0;j < cbsTemp.length;j++) {
cbsTemp[j](arg)
}
}};
sjcl.random = new sjcl.prng(6);
(function() {
try {
var buf, crypt, getRandomValues, ab;
if(typeof module !== "undefined" && module.exports && (crypt = require("crypto")) && crypt.randomBytes) {
buf = crypt.randomBytes(1024 / 8);
buf = new Uint32Array((new Uint8Array(buf)).buffer);
sjcl.random.addEntropy(buf, 1024, "crypto.randomBytes")
}else {
if(window && Uint32Array) {
ab = new Uint32Array(32);
if(window.crypto && window.crypto.getRandomValues) {
window.crypto.getRandomValues(ab)
}else {
if(window.msCrypto && window.msCrypto.getRandomValues) {
window.msCrypto.getRandomValues(ab)
}else {
return
}
}
sjcl.random.addEntropy(ab, 1024, "crypto.getRandomValues")
}else {
}
}
}catch(e) {
console.log("There was an error collecting entropy from the browser:");
console.log(e)
}
})();
}).call(this);