Skip to content

Commit 2694389

Browse files
committed
Fix phantom snippet bug, add abuse detection, add prng availability for apis and snippets
1 parent 88ee967 commit 2694389

3 files changed

Lines changed: 177 additions & 57 deletions

File tree

api/0.1/Generator.js

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const mersenne = require('mersenne');
1+
const mersenne = new (require('mersenne-twister'));
22
const crypto = require('crypto');
33
const YAML = require('yamljs');
44
const js2xmlparser = require('js2xmlparser');
@@ -34,7 +34,7 @@ const Generator = function(name, options) {
3434
this.originalContext = [
3535
'random', 'list', 'hash', 'timestamp',
3636
'require', '_APIgetVars', '_APIresults',
37-
'_APIstack', '_APIerror', 'getVar', 'stacktrace'
37+
'_APIstack', '_APIerror', 'getVar', 'stacktrace', 'prng'
3838
];
3939

4040
this.reservedObjects = {
@@ -110,7 +110,7 @@ const Generator = function(name, options) {
110110
this.emit('listResponse', msg.data);
111111

112112
} else if (msg.mode === 'snippet') {
113-
this.emit('snippetResponse', msg.data);
113+
this.emit(`snippetResponse:${msg.data.signature}`, msg.data);
114114
}
115115

116116
} else if (msg.type === 'cmd') {
@@ -320,7 +320,7 @@ ${this.src}
320320
} else {
321321
this.sandBox = new vm.Script(`
322322
'use strict'
323-
var _APIgetVars = ${JSON.stringify(this.options)};
323+
var _APIgetVars = ${JSON.stringify(_.defaults(this.options, {seed: this.seed, numericSeed: this.numericSeed}))};
324324
var _APIresults = [];
325325
var _APIlogs = [];
326326
var _APIerror = null;
@@ -399,7 +399,7 @@ Generator.prototype.seedRNG = function() {
399399
let seed = this.page !== 1 ? this.seed + String(this.page) : this.seed;
400400

401401
this.numericSeed = parseInt(crypto.createHash('md5').update(seed).digest('hex').substring(0, 8), 16);
402-
mersenne.seed(this.numericSeed);
402+
mersenne.init_seed(this.numericSeed);
403403
};
404404

405405
Generator.prototype.defaultSeed = function() {
@@ -446,11 +446,6 @@ Generator.prototype.availableFuncs = function() {
446446
// Update local cache lastUsed date
447447
// Also update redis cache lastUsed date
448448
this.cache[obj].lastUsed = new Date().getTime();
449-
redis.exists("list:" + obj + ":contents", (err, result) => {
450-
if (result === 1) {
451-
redis.hmset("list:" + obj, 'lastUsed', new Date().getTime());
452-
}
453-
});
454449

455450
if (num !== undefined) {
456451
if (num < 1 || num > this.cache[obj].contents.length) {
@@ -568,7 +563,8 @@ Generator.prototype.availableFuncs = function() {
568563
},
569564
timestamp: () => funcs.timestamp(),
570565
stacktrace: () => funcs.stacktrace(),
571-
require: lib => funcs.require(lib)
566+
require: lib => funcs.require(lib),
567+
prng
572568
};
573569
};
574570

@@ -594,13 +590,7 @@ Generator.prototype.require = function(signature) {
594590
if (this.snippetCache[obj].published === 1 || this.snippetCache[obj].owner === this.user.id) {
595591

596592
// Update local snippet cache lastUsed date
597-
// Also update redis snippet cache lastUsed date
598593
this.snippetCache[obj].lastUsed = new Date().getTime();
599-
redis.exists(`snippet:${obj}:contents`, (err, result) => {
600-
if (result === 1) {
601-
redis.hmset(`snippet:${obj}`, 'lastUsed', new Date().getTime());
602-
}
603-
});
604594
return this.snippetCache[obj].snippet;
605595
} else {
606596
throw new Error(`Snippet signature ${obj} wasn't recognized`);
@@ -615,18 +605,21 @@ Generator.prototype.require = function(signature) {
615605
let done = false;
616606
let contents = null;
617607

618-
this.once('snippetResponse', result => {
619-
if (result === false) {
620-
throw new Error(`Snippet signature ${obj} wasn't recognized`);
608+
this.once(`snippetResponse:${signature}`, result => {
609+
// Generic unrecognized snippet
610+
if (result.status === false && result.msg === undefined) {
621611
done = true;
612+
throw new Error(`Snippet signature ${obj} wasn't recognized`);
622613

623-
} else if (result === "missing_version") {
614+
} else if (result.msg === "missing_version") {
615+
done = true;
624616
throw new Error(`Version number is missing`);
617+
618+
} else if (result.msg === "invalid_version") {
625619
done = true;
626-
} else if (result === "invalid_version") {
627620
throw new Error(`Invalid version number`);
628-
done = true;
629-
} else {
621+
622+
} else if (!done) {
630623
redis.GET(`snippet:${obj}:contents`, (err, snippet) => {
631624

632625
// Fetch metadata for snippet and store in local generator snippet cache
@@ -694,13 +687,13 @@ Generator.prototype.updateRequires = function() {
694687
// Don't let snippets include other snippets
695688
if (this.mode === 'snippet') resolve();
696689
else {
697-
let rawMatches = this.src.match(/require\(['"](?:((?:.*)\/(?:.*))|(~.*))['"]\)/g);
690+
let rawMatches = this.src.match(/require\((?:["'`]([A-z0-9]*\/[a-zA-Z0-9 _\-\.+\[\]\{\}\(\)]*(?:\/[0-9]*?)?|~.[a-zA-Z0-9 _\-\.+\[\]\{\}\(\)]*(?:\/[0-9]*?)?)["'`]\))/g);
698691
let index = 0;
699692

700693
try {
701694
// There are matches
702695
if (rawMatches !== null) {
703-
let reg = new RegExp(/require\(['"](?:((?:.*)\/(?:.*))|(~.*))['"]\)/g);
696+
let reg = new RegExp(/require\((?:["'`]([A-z0-9]*\/[a-zA-Z0-9 _\-\.+\[\]\{\}\(\)]*(?:\/[0-9]*?)?|~.[a-zA-Z0-9 _\-\.+\[\]\{\}\(\)]*(?:\/[0-9]*?)?)["'`]\))/g);
704697
let match = reg.exec(this.src);
705698
while (match !== null) {
706699
let result = (match[1] || match[2]).trim();
@@ -834,9 +827,13 @@ const randomItem = arr => {
834827
const range = (min, max) => {
835828
if (!Number.isInteger(min) || !Number.isInteger(max)) throw new TypeError('Non numeric arguments provided');
836829
if (max < min) throw new RangeError('min is greater than max');
837-
return min + mersenne.rand(max-min+1);
830+
return Math.floor(mersenne.random() * (max - min + 1)) + min;
838831
};
839832

833+
function prng() {
834+
return mersenne.random();
835+
}
836+
840837
const log = msg => {
841838
process.send({type: 'logger', content: String(msg)});
842839
}

0 commit comments

Comments
 (0)