(function () { /* Imports */ var Meteor = Package.meteor.Meteor; var _ = Package.underscore._; /* Package-scope variables */ var Random; (function () { ////////////////////////////////////////////////////////////////////////////////////// // // // packages/random/random.js // // // ////////////////////////////////////////////////////////////////////////////////////// // // We use cryptographically strong PRNGs (crypto.getRandomBytes() on the server, // 1 // window.crypto.getRandomValues() in the browser) when available. If these // 2 // PRNGs fail, we fall back to the Alea PRNG, which is not cryptographically // 3 // strong, and we seed it with various sources such as the date, Math.random, // 4 // and window size on the client. When using crypto.getRandomValues(), our // 5 // primitive is hexString(), from which we construct fraction(). When using // 6 // window.crypto.getRandomValues() or alea, the primitive is fraction and we use // 7 // that to construct hex string. // 8 // 9 if (Meteor.isServer) // 10 var nodeCrypto = Npm.require('crypto'); // 11 // 12 // see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript // 13 // for a full discussion and Alea implementation. // 14 var Alea = function () { // 15 function Mash() { // 16 var n = 0xefc8249d; // 17 // 18 var mash = function(data) { // 19 data = data.toString(); // 20 for (var i = 0; i < data.length; i++) { // 21 n += data.charCodeAt(i); // 22 var h = 0.02519603282416938 * n; // 23 n = h >>> 0; // 24 h -= n; // 25 h *= n; // 26 n = h >>> 0; // 27 h -= n; // 28 n += h * 0x100000000; // 2^32 // 29 } // 30 return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 // 31 }; // 32 // 33 mash.version = 'Mash 0.9'; // 34 return mash; // 35 } // 36 // 37 return (function (args) { // 38 var s0 = 0; // 39 var s1 = 0; // 40 var s2 = 0; // 41 var c = 1; // 42 // 43 if (args.length == 0) { // 44 args = [+new Date]; // 45 } // 46 var mash = Mash(); // 47 s0 = mash(' '); // 48 s1 = mash(' '); // 49 s2 = mash(' '); // 50 // 51 for (var i = 0; i < args.length; i++) { // 52 s0 -= mash(args[i]); // 53 if (s0 < 0) { // 54 s0 += 1; // 55 } // 56 s1 -= mash(args[i]); // 57 if (s1 < 0) { // 58 s1 += 1; // 59 } // 60 s2 -= mash(args[i]); // 61 if (s2 < 0) { // 62 s2 += 1; // 63 } // 64 } // 65 mash = null; // 66 // 67 var random = function() { // 68 var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32 // 69 s0 = s1; // 70 s1 = s2; // 71 return s2 = t - (c = t | 0); // 72 }; // 73 random.uint32 = function() { // 74 return random() * 0x100000000; // 2^32 // 75 }; // 76 random.fract53 = function() { // 77 return random() + // 78 (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 // 79 }; // 80 random.version = 'Alea 0.9'; // 81 random.args = args; // 82 return random; // 83 // 84 } (Array.prototype.slice.call(arguments))); // 85 }; // 86 // 87 var UNMISTAKABLE_CHARS = "23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz"; // 88 var BASE64_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + // 89 "0123456789-_"; // 90 // 91 // If seeds are provided, then the alea PRNG will be used, since cryptographic // 92 // PRNGs (Node crypto and window.crypto.getRandomValues) don't allow us to // 93 // specify seeds. The caller is responsible for making sure to provide a seed // 94 // for alea if a csprng is not available. // 95 var RandomGenerator = function (seedArray) { // 96 var self = this; // 97 if (seedArray !== undefined) // 98 self.alea = Alea.apply(null, seedArray); // 99 }; // 100 // 101 RandomGenerator.prototype.fraction = function () { // 102 var self = this; // 103 if (self.alea) { // 104 return self.alea(); // 105 } else if (nodeCrypto) { // 106 var numerator = parseInt(self.hexString(8), 16); // 107 return numerator * 2.3283064365386963e-10; // 2^-32 // 108 } else if (typeof window !== "undefined" && window.crypto && // 109 window.crypto.getRandomValues) { // 110 var array = new Uint32Array(1); // 111 window.crypto.getRandomValues(array); // 112 return array[0] * 2.3283064365386963e-10; // 2^-32 // 113 } else { // 114 throw new Error('No random generator available'); // 115 } // 116 }; // 117 // 118 RandomGenerator.prototype.hexString = function (digits) { // 119 var self = this; // 120 if (nodeCrypto && ! self.alea) { // 121 var numBytes = Math.ceil(digits / 2); // 122 var bytes; // 123 // Try to get cryptographically strong randomness. Fall back to // 124 // non-cryptographically strong if not available. // 125 try { // 126 bytes = nodeCrypto.randomBytes(numBytes); // 127 } catch (e) { // 128 // XXX should re-throw any error except insufficient entropy // 129 bytes = nodeCrypto.pseudoRandomBytes(numBytes); // 130 } // 131 var result = bytes.toString("hex"); // 132 // If the number of digits is odd, we'll have generated an extra 4 bits // 133 // of randomness, so we need to trim the last digit. // 134 return result.substring(0, digits); // 135 } else { // 136 var hexDigits = []; // 137 for (var i = 0; i < digits; ++i) { // 138 hexDigits.push(self.choice("0123456789abcdef")); // 139 } // 140 return hexDigits.join(''); // 141 } // 142 }; // 143 // 144 RandomGenerator.prototype._randomString = function (charsCount, // 145 alphabet) { // 146 var self = this; // 147 var digits = []; // 148 for (var i = 0; i < charsCount; i++) { // 149 digits[i] = self.choice(alphabet); // 150 } // 151 return digits.join(""); // 152 }; // 153 // 154 RandomGenerator.prototype.id = function (charsCount) { // 155 var self = this; // 156 // 17 characters is around 96 bits of entropy, which is the amount of // 157 // state in the Alea PRNG. // 158 if (charsCount === undefined) // 159 charsCount = 17; // 160 // 161 return self._randomString(charsCount, UNMISTAKABLE_CHARS); // 162 }; // 163 // 164 RandomGenerator.prototype.secret = function (charsCount) { // 165 var self = this; // 166 // Default to 256 bits of entropy, or 43 characters at 6 bits per // 167 // character. // 168 if (charsCount === undefined) // 169 charsCount = 43; // 170 return self._randomString(charsCount, BASE64_CHARS); // 171 }; // 172 // 173 RandomGenerator.prototype.choice = function (arrayOrString) { // 174 var index = Math.floor(this.fraction() * arrayOrString.length); // 175 if (typeof arrayOrString === "string") // 176 return arrayOrString.substr(index, 1); // 177 else // 178 return arrayOrString[index]; // 179 }; // 180 // 181 // instantiate RNG. Heuristically collect entropy from various sources when a // 182 // cryptographic PRNG isn't available. // 183 // 184 // client sources // 185 var height = (typeof window !== 'undefined' && window.innerHeight) || // 186 (typeof document !== 'undefined' // 187 && document.documentElement // 188 && document.documentElement.clientHeight) || // 189 (typeof document !== 'undefined' // 190 && document.body // 191 && document.body.clientHeight) || // 192 1; // 193 // 194 var width = (typeof window !== 'undefined' && window.innerWidth) || // 195 (typeof document !== 'undefined' // 196 && document.documentElement // 197 && document.documentElement.clientWidth) || // 198 (typeof document !== 'undefined' // 199 && document.body // 200 && document.body.clientWidth) || // 201 1; // 202 // 203 var agent = (typeof navigator !== 'undefined' && navigator.userAgent) || ""; // 204 // 205 if (nodeCrypto || // 206 (typeof window !== "undefined" && // 207 window.crypto && window.crypto.getRandomValues)) // 208 Random = new RandomGenerator(); // 209 else // 210 Random = new RandomGenerator([new Date(), height, width, agent, Math.random()]); // 211 // 212 Random.createWithSeeds = function () { // 213 if (arguments.length === 0) { // 214 throw new Error('No seeds were provided'); // 215 } // 216 return new RandomGenerator(arguments); // 217 }; // 218 // 219 ////////////////////////////////////////////////////////////////////////////////////// }).call(this); (function () { ////////////////////////////////////////////////////////////////////////////////////// // // // packages/random/deprecated.js // // // ////////////////////////////////////////////////////////////////////////////////////// // // Before this package existed, we used to use this Meteor.uuid() // 1 // implementing the RFC 4122 v4 UUID. It is no longer documented // 2 // and will go away. // 3 // XXX COMPAT WITH 0.5.6 // 4 Meteor.uuid = function () { // 5 var HEX_DIGITS = "0123456789abcdef"; // 6 var s = []; // 7 for (var i = 0; i < 36; i++) { // 8 s[i] = Random.choice(HEX_DIGITS); // 9 } // 10 s[14] = "4"; // 11 s[19] = HEX_DIGITS.substr((parseInt(s[19],16) & 0x3) | 0x8, 1); // 12 s[8] = s[13] = s[18] = s[23] = "-"; // 13 // 14 var uuid = s.join(""); // 15 return uuid; // 16 }; // 17 // 18 ////////////////////////////////////////////////////////////////////////////////////// }).call(this); /* Exports */ if (typeof Package === 'undefined') Package = {}; Package.random = { Random: Random }; })(); //# sourceMappingURL=random.js.map