├── .gitignore ├── images ├── favicon.ico ├── location.svg ├── cidr.svg ├── server.svg ├── mail.svg ├── port.svg ├── person.svg ├── linkedin.svg ├── info.svg ├── email.svg ├── organization.svg ├── subdomain.svg ├── phone.svg ├── network.svg ├── txt.svg ├── nameserver.svg └── position.svg ├── package.json ├── scripts ├── jquery.cookie.js ├── socket.io.js └── vivagraph.min.js ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | package-lock.json 3 | export* 4 | notes.txt 5 | *_*-*-*_*-*-*.js 6 | -------------------------------------------------------------------------------- /images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrismaddalena/scope_creep/master/images/favicon.ico -------------------------------------------------------------------------------- /images/location.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/cidr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scope_creep", 3 | "version": "1.0.0", 4 | "description": "Mass Target Enumeration", 5 | "main": "index.js", 6 | "dependencies": { 7 | "chrome-launcher": "^0.10.5", 8 | "chrome-remote-interface": "^0.27.0", 9 | "dateformat": "^3.0.3", 10 | "dns": "^0.2.2", 11 | "dns-axfr": "^0.2.3", 12 | "evilscan": "^1.7.1", 13 | "express": "^4.16.4", 14 | "netmask": "^1.0.6", 15 | "ping": "^0.2.2", 16 | "socket.io": "^2.2.0", 17 | "whois": "^2.9.0" 18 | }, 19 | "devDependencies": {}, 20 | "scripts": { 21 | "test": "echo \"Error: no test specified\" && exit 1" 22 | }, 23 | "author": "Forrest Kasler @fkasler", 24 | "license": "ISC" 25 | } 26 | -------------------------------------------------------------------------------- /images/server.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/mail.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/port.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/person.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/linkedin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/info.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/email.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/organization.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/subdomain.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/phone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/network.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/txt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/nameserver.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Cookie Plugin v1.4.1 3 | * https://github.com/carhartl/jquery-cookie 4 | * 5 | * Copyright 2013 Klaus Hartl 6 | * Released under the MIT license 7 | */ 8 | (function (factory) { 9 | if (typeof define === 'function' && define.amd) { 10 | // AMD 11 | define(['jquery'], factory); 12 | } else if (typeof exports === 'object') { 13 | // CommonJS 14 | factory(require('jquery')); 15 | } else { 16 | // Browser globals 17 | factory(jQuery); 18 | } 19 | }(function ($) { 20 | 21 | var pluses = /\+/g; 22 | 23 | function encode(s) { 24 | return config.raw ? s : encodeURIComponent(s); 25 | } 26 | 27 | function decode(s) { 28 | return config.raw ? s : decodeURIComponent(s); 29 | } 30 | 31 | function stringifyCookieValue(value) { 32 | return encode(config.json ? JSON.stringify(value) : String(value)); 33 | } 34 | 35 | function parseCookieValue(s) { 36 | if (s.indexOf('"') === 0) { 37 | // This is a quoted cookie as according to RFC2068, unescape... 38 | s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 39 | } 40 | 41 | try { 42 | // Replace server-side written pluses with spaces. 43 | // If we can't decode the cookie, ignore it, it's unusable. 44 | // If we can't parse the cookie, ignore it, it's unusable. 45 | s = decodeURIComponent(s.replace(pluses, ' ')); 46 | return config.json ? JSON.parse(s) : s; 47 | } catch(e) {} 48 | } 49 | 50 | function read(s, converter) { 51 | var value = config.raw ? s : parseCookieValue(s); 52 | return $.isFunction(converter) ? converter(value) : value; 53 | } 54 | 55 | var config = $.cookie = function (key, value, options) { 56 | 57 | // Write 58 | 59 | if (value !== undefined && !$.isFunction(value)) { 60 | options = $.extend({}, config.defaults, options); 61 | 62 | if (typeof options.expires === 'number') { 63 | var days = options.expires, t = options.expires = new Date(); 64 | t.setTime(+t + days * 864e+5); 65 | } 66 | 67 | return (document.cookie = [ 68 | encode(key), '=', stringifyCookieValue(value), 69 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 70 | options.path ? '; path=' + options.path : '', 71 | options.domain ? '; domain=' + options.domain : '', 72 | options.secure ? '; secure' : '' 73 | ].join('')); 74 | } 75 | 76 | // Read 77 | 78 | var result = key ? undefined : {}; 79 | 80 | // To prevent the for loop in the first place assign an empty array 81 | // in case there are no cookies at all. Also prevents odd result when 82 | // calling $.cookie(). 83 | var cookies = document.cookie ? document.cookie.split('; ') : []; 84 | 85 | for (var i = 0, l = cookies.length; i < l; i++) { 86 | var parts = cookies[i].split('='); 87 | var name = decode(parts.shift()); 88 | var cookie = parts.join('='); 89 | 90 | if (key && key === name) { 91 | // If second argument (value) is a function it's a converter... 92 | result = read(cookie, value); 93 | break; 94 | } 95 | 96 | // Prevent storing a cookie that we couldn't decode. 97 | if (!key && (cookie = read(cookie)) !== undefined) { 98 | result[name] = cookie; 99 | } 100 | } 101 | 102 | return result; 103 | }; 104 | 105 | config.defaults = {}; 106 | 107 | $.removeCookie = function (key, options) { 108 | if ($.cookie(key) === undefined) { 109 | return false; 110 | } 111 | 112 | // Must not alter options, thus extending a fresh object... 113 | $.cookie(key, '', $.extend({}, options, { expires: -1 })); 114 | return !$.cookie(key); 115 | }; 116 | 117 | })); 118 | -------------------------------------------------------------------------------- /images/position.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Scope Creep 2 | ===== 3 | A mass target enumeration tool 4 | 5 | Installation 6 | ===== 7 | This project is written in Node.js for its flexibility and non-blocking I/O. 8 | You will need to install Node and NPM (Node Package Manager) to run the project: [Node.js Download](https://nodejs.org/en/download/) 9 | 10 | Clone the repo and install the dependencies: 11 | ``` 12 | git clone https://github.com/fkasler/scope_creep.git 13 | cd scope_creep 14 | npm install 15 | ``` 16 | 17 | Getting Started 18 | ===== 19 | 20 | - start the server and navigate to [http://localhost:3000](http://localhost:3000) in Chrome to get started: 21 | 22 | ``` 23 | node index.js 24 | ``` 25 | 26 | Usage/Modules 27 | ===== 28 | 29 | - Scope Creep was built on Chrome. I hear the key bindings don't work on Firefox. You may experience issues with browsers other than Chrome. You've been warned. 30 | - By default, "Safety" Mode is turned on to prevent the accidental running of mass queries against CIDR ranges and port scanning or ping sweeping anything. You can turn it off if you know what you're doing. 31 | - You can trigger modules by clicking on them in the help menu. However, it's faster and more fun to learn the key bindings. 32 | - You can select multiple nodes by either clicking on their row in the stats list or by using the node search. 33 | - Node search/find(f) supports JavaScript regular expressions (e.g. 'domain.com' will select the domain and its subdomains but '^domain.com' will only select the domain and no subs). [regex reference](https://eloquentjavascript.net/09_regexp.html) 34 | - Add values for [shodan](https://www.shodan.io/) api key, [whoxy](https://www.whoxy.com/reverse-whois/) api key, [li_at](https://www.linkedin.com/) cookie, and [hunter.io](https://hunter.io/users/sign_up) api key to use those features. The value is saved in a cookie when you click out of the input so that they persist between page reloads. 35 | - The li_at cookie is LinkedIn's session cookie and required to mine LinkedIn with Scope Creep. I recommend [editthiscookie](http://www.editthiscookie.com/) extension for Chrome to get your current session cookie. 36 | 37 | ### Add Node(a): 38 | Press 'a' to select and clear the "Add Node(a)" input box. Hit enter to add the node to the graph. 39 | 40 | ### Help(h): 41 | Toggles the help window in and out of the screen. 42 | 43 | ### Hide Stats(H): 44 | Toggles the Stats list in and out of the screen. 45 | 46 | ### Connect Nodes(c): 47 | Select a node, hit 'c', and select another node to connect them. Press 'c' again to cancel if you accidentally hit it. 48 | 49 | ### Copy Nodes to Clipboard(y): 50 | Yank the contents of the selected nodes to your clipboard. Useful for fast export of data like pulling an addresses.txt for phishing. 51 | 52 | ### Export Nodes(e): 53 | Export the contents of the selected nodes to a file name of your choosing. If you include the word 'finding' in the file name, the selected nodes will be exported in the format that Engage expects for finding imports. This is great for turning open port nodes into a finding like "Internet accessible authentication prompts". 54 | 55 | ### Export Graph(E): 56 | Export the entire graph as a JSON object to a file. Useful for saving progress or sharing graphs with others. 57 | 58 | ### Select Nodes based on # of connections (0-9): 59 | Select nodes based on how many nodes are connected to them. Good for some mass operations. 60 | 61 | ### Open Scope File(o): 62 | Open a scope file with domains, subdomains, IPs, and CIDR ranges in it. This module needs you to select a parent node for the entries to attach to so they don't go flying in all directions. Supports wildcard imports (e.g. scope_file\* would import scope_file1.txt, scope_file2.txt, and scope_file_more_entries.txt) 63 | 64 | ### Open Graph(O): 65 | Open a saved graph. This also supports wildcards. Wildcards are a great way to combine graphs into a single scope graph. 66 | 67 | ### Delete Nodes(d): 68 | Deletes all selected nodes. 69 | 70 | ### Delete Unselected Nodes(D): 71 | Deletes everything except the currently selected nodes. Great to use in combo with (f). 72 | 73 | ### Undo Deleted Nodes(u): 74 | You can bring back connections to the selected nodes by using the undo feature. Useful for pairing down and building back graphs based on search criteria. 75 | 76 | ### Change Node Type(U): 77 | Lets you update the node type for a single selected node. 78 | 79 | ### Whois Lookup(w): 80 | Performs a Whois lookup on the selected IP node. 81 | 82 | ### Whoxy Reverse Whois Lookup(W): 83 | Searches the Whoxy API for related domains based on Organization name, technical contact email, or keyword search. To search domain nodes like "example.com", use option (c) when prompted. 84 | 85 | ### MX Query(m): 86 | Performs a DNS MX lookup on the selected nodes. Useful for quickly getting a list of mail servers. 87 | 88 | ### Reverse DNS Lookup(r): 89 | Performs a DNS reverse lookup on the selected nodes. If a CIDR range is selected, it will do a reverse lookup for all possible IPs in the range. Great for quickly finding hosts on a network. 90 | 91 | ### Mass Reverse DNS Lookup(R): 92 | Performs a DNS reverse lookup on ALL IP nodes in the graph. 93 | 94 | ### TXT Records(t): 95 | Performs a DNS TXT lookup on the selected nodes. This module also tries to parse out CIDR ranges, hosts, and domains from SPF records. 96 | 97 | ### Mass TXT Records(T): 98 | Same as (t), but against all domain nodes. This is great for enumerating runaway SPF records quickly. 99 | 100 | ### Name Servers(n): 101 | Performs a DNS NS lookup on the selected nodes. 102 | 103 | ### Generate Emails(g): 104 | Generates emails from all person nodes in the graph. If you leave the domain blank, it will not include the @ symbol so this is also good for generating usernames. 105 | 106 | ### Generate Phishmonger Target CSV(G): 107 | Exports a CSV to the clipboard that contains a social engineering targets list. Useful in combination with the LinkedIn scraper and Hunter.io results. 108 | 109 | ### View Website in New Tab(v): 110 | Opens a new Chrome tab for the selected nodes. Great for viewing web portals. 111 | 112 | ### Mass View Website in New Tab(V): 113 | Opens a new Chrome tab for every subdomain node in the graph. Great for a quick look at subs to see what they're hosting. 114 | 115 | ### ASN search(A): 116 | Searches for IP ranges that belong to an organization by querying the [http://asnlookup.com/](http://asnlookup.com/) API. The public repo only supports forward lookups based on organization name. I will link to resources on setting up a better API sometime in the future. 117 | 118 | ### DoxNS Lookup(x): 119 | Proprietary DB for now. I will link to more details sometime in the future. 120 | 121 | ### Reverse DoxNS Lookup(X): 122 | Proprietary DB for now. I will link to more details sometime in the future. 123 | 124 | ### IP DNS Query/Ping Sweep CIDR(i): 125 | Performs a DNS lookup for the selected nodes. If a CIDR range is selected, this module performs an ICMP ping sweep on the range equivalent to 'nmap -sn -PE 192.168.0.0/24'. Ping sweeps are not allowed in safety mode. 126 | 127 | ### Mass IP DNS Query/Ping Sweep CIDR(I): 128 | Performs a DNS lookup for ALL subdomain and CIDR nodes. CIDR is not scanned if safty mode is turned on. If a CIDR range is selected, this module performs an ICMP ping sweep on the range equivalent to 'nmap -sn -PE 192.168.0.0/24' 129 | 130 | ### Subdomain Lookup (limit 100 queries/day)(s): 131 | Performs a subdomain search using alienvault's free API and hackertarget.com's free API. Limited to 100 queries per day. That's a lot of free data. 132 | 133 | ### CRT.SH Subdomain Lookup (unknown limit)(S): 134 | Performs a subdomain search using crt.sh. This can find some cool stuff when it works. Sometimes you can even find internal domain names if the org uses the same cert for internal and external use. 135 | 136 | ### Query Shodan (rate limit 1 per second)(q): 137 | Performs a Shodan query on the selected node. One node at a time limit because Shodan only allows a query per second or so and Node.js would try to do them all at once. 138 | 139 | ### LinkedIn Search (deactivation risk, DO NOT THREAD!)(l): 140 | Mines LinkedIn for employee names and positions using a headless Chrome browser that mimics a human scrolling through pages. You need to make sure you have a current li_at cookie set first. You also need to select a node for the results to attach to. Go search for your target org in LinkedIn and get the OrgID and the number of results pages you want to mine. The OrgId for "https://www.linkedin.com/search/results/people/?facetCurrentCompany=11452158" would be 11452158. Sometimes you'll see multiple OrgIds. In those cases, just mine them one after the other. DO NOT TRY TO SPEED UP OR THREAD THIS MODULE!!!!!!!!! YOU CAN GET BUSTED AND ACCOUNT SUSPENDED!!!! It is slow for a reason. 141 | 142 | ### Email Search (limit 100 queries/month)(M): 143 | Performs a Hunter.io email search and a SKS-KeyServer email search. Go get a free Hunter.io account and grab the api key. The free API allows 100 results per month but 10 emails is equal to one result. The max emails per query is 100 so that will burn 10 "queries" if you get 100 results. In effect, you are limited to an absolute maximum of 1,000 emails per month with the free account. I recommend exporting and looking through the email sources that it returns. They can point to directories and places to get other emails. They can also give you an idea of other organizations that your target works with. Great for blackbox testing. 144 | 145 | ### Location Search (general rate limit)(L): 146 | Tries to find the Lat/Long location associated with an IP. You can view location nodes in Google maps by using the "View Website in New Tab(v)" module. 147 | 148 | ### DNS Zone Transfer(Z): 149 | Performs a Zone Transfer against the selected domain/network nodes. This will run a axfr query against ALL name servers for the domain so it can be noisy if successful. 150 | 151 | ### Bruteforce Subdomains (interacts with client servers)(b): 152 | Performs DNS subdomain bruteforcing using the alexa list from fuzzdb. This can take a while but generally goes fast on private networks. Great for quickly finding hosts with DNS on internal assessments/SE. 153 | 154 | ### Port Scan/Port Scan ALL IPs(p): 155 | Performs a TCP port scan on the selected nodes. Supports individual CIDR ranges. You specify the ports/ranges in the ports input field. You can mix ports and ranges if you'd like (e.g. 21-15,80,443,8080,4444-555). Not allowed in safety mode. 156 | 157 | ### Mass Port Scan/Port Scan ALL IPs(P): 158 | Performs a TCP port scan on ALL IP nodes. You specify the ports/ranges in the ports input field. You can mix ports and ranges if you'd like (e.g. 21-15,80,443,8080,4444-555). Not allowed in safety mode. 159 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | fs = require('fs'); 2 | glob = require("glob") 3 | dateFormat = require('dateformat'); 4 | var app = require('express')(); 5 | var http = require('http').Server(app); 6 | http_resolver = require('http') 7 | https_resolver = require('https') 8 | var io = require('socket.io')(http); 9 | var dns = require('dns'); 10 | var axfr = require('dns-axfr'); 11 | //CIDR parser 12 | netmask = require('netmask').Netmask 13 | //headless chrome stuff 14 | const chromeLauncher = require('chrome-launcher'); 15 | const CDP = require('chrome-remote-interface'); 16 | //port scanner 17 | evilscan = require('evilscan'); 18 | //ping sweeps 19 | var ping = require('ping'); 20 | 21 | app.get('/', function(req, res){ 22 | res.sendFile(__dirname + '/scopecreep.html'); 23 | }); 24 | 25 | app.get('/favicon.ico', function(req, res){ 26 | res.sendFile(__dirname + '/images/favicon.ico'); 27 | }); 28 | 29 | app.get('/scripts/jquery.min.js', function(req, res){ 30 | res.sendFile(__dirname + '/scripts/jquery.min.js'); 31 | }); 32 | 33 | app.get('/scripts/jquery.cookie.js', function(req, res){ 34 | res.sendFile(__dirname + '/scripts/jquery.cookie.js'); 35 | }); 36 | 37 | app.get('/scripts/vivagraph.min.js', function(req, res){ 38 | res.sendFile(__dirname + '/scripts/vivagraph.min.js'); 39 | }); 40 | 41 | app.get('/scripts/socket.io.js', function(req, res){ 42 | res.sendFile(__dirname + '/scripts/socket.io.js'); 43 | }); 44 | 45 | app.get('/images/network', function(req, res){ 46 | res.sendFile(__dirname + '/images/network.svg'); 47 | }); 48 | 49 | app.get('/images/mail', function(req, res){ 50 | res.sendFile(__dirname + '/images/mail.svg'); 51 | }); 52 | 53 | app.get('/images/server', function(req, res){ 54 | res.sendFile(__dirname + '/images/server.svg'); 55 | }); 56 | 57 | app.get('/images/subdomain', function(req, res){ 58 | res.sendFile(__dirname + '/images/subdomain.svg'); 59 | }); 60 | 61 | app.get('/images/txt', function(req, res){ 62 | res.sendFile(__dirname + '/images/txt.svg'); 63 | }); 64 | 65 | app.get('/images/organization', function(req, res){ 66 | res.sendFile(__dirname + '/images/organization.svg'); 67 | }); 68 | 69 | app.get('/images/cidr', function(req, res){ 70 | res.sendFile(__dirname + '/images/cidr.svg'); 71 | }); 72 | 73 | app.get('/images/person', function(req, res){ 74 | res.sendFile(__dirname + '/images/person.svg'); 75 | }); 76 | 77 | app.get('/images/linkedin', function(req, res){ 78 | res.sendFile(__dirname + '/images/linkedin.svg'); 79 | }); 80 | 81 | app.get('/images/position', function(req, res){ 82 | res.sendFile(__dirname + '/images/position.svg'); 83 | }); 84 | 85 | app.get('/images/nameserver', function(req, res){ 86 | res.sendFile(__dirname + '/images/nameserver.svg'); 87 | }); 88 | 89 | app.get('/images/port', function(req, res){ 90 | res.sendFile(__dirname + '/images/port.svg'); 91 | }); 92 | 93 | app.get('/images/email', function(req, res){ 94 | res.sendFile(__dirname + '/images/email.svg'); 95 | }); 96 | 97 | app.get('/images/info', function(req, res){ 98 | res.sendFile(__dirname + '/images/info.svg'); 99 | }); 100 | 101 | app.get('/images/location', function(req, res){ 102 | res.sendFile(__dirname + '/images/location.svg'); 103 | }); 104 | 105 | app.get('/images/phone', function(req, res){ 106 | res.sendFile(__dirname + '/images/phone.svg'); 107 | }); 108 | 109 | io.on('connection', function(socket){ 110 | socket.on('whois_lookup', function(query){ 111 | var whois = require('whois') 112 | whois.lookup(query, function(err, data) { 113 | var searches = [ 114 | {"search_string": "CIDR:", "node_type": "cidr"}, 115 | {"search_string": "NetRange:", "node_type": "info"}, 116 | {"search_string": "Organization:", "node_type": "organization"}, 117 | {"search_string": "OrgTechEmail:", "node_type": "email"}, 118 | {"search_string": "OrgName:", "node_type": "organization"} 119 | ] 120 | for(i=0; i < searches.length; i++){ 121 | myRegexp = new RegExp(`^${searches[i].search_string}.+$`,"gm"); 122 | do { 123 | match = myRegexp.exec(data); 124 | if (match) { 125 | new_node = JSON.parse('{"id": "'+ match[0].replace(/ /g,'').split(':')[1] + '", "parent": "' + query + '", "node_type": "' + searches[i].node_type +'"}') 126 | io.emit('add_node', new_node) 127 | } 128 | } while (match); 129 | } 130 | }) 131 | }); 132 | 133 | socket.on('whoxy_api_check', function(query_object){ 134 | 135 | api_call = 'https://api.whoxy.com/?key=' + query_object + '&account=balance' 136 | 137 | https_resolver.get(api_call, (resp) => { 138 | let data = ''; 139 | 140 | resp.on('data', (chunk) => { 141 | data += chunk; 142 | }); 143 | 144 | resp.on('end', () => { 145 | try{ 146 | results = JSON.parse(data) 147 | io.emit('server_message', "Available Balance: " + results.reverse_whois_balance) 148 | }catch (err){ 149 | io.emit('server_message', "There is a problem with your API key") 150 | } 151 | }); 152 | }).on("error", (err) => { 153 | console.log("Error: " + err.message); 154 | }); 155 | }); 156 | 157 | socket.on('whoxy_search', function(query_object){ 158 | 159 | if(query_object.search_method == 'email'){ 160 | api_call = 'https://api.whoxy.com/?key=' + query_object.whoxy_api_key + '&reverse=whois&email=' + query_object.node_id + '&page=' + query_object.page_number 161 | }else if(query_object.search_method == 'keyword'){ 162 | api_call = 'https://api.whoxy.com/?key=' + query_object.whoxy_api_key + '&reverse=whois&keyword=' + query_object.node_id + '&page=' + query_object.page_number 163 | }else{ 164 | api_call = 'https://api.whoxy.com/?key=' + query_object.whoxy_api_key + '&reverse=whois&company=' + query_object.node_id + '&page=' + query_object.page_number 165 | } 166 | 167 | https_resolver.get(api_call, (resp) => { 168 | let data = ''; 169 | 170 | resp.on('data', (chunk) => { 171 | data += chunk; 172 | }); 173 | 174 | resp.on('end', () => { 175 | results = JSON.parse(data) 176 | if(results.total_pages > 1){ 177 | io.emit('server_message', "Total Pages: " + results.total_pages) 178 | } 179 | for(i=0; i < results.search_result.length; i++){ 180 | record = results.search_result[i] 181 | new_node = JSON.parse('{"id": "'+ record.domain_name + '", "parent": "' + query_object.node_id + '", "node_type": "network"}') 182 | io.emit('add_node', new_node) 183 | if(record.registrant_contact.company_name){ 184 | new_node = JSON.parse('{"id": "'+ record.registrant_contact.company_name + '", "parent": "' + record.domain_name + '", "node_type": "organization"}') 185 | io.emit('add_node', new_node) 186 | } 187 | if(record.administrative_contact.company_name){ 188 | new_node = JSON.parse('{"id": "'+ record.registrant_contact.company_name + '", "parent": "' + record.domain_name + '", "node_type": "organization"}') 189 | io.emit('add_node', new_node) 190 | } 191 | if(record.technical_contact.company_name){ 192 | new_node = JSON.parse('{"id": "'+ record.registrant_contact.company_name + '", "parent": "' + record.domain_name + '", "node_type": "organization"}') 193 | io.emit('add_node', new_node) 194 | } 195 | if(record.registrant_contact.email_address){ 196 | new_node = JSON.parse('{"id": "'+ record.registrant_contact.email_address + '", "parent": "' + record.domain_name + '", "node_type": "email"}') 197 | io.emit('add_node', new_node) 198 | if(record.registrant_contact.phone_number){ 199 | new_node = JSON.parse('{"id": "'+ record.registrant_contact.phone_number + '", "parent": "' + record.registrant_contact.email_address + '", "node_type": "phone"}') 200 | io.emit('add_node', new_node) 201 | } 202 | } 203 | if(record.administrative_contact.email_address){ 204 | new_node = JSON.parse('{"id": "'+ record.administrative_contact.email_address + '", "parent": "' + record.domain_name + '", "node_type": "email"}') 205 | io.emit('add_node', new_node) 206 | if(record.administrative_contact.phone_number){ 207 | new_node = JSON.parse('{"id": "'+ record.administrative_contact.phone_number + '", "parent": "' + record.administrative_contact.email_address + '", "node_type": "phone"}') 208 | io.emit('add_node', new_node) 209 | } 210 | } 211 | if(record.technical_contact.email_address){ 212 | new_node = JSON.parse('{"id": "'+ record.technical_contact.email_address + '", "parent": "' + record.domain_name + '", "node_type": "email"}') 213 | io.emit('add_node', new_node) 214 | if(record.technical_contact.phone_number){ 215 | new_node = JSON.parse('{"id": "'+ record.technical_contact.phone_number + '", "parent": "' + record.technical_contact.email_address + '", "node_type": "phone"}') 216 | io.emit('add_node', new_node) 217 | } 218 | } 219 | } 220 | }); 221 | }).on("error", (err) => { 222 | console.log("Error: " + err.message); 223 | }); 224 | }); 225 | 226 | 227 | socket.on('mx_query', function(query){ 228 | dns.resolveMx(query, function(err, addresses){ 229 | for (server in addresses){ 230 | new_node = JSON.parse('{"id": "'+ addresses[server].exchange + '", "parent": "' + query + '", "node_type": "mail"}') 231 | io.emit('add_node', new_node) 232 | } 233 | }) 234 | }); 235 | 236 | socket.on('reverse_lookup', function(query_object){ 237 | //run a reverse lookup on everything in the range if it's a CIDR subnet 238 | if(query_object.node_type == "cidr"){ 239 | var block = new netmask(query_object.node_id); 240 | block.forEach(function(ip){ 241 | dns.reverse(ip.toString(), function(err, addresses){ 242 | for (server in addresses){ 243 | if(addresses[server].split('.').length == 2){ 244 | new_node = JSON.parse('{"id": "'+ addresses[server] + '", "parent": "' + query_object.node_id + '", "node_type": "network"}') 245 | }else{ 246 | new_node = JSON.parse('{"id": "'+ addresses[server] + '", "parent": "' + query_object.node_id + '", "node_type": "subdomain"}') 247 | } 248 | io.emit('add_node', new_node) 249 | } 250 | }) 251 | }); 252 | //otherwise treat like a single query 253 | }else{ 254 | dns.reverse(query_object.node_id, function(err, addresses){ 255 | for (server in addresses){ 256 | if(addresses[server].split('.').length == 2){ 257 | new_node = JSON.parse('{"id": "'+ addresses[server] + '", "parent": "' + query_object.node_id + '", "node_type": "network"}') 258 | }else{ 259 | new_node = JSON.parse('{"id": "'+ addresses[server] + '", "parent": "' + query_object.node_id + '", "node_type": "subdomain"}') 260 | } 261 | io.emit('add_node', new_node) 262 | } 263 | }) 264 | } 265 | }); 266 | 267 | socket.on('txt_records', function(query){ 268 | dns.resolveTxt(query, function(err, records){ 269 | for (entry in records){ 270 | new_node = JSON.parse('{"id": "'+ records[entry][0] + '", "parent": "' + query + '", "node_type": "txt"}') 271 | io.emit('add_node', new_node) 272 | if(records[entry][0].indexOf('v=spf') !== -1){ 273 | myRegexp = /ip4:(\d+\.\d+\.\d+\.\d+([^\s]+))/g 274 | do { 275 | match = myRegexp.exec(records[entry]); 276 | if (match) { 277 | if(match[1].indexOf('/') !== -1){ 278 | new_node = JSON.parse('{"id": "'+ match[1] + '", "parent": "' + records[entry][0] + '", "node_type": "cidr"}') 279 | }else if(match[1].indexOf('-') !== -1){ 280 | new_node = JSON.parse('{"id": "Net Range: '+ match[1] + '", "parent": "' + records[entry][0] + '", "node_type": "info"}') 281 | }else{ 282 | new_node = JSON.parse('{"id": "'+ match[1] + '", "parent": "' + records[entry][0] + '", "node_type": "server"}') 283 | } 284 | io.emit('add_node', new_node) 285 | } 286 | } while (match); 287 | myRegexp = /include:([^\s]+)/g 288 | do { 289 | match = myRegexp.exec(records[entry]); 290 | if (match) { 291 | new_node = JSON.parse('{"id": "'+ match[1] + '", "parent": "' + records[entry][0] + '", "node_type": "network"}') 292 | io.emit('add_node', new_node) 293 | } 294 | } while (match); 295 | myRegexp = /a:([^\s]+)/g 296 | do { 297 | match = myRegexp.exec(records[entry]); 298 | if (match) { 299 | new_node = JSON.parse('{"id": "'+ match[1] + '", "parent": "' + records[entry][0] + '", "node_type": "subdomain"}') 300 | io.emit('add_node', new_node) 301 | } 302 | } while (match); 303 | } 304 | } 305 | }) 306 | }); 307 | 308 | socket.on('nameservers', function(query){ 309 | dns.resolveNs(query, function(err, records){ 310 | for (entry in records){ 311 | new_node = JSON.parse('{"id": "'+ records[entry] + '", "parent": "' + query + '", "node_type": "nameserver"}') 312 | io.emit('add_node', new_node) 313 | } 314 | }) 315 | }); 316 | 317 | socket.on('ip_lookup', function(query_object){ 318 | //run a ping sweep if this is a CIDR range 319 | if(query_object.node_type == "cidr"){ 320 | var block = new netmask(query_object.node_id); 321 | block.forEach(function(host){ 322 | ping.sys.probe(host, function(isAlive){ 323 | if(isAlive){ 324 | new_node = JSON.parse('{"id": "'+ host + '", "parent": "' + query_object.node_id + '", "node_type": "server"}') 325 | io.emit('add_node', new_node) 326 | } 327 | }); 328 | 329 | }); 330 | }else{ 331 | dns.resolve(query_object.node_id.toString(), function(err, addresses){ 332 | for (server in addresses){ 333 | new_node = JSON.parse('{"id": "'+ addresses[server] + '", "parent": "' + query_object.node_id + '", "node_type": "server"}') 334 | io.emit('add_node', new_node) 335 | } 336 | }) 337 | } 338 | }); 339 | 340 | socket.on('export_graph', function(query_object){ 341 | if(query_object.file_name == ""){ 342 | query_object.file_name = "export" 343 | } 344 | if(query_object.export_type == 'list'){ 345 | fs.writeFile("./" + query_object.file_name, query_object.export_list, function(err) { 346 | if(err) { 347 | console.log(err); 348 | } 349 | io.emit('server_message', "File Exported: ./" + query_object.file_name) 350 | }); 351 | }else{ 352 | fs.writeFile("./" + query_object.file_name + "_" + dateFormat(new Date(), "yyyy-mm-dd_HH-MM-ss")+".js", JSON.stringify(query_object.graph_object,false, 2), function(err) { 353 | if(err) { 354 | console.log(err); 355 | } 356 | io.emit('server_message', "File Exported: ./" + query_object.file_name + "_" +dateFormat(new Date(), "yyyy-mm-dd_HH-MM-ss")+".js") 357 | }); 358 | } 359 | }); 360 | 361 | socket.on('subdomain_lookup', function(query){ 362 | http_resolver.get('http://api.hackertarget.com/hostsearch/?q=' + query, (resp) => { 363 | let data = ''; 364 | 365 | resp.on('data', (chunk) => { 366 | data += chunk; 367 | }); 368 | 369 | resp.on('end', () => { 370 | lines = data.split('\n') 371 | for(line in lines){ 372 | subdomain = lines[line].split(',') 373 | subdomain_name = subdomain[0] 374 | subdomain_ip = subdomain[1] 375 | if(subdomain_name.split('.').length == 2){ 376 | new_node = JSON.parse('{"id": "'+ subdomain_name + '", "parent": "' + query + '", "node_type": "network"}') 377 | }else{ 378 | new_node = JSON.parse('{"id": "'+ subdomain_name + '", "parent": "' + query + '", "node_type": "subdomain"}') 379 | } 380 | io.emit('add_node', new_node) 381 | new_node = JSON.parse('{"id": "'+ subdomain_ip + '", "parent": "' + subdomain_name + '", "node_type": "server"}') 382 | io.emit('add_node', new_node) 383 | } 384 | }); 385 | 386 | }).on("error", (err) => { 387 | console.log("Error: " + err.message); 388 | }); 389 | 390 | https_resolver.get('https://otx.alienvault.com/api/v1/indicators/domain/' + query + '/passive_dns', (resp) => { 391 | let data = ''; 392 | 393 | resp.on('data', (chunk) => { 394 | data += chunk; 395 | }); 396 | 397 | resp.on('end', () => { 398 | results = JSON.parse(data).passive_dns 399 | for(i=0;i { 410 | console.log("Error: " + err.message); 411 | }); 412 | }); 413 | 414 | socket.on('asn_search', function(query_object){ 415 | var api_call = 'http://asnlookup.com/api/lookup?org=' + encodeURIComponent(query_object.node_id) 416 | // if(query_object.node_type == "server"){ 417 | // api_call = 'http://10.0.50.105:10120/ip_to_asn?q=' + query_object.node_id 418 | // }else if(query_object.node_type == "info"){ 419 | // api_call = 'http://10.0.50.105:10120/asn_to_org?q=' + query_object.node_id.replace(/ASN:/,'') 420 | // }else{ 421 | // api_call = 'http://10.0.50.105:10120/org_to_asn?q=' + query_object.node_id 422 | // } 423 | http_resolver.get(api_call, (resp) => { 424 | let data = ''; 425 | 426 | resp.on('data', (chunk) => { 427 | data += chunk; 428 | }); 429 | 430 | resp.on('end', () => { 431 | results = JSON.parse(data) 432 | for(result in results){ 433 | // new_node = JSON.parse('{"id": "'+ results[result].org + '", "parent": "' + query_object.node_id + '", "node_type": "organization"}') 434 | // io.emit('add_node', new_node) 435 | // new_node = JSON.parse('{"id": "ASN:'+ results[result].asn + '", "parent": "' + results[result].org + '", "node_type": "info"}') 436 | // io.emit('add_node', new_node) 437 | new_node = JSON.parse('{"id": "' + results[result] + '", "parent": "' + query_object.node_id + '", "node_type": "cidr"}') 438 | io.emit('add_node', new_node) 439 | // new_node = JSON.parse('{"id": "Country:'+ results[result].country + '", "parent": "' + results[result].org + '", "node_type": "info"}') 440 | // io.emit('add_node', new_node) 441 | } 442 | }); 443 | 444 | }).on("error", (err) => { 445 | console.log("Error: " + err.message); 446 | }); 447 | }); 448 | 449 | socket.on('dox_ns', function(query){ 450 | http_resolver.get('http://10.0.50.105:10120/search?q=' + query, (resp) => { 451 | let data = ''; 452 | 453 | resp.on('data', (chunk) => { 454 | data += chunk; 455 | }); 456 | 457 | resp.on('end', () => { 458 | results = JSON.parse(data) 459 | for(result in results){ 460 | subdomain_name = results[result].name 461 | subdomain_ip = results[result].value 462 | if(subdomain_name.split('.').length == 2){ 463 | new_node = JSON.parse('{"id": "'+ subdomain_name + '", "parent": "' + query + '", "node_type": "network"}') 464 | }else{ 465 | new_node = JSON.parse('{"id": "'+ subdomain_name + '", "parent": "' + query + '", "node_type": "subdomain"}') 466 | } 467 | io.emit('add_node', new_node) 468 | 469 | if(results[result].type == 'cname'){ 470 | if(subdomain_name.split('.').length == 2){ 471 | new_node = JSON.parse('{"id": "'+ subdomain_ip + '", "parent": "' + subdomain_name + '", "node_type": "network"}') 472 | }else{ 473 | new_node = JSON.parse('{"id": "'+ subdomain_ip + '", "parent": "' + subdomain_name + '", "node_type": "subdomain"}') 474 | } 475 | }else{ 476 | new_node = JSON.parse('{"id": "'+ subdomain_ip + '", "parent": "' + subdomain_name + '", "node_type": "server"}') 477 | } 478 | io.emit('add_node', new_node) 479 | } 480 | }); 481 | 482 | }).on("error", (err) => { 483 | console.log("Error: " + err.message); 484 | }); 485 | }); 486 | 487 | socket.on('reverse_dox_ns', function(query){ 488 | http_resolver.get('http://10.0.50.105:10120/reverse_search?q=' + query, (resp) => { 489 | let data = ''; 490 | 491 | resp.on('data', (chunk) => { 492 | data += chunk; 493 | }); 494 | 495 | resp.on('end', () => { 496 | results = JSON.parse(data) 497 | for(result in results){ 498 | subdomain_name = results[result].name 499 | subdomain_ip = results[result].value 500 | if(subdomain_name.split('.').length == 2){ 501 | new_node = JSON.parse('{"id": "'+ subdomain_name + '", "parent": "' + query + '", "node_type": "network"}') 502 | }else{ 503 | new_node = JSON.parse('{"id": "'+ subdomain_name + '", "parent": "' + query + '", "node_type": "subdomain"}') 504 | } 505 | io.emit('add_node', new_node) 506 | } 507 | }); 508 | 509 | }).on("error", (err) => { 510 | console.log("Error: " + err.message); 511 | }); 512 | }); 513 | 514 | socket.on('crtsh_lookup', function(query){ 515 | https_resolver.get('https://crt.sh/?q=%25.' + query, (resp) => { 516 | let data = ''; 517 | 518 | resp.on('data', (chunk) => { 519 | data += chunk; 520 | }); 521 | 522 | resp.on('end', () => { 523 | myRegexp = new RegExp(`([^>\ =]+\.${query})`, 'g') 524 | do { 525 | match = myRegexp.exec(data); 526 | if (match) { 527 | if(match[1].split('.').length > 2){ 528 | new_node = JSON.parse('{"id": "'+ match[1].toLowerCase() + '", "parent": "' + query + '", "node_type": "subdomain"}') 529 | io.emit('add_node', new_node) 530 | }else{ 531 | new_node = JSON.parse('{"id": "'+ match[1].toLowerCase() + '", "parent": "' + query + '", "node_type": "network"}') 532 | io.emit('add_node', new_node) 533 | } 534 | } 535 | } while (match); 536 | }); 537 | 538 | }).on("error", (err) => { 539 | console.log("Error: " + err.message); 540 | }); 541 | }); 542 | 543 | socket.on('bruteforce_subdomains', function(query){ 544 | //console.log(dateFormat("isoDateTime") + " starting bruteforce"); 545 | dns.resolve('notavalidsubdomain.' + query, function(err, wildcardIP){ 546 | if(wildcardIP){ 547 | new_node = JSON.parse('{"id": "*.' + query + '", "parent": "' + query + '", "node_type": "subdomain"}') 548 | io.emit('add_node', new_node) 549 | new_node = JSON.parse('{"id": "'+ wildcardIP[0] + '", "parent": "*.' + query + '", "node_type": "server"}') 550 | io.emit('add_node', new_node) 551 | }else{ 552 | wildcardIP = ['1.1.1.1'] 553 | } 554 | var lineReader = require('readline').createInterface({ 555 | //input: fs.createReadStream('./lists/servers.txt') 556 | input: fs.createReadStream('./lists/alexaTop1mAXFRcommonSubdomains.txt') 557 | }); 558 | lineReader.on('line', function (subdomain) { 559 | dns.resolve(subdomain + '.' + query, function(err, addresses){ 560 | if (typeof(addresses) !== 'undefined'){ 561 | if(addresses[0] !== wildcardIP[0]){ 562 | new_node = JSON.parse('{"id": "'+ subdomain + '.' + query + '", "parent": "' + query + '", "node_type": "subdomain"}') 563 | io.emit('add_node', new_node) 564 | for (server in addresses){ 565 | new_node = JSON.parse('{"id": "'+ addresses[server] + '", "parent": "' + subdomain + '.' + query + '", "node_type": "server"}') 566 | io.emit('add_node', new_node) 567 | } 568 | } 569 | } 570 | }) 571 | }) 572 | }) 573 | lineReader.on('close', function () { 574 | //console.log(dateFormat("isoDateTime") + " finished bruteforce"); 575 | }); 576 | }); 577 | 578 | socket.on('port_scan', function(query_object){ 579 | //console.log(dateFormat("isoDateTime") + " starting port scan"); 580 | if(query_object.node_type == 'cidr'){ 581 | var block = new netmask(query_object.node_id); 582 | target_range = block.first + "-" + block.last 583 | }else{ 584 | target_range = query_object.node_id 585 | } 586 | let options = { 587 | target : target_range, 588 | // target :'192.168.1.1-5', 589 | // target :'192.168.1.1-192.168.1.5', 590 | //port :'21, 22, 23, 25, 80, 443, 4443, 4444, 3389, 139, 137, 8443, 8080', 591 | port : query_object.port_list, 592 | //status : 'TROU', // Timeout, Refused, Open, Unreachable 593 | status : 'O', // Timeout, Refused, Open, Unreachable 594 | timeout : 3000, 595 | banner : false,//maybe we can collect this later. Might slow down the scans though 596 | //geo : true 597 | }; 598 | 599 | let scanner = new evilscan(options); 600 | scanner.on('result',function (data) { 601 | // fired when item is matching options 602 | //console.log(data); 603 | //make sure to create ip nodes if we are scanning a range 604 | if(query_object.node_type == 'cidr'){ 605 | new_node = JSON.parse('{"id": "'+ data.ip + '", "parent": "' + query_object.node_id + '", "node_type": "server"}') 606 | io.emit('add_node', new_node) 607 | new_node = JSON.parse('{"id": "'+ data.ip + ':' + data.port + '", "parent": "' + data.ip + '", "node_type": "port"}') 608 | io.emit('add_node', new_node) 609 | }else{ 610 | new_node = JSON.parse('{"id": "'+ data.ip + ':' + data.port + '", "parent": "' + query_object.node_id + '", "node_type": "port"}') 611 | io.emit('add_node', new_node) 612 | } 613 | }); 614 | scanner.on('error',function (err) { 615 | //throw new Error(data.toString()); 616 | console.log(data.toString()); 617 | }); 618 | scanner.on('done',function () { 619 | //console.log(dateFormat("isoDateTime") + " finished port scan"); 620 | }); 621 | scanner.run(); 622 | }); 623 | 624 | socket.on('location_search', function(query_object){ 625 | api_call = { 626 | hostname: 'ipapi.co', 627 | path: '/' + query_object + '/json/', 628 | headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36' } 629 | }; 630 | https_resolver.get(api_call, (resp) => { 631 | let data = ''; 632 | 633 | resp.on('data', (chunk) => { 634 | data += chunk; 635 | }); 636 | 637 | resp.on('end', () => { 638 | location_results = JSON.parse(data) 639 | try{ 640 | new_node = JSON.parse('{"id": "'+ location_results.latitude + ':' + location_results.longitude + '", "parent": "' + query_object + '", "node_type": "location"}') 641 | io.emit('add_node', new_node) 642 | }catch (err){ 643 | } 644 | try{ 645 | new_node = JSON.parse('{"id": "State: '+ location_results.region + '", "parent": "' + query_object + '", "node_type": "info"}') 646 | io.emit('add_node', new_node) 647 | }catch (err){ 648 | } 649 | try{ 650 | new_node = JSON.parse('{"id": "City: '+ location_results.city + '", "parent": "' + query_object + '", "node_type": "info"}') 651 | io.emit('add_node', new_node) 652 | }catch (err){ 653 | } 654 | try{ 655 | new_node = JSON.parse('{"id": "'+ location_results.org + '", "parent": "' + query_object + '", "node_type": "organization"}') 656 | io.emit('add_node', new_node) 657 | }catch (err){ 658 | } 659 | }); 660 | 661 | }).on("error", (err) => { 662 | console.log("Error: " + err.message); 663 | }); 664 | 665 | }); 666 | 667 | socket.on('convert_to_cidr', function(query_object){ 668 | try{ 669 | query_object = query_object.replace(/[\s\n\r]+/g,'') 670 | range = query_object.split('-') 671 | base_ip = range[0] 672 | limit_ip = range[1] 673 | for(mask = 32; mask > 0; mask -= 1){ 674 | var block = new netmask(base_ip + "/" + mask.toString()); 675 | if((block.base == base_ip)&(block.broadcast == limit_ip)){ 676 | new_node = JSON.parse('{"id": "'+ base_ip + "/" + mask.toString() + '", "parent": "' + query_object + '", "node_type": "cidr"}') 677 | io.emit('add_node', new_node) 678 | //console.log(block) 679 | } 680 | } 681 | }catch (err){ 682 | io.emit('server_message', "Error Converting to CIDR: " + err) 683 | } 684 | }); 685 | 686 | socket.on('zone_transfer', function(query){ 687 | dns.resolveNs(query, function(err, records){ 688 | for (entry in records){ 689 | new_node = JSON.parse('{"id": "'+ records[entry] + '", "parent": "' + query + '", "node_type": "nameserver"}') 690 | io.emit('add_node', new_node) 691 | axfr.resolveAxfrTimeout(1000); 692 | axfr.resolveAxfr(records[entry], query, function(err, addr) { 693 | if (err) { 694 | //console.error('Error ocurred: ' + addr + ' (' + err + ')'); 695 | return; 696 | } 697 | results = addr.answers 698 | for(i=0;i { 727 | let data = ''; 728 | 729 | resp.on('data', (chunk) => { 730 | data += chunk; 731 | }); 732 | 733 | resp.on('end', () => { 734 | try{ 735 | results = JSON.parse(data) 736 | io.emit('server_message', "Used: " + results.data.calls.used + "\nAvailable: " + (results.data.calls.available - results.data.calls.used) + "\nResets: " + results.data.reset_date) 737 | }catch (err){ 738 | io.emit('server_message', "There is a problem with your API key") 739 | } 740 | }); 741 | }).on("error", (err) => { 742 | console.log("Error: " + err.message); 743 | }); 744 | }); 745 | 746 | 747 | socket.on('email_search', function(query_object){ 748 | 749 | api_call = 'https://sks-keyservers.net/pks/lookup?search=' + query_object.node_id 750 | https_resolver.get(api_call, (resp) => { 751 | let data = ''; 752 | 753 | resp.on('data', (chunk) => { 754 | data += chunk; 755 | }); 756 | 757 | resp.on('end', () => { 758 | myRegexp = />([^<]+@[^<]+)/g 759 | do { 760 | match = myRegexp.exec(data); 761 | if (match) { 762 | name = match[1].slice(0, match[1].indexOf('<')) 763 | email = match[1].slice(match[1].indexOf('<')+4, match[1].indexOf('>')) 764 | new_node = JSON.parse('{"id": "'+ email + '", "parent": "' + query_object.node_id + '", "node_type": "email"}') 765 | io.emit('add_node', new_node) 766 | new_node = JSON.parse('{"id": "'+ name + '", "parent": "' + email + '", "node_type": "person"}') 767 | io.emit('add_node', new_node) 768 | } 769 | } while (match); 770 | }); 771 | 772 | }).on("error", (err) => { 773 | console.log("Error: " + err.message); 774 | }); 775 | 776 | api_call = 'https://api.hunter.io/v2/domain-search?limit=1000&domain=' + query_object.node_id + '&api_key=' + query_object.hunter_api_key 777 | 778 | https_resolver.get(api_call, (resp) => { 779 | let data = ''; 780 | 781 | resp.on('data', (chunk) => { 782 | data += chunk; 783 | }); 784 | 785 | resp.on('end', () => { 786 | results = JSON.parse(data) 787 | if(results.data.pattern){ 788 | new_node = JSON.parse('{"id": "Mail Pattern:'+ results.data.pattern + '", "parent": "' + query_object.node_id + '", "node_type": "info"}') 789 | io.emit('add_node', new_node) 790 | } 791 | if(results.data.organization){ 792 | new_node = JSON.parse('{"id": "'+ results.data.organization + '", "parent": "' + query_object.node_id + '", "node_type": "organization"}') 793 | io.emit('add_node', new_node) 794 | } 795 | for(i=0; i < results.data.emails.length; i++){ 796 | email = results.data.emails[i] 797 | new_node = JSON.parse('{"id": "'+ email.value + '", "parent": "' + query_object.node_id + '", "node_type": "email"}') 798 | io.emit('add_node', new_node) 799 | if(email.first_name && email.last_name){ 800 | new_node = JSON.parse('{"id": "'+ email.first_name + ' ' + email.last_name + '", "parent": "' + email.value + '", "node_type": "person"}') 801 | io.emit('add_node', new_node) 802 | }else if(email.first_name){ 803 | new_node = JSON.parse('{"id": "'+ email.first_name + '", "parent": "' + email.value + '", "node_type": "person"}') 804 | io.emit('add_node', new_node) 805 | }else if(email.last_name){ 806 | new_node = JSON.parse('{"id": "'+ email.last_name + '", "parent": "' + email.value + '", "node_type": "person"}') 807 | io.emit('add_node', new_node) 808 | } 809 | if(email.position){ 810 | new_node = JSON.parse('{"id": "'+ email.position + '", "parent": "' + email.value + '", "node_type": "position"}') 811 | io.emit('add_node', new_node) 812 | } 813 | if(email.twitter){ 814 | new_node = JSON.parse('{"id": "www.twitter.com/'+ email.twitter + '", "parent": "' + email.value + '", "node_type": "info"}') 815 | io.emit('add_node', new_node) 816 | } 817 | if(email.linkedin){ 818 | new_node = JSON.parse('{"id": "www.linkedin.com/in/'+ email.linkedin + '", "parent": "' + email.value + '", "node_type": "info"}') 819 | io.emit('add_node', new_node) 820 | } 821 | if(email.phone_number){ 822 | new_node = JSON.parse('{"id": "'+ email.phone_number + '", "parent": "' + email.value + '", "node_type": "phone"}') 823 | io.emit('add_node', new_node) 824 | } 825 | for(j=0; j < email.sources.length; j++){ 826 | source = email.sources[j] 827 | new_node = JSON.parse('{"id": "Email Source:'+ source.uri + '", "parent": "' + email.value + '", "node_type": "info"}') 828 | io.emit('add_node', new_node) 829 | } 830 | } 831 | }); 832 | }).on("error", (err) => { 833 | console.log("Error: " + err.message); 834 | }); 835 | }); 836 | 837 | socket.on('query_shodan', function(query_object){ 838 | if(query_object.node_type == "organization"){ 839 | api_call = 'https://api.shodan.io/shodan/host/search?query=org:"' + encodeURIComponent(query_object.node_id) + '"&key=' + query_object.api_key 840 | }else if((query_object.node_type == "cidr") || (query_object.node_type == "server")) { 841 | api_call = 'https://api.shodan.io/shodan/host/search?query=net:' + encodeURIComponent(query_object.node_id) + '&key=' + query_object.api_key 842 | }else{ 843 | api_call = 'https://api.shodan.io/shodan/host/search?query=hostname:' + encodeURIComponent(query_object.node_id) + '&key=' + query_object.api_key 844 | } 845 | https_resolver.get(api_call, (resp) => { 846 | let data = ''; 847 | 848 | resp.on('data', (chunk) => { 849 | data += chunk; 850 | }); 851 | 852 | resp.on('end', () => { 853 | shodan_results = JSON.parse(data) 854 | for(i=0; i < shodan_results.matches.length; i++) { 855 | match = shodan_results.matches[i] 856 | try { 857 | server = match.ip_str 858 | new_node = JSON.parse('{"id": "'+ server + '", "parent": "' + query_object.node_id + '", "node_type": "server"}') 859 | io.emit('add_node', new_node) 860 | host_names = match.hostnames 861 | for (j=0; j < host_names.length; j++) { 862 | subdomain = host_names[j] 863 | new_node = JSON.parse('{"id": "'+ subdomain + '", "parent": "' + server + '", "node_type": "subdomain"}') 864 | io.emit('add_node', new_node) 865 | } 866 | network_names = match.domains 867 | for (j=0; j < network_names.length; j++) { 868 | network = host_names[j] 869 | new_node = JSON.parse('{"id": "'+ network + '", "parent": "' + server + '", "node_type": "network"}') 870 | io.emit('add_node', new_node) 871 | } 872 | if(match.port){ 873 | new_node = JSON.parse('{"id": "'+ server + ":" + match.port + '", "parent": "' + server + '", "node_type": "port"}') 874 | io.emit('add_node', new_node) 875 | } 876 | if(match.location.longitude){ 877 | new_node = JSON.parse('{"id": "'+ match.location.latitude + ":" + match.location.longitude + '", "parent": "' + server + '", "node_type": "location"}') 878 | io.emit('add_node', new_node) 879 | if(match.location.city){ 880 | new_node = JSON.parse('{"id": "City: '+ match.location.city + '", "parent": "' + match.location.latitude + ":" + match.location.longitude + '", "node_type": "info"}') 881 | io.emit('add_node', new_node) 882 | } 883 | if(match.location.region_code){ 884 | new_node = JSON.parse('{"id": "State: '+ match.location.region_code + '", "parent": "' + match.location.latitude + ":" + match.location.longitude + '", "node_type": "info"}') 885 | io.emit('add_node', new_node) 886 | } 887 | } 888 | if(match.org){ 889 | new_node = JSON.parse('{"id": "'+ match.org + '", "parent": "' + server + '", "node_type": "organization"}') 890 | io.emit('add_node', new_node) 891 | } 892 | } catch (err) { 893 | console.log(err); 894 | } 895 | } 896 | }); 897 | }).on("error", (err) => { 898 | console.log("Error: " + err.message); 899 | }); 900 | }); 901 | 902 | socket.on('linkedin_search', function(query_object){ 903 | linkedinMiner(query_object.node_id, io, query_object.linkedin_cookie, query_object.org_id, query_object.start_page, query_object.end_page) 904 | }); 905 | 906 | socket.on('open_file', function(query_object){ 907 | glob(query_object.file_path, function (er, files) { 908 | for (var i=0; i { 969 | setTimeout(() => { 970 | resolve() 971 | }, (timeout + Math.random()*1000)) 972 | }) 973 | } 974 | 975 | //sorry this function is so funky! had to do some sync gynastics to keep enumeration to a human level so we don't get busted ;D 976 | async function linkedinMiner(parent_node, io, linkedin_cookie, org_id, start_page, end_page) { 977 | async function launchChrome() { 978 | return await chromeLauncher.launch({ 979 | chromeFlags: [ 980 | '--headless', 981 | '--disable-gpu' 982 | ] 983 | }); 984 | } 985 | const chrome = await launchChrome(); 986 | const protocol = await CDP({ 987 | port: chrome.port 988 | }); 989 | 990 | const { 991 | DOM, 992 | Page, 993 | Emulation, 994 | Runtime 995 | } = protocol; 996 | 997 | await Promise.all([Page.enable(), Runtime.enable(), DOM.enable()]); 998 | await protocol.Network.setCookie({ 999 | name: "li_at", 1000 | value: linkedin_cookie, 1001 | domain: "www.linkedin.com" 1002 | }) 1003 | 1004 | async function getPage(page_number){ 1005 | return new Promise(async function(resolve, reject){ 1006 | Page.navigate({ 1007 | url: 'https://www.linkedin.com/search/results/people/?facetCurrentCompany=%5B%22' + org_id + '%22%5D&page=' + page_number 1008 | }); 1009 | 1010 | Page.loadEventFired(async() => { 1011 | await wait(2000) 1012 | script1 = "window.scrollTo(0,(document.body.scrollHeight/2));" 1013 | result = await Runtime.evaluate({ 1014 | expression: script1 1015 | }); 1016 | await wait(2000) 1017 | script1 = "window.scrollTo(0,document.body.scrollHeight);" 1018 | result = await Runtime.evaluate({ 1019 | expression: script1 1020 | }); 1021 | await wait(2000) 1022 | // script1 = 'names = document.getElementsByClassName("name actor-name");output = "";for (i = 0; i < names.length; i++){ if (names[i].text != "LinkedIn Member"){output = output + "\\n" + (names[i].innerHTML)}};output;' 1023 | script1 = 'names = document.getElementsByClassName("name actor-name");output = "";for (i = 0; i < names.length; i++){ if (names[i].text != "LinkedIn Member"){output = output + "\\n" + (names[i].innerHTML + ":" + names[i].parentNode.parentNode.parentNode.parentNode.parentNode.getElementsByTagName("p")[0].textContent.trim())}};output;' 1024 | 1025 | result = await Runtime.evaluate({ 1026 | expression: script1 1027 | }); 1028 | 1029 | resolve(result.result.value); 1030 | }); 1031 | }); 1032 | } 1033 | 1034 | for (i=start_page;i<=end_page;i++) { 1035 | results = await getPage(i).catch( e => { } ) 1036 | employees = results.split('\n') 1037 | //console.log(employees); 1038 | for(j=0; j=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function i(t){var n=this.useColors;if(t[0]=(n?"%c":"")+this.namespace+(n?" %c":" ")+t[0]+(n?"%c ":" ")+"+"+e.humanize(this.diff),n){var r="color: "+this.color;t.splice(1,0,r,"color: inherit");var o=0,i=0;t[0].replace(/%[a-zA-Z%]/g,function(t){"%%"!==t&&(o++,"%c"===t&&(i=o))}),t.splice(i,0,r)}}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(t){try{null==t?e.storage.removeItem("debug"):e.storage.debug=t}catch(n){}}function c(){var t;try{t=e.storage.debug}catch(n){}return!t&&"undefined"!=typeof r&&"env"in r&&(t=r.env.DEBUG),t}function p(){try{return window.localStorage}catch(t){}}e=t.exports=n(5),e.log=s,e.formatArgs=i,e.save=a,e.load=c,e.useColors=o,e.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:p(),e.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],e.formatters.j=function(t){try{return JSON.stringify(t)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}},e.enable(c())}).call(e,n(4))},function(t,e){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function o(t){if(u===setTimeout)return setTimeout(t,0);if((u===n||!u)&&setTimeout)return u=setTimeout,setTimeout(t,0);try{return u(t,0)}catch(e){try{return u.call(null,t,0)}catch(e){return u.call(this,t,0)}}}function i(t){if(h===clearTimeout)return clearTimeout(t);if((h===r||!h)&&clearTimeout)return h=clearTimeout,clearTimeout(t);try{return h(t)}catch(e){try{return h.call(null,t)}catch(e){return h.call(this,t)}}}function s(){y&&l&&(y=!1,l.length?d=l.concat(d):m=-1,d.length&&a())}function a(){if(!y){var t=o(s);y=!0;for(var e=d.length;e;){for(l=d,d=[];++m1)for(var n=1;n100)){var e=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(t);if(e){var n=parseFloat(e[1]),r=(e[2]||"ms").toLowerCase();switch(r){case"years":case"year":case"yrs":case"yr":case"y":return n*u;case"days":case"day":case"d":return n*p;case"hours":case"hour":case"hrs":case"hr":case"h":return n*c;case"minutes":case"minute":case"mins":case"min":case"m":return n*a;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}}}function r(t){return t>=p?Math.round(t/p)+"d":t>=c?Math.round(t/c)+"h":t>=a?Math.round(t/a)+"m":t>=s?Math.round(t/s)+"s":t+"ms"}function o(t){return i(t,p,"day")||i(t,c,"hour")||i(t,a,"minute")||i(t,s,"second")||t+" ms"}function i(t,e,n){if(!(t0)return n(t);if("number"===i&&isNaN(t)===!1)return e["long"]?o(t):r(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))}},function(t,e,n){function r(){}function o(t){var n=""+t.type;if(e.BINARY_EVENT!==t.type&&e.BINARY_ACK!==t.type||(n+=t.attachments+"-"),t.nsp&&"/"!==t.nsp&&(n+=t.nsp+","),null!=t.id&&(n+=t.id),null!=t.data){var r=i(t.data);if(r===!1)return g;n+=r}return f("encoded %j as %s",t,n),n}function i(t){try{return JSON.stringify(t)}catch(e){return!1}}function s(t,e){function n(t){var n=d.deconstructPacket(t),r=o(n.packet),i=n.buffers;i.unshift(r),e(i)}d.removeBlobs(t,n)}function a(){this.reconstructor=null}function c(t){var n=0,r={type:Number(t.charAt(0))};if(null==e.types[r.type])return h("unknown packet type "+r.type);if(e.BINARY_EVENT===r.type||e.BINARY_ACK===r.type){for(var o="";"-"!==t.charAt(++n)&&(o+=t.charAt(n),n!=t.length););if(o!=Number(o)||"-"!==t.charAt(n))throw new Error("Illegal attachments");r.attachments=Number(o)}if("/"===t.charAt(n+1))for(r.nsp="";++n;){var i=t.charAt(n);if(","===i)break;if(r.nsp+=i,n===t.length)break}else r.nsp="/";var s=t.charAt(n+1);if(""!==s&&Number(s)==s){for(r.id="";++n;){var i=t.charAt(n);if(null==i||Number(i)!=i){--n;break}if(r.id+=t.charAt(n),n===t.length)break}r.id=Number(r.id)}if(t.charAt(++n)){var a=p(t.substr(n)),c=a!==!1&&(r.type===e.ERROR||y(a));if(!c)return h("invalid payload");r.data=a}return f("decoded %s as %j",t,r),r}function p(t){try{return JSON.parse(t)}catch(e){return!1}}function u(t){this.reconPack=t,this.buffers=[]}function h(t){return{type:e.ERROR,data:"parser error: "+t}}var f=n(3)("socket.io-parser"),l=n(8),d=n(9),y=n(10),m=n(11);e.protocol=4,e.types=["CONNECT","DISCONNECT","EVENT","ACK","ERROR","BINARY_EVENT","BINARY_ACK"],e.CONNECT=0,e.DISCONNECT=1,e.EVENT=2,e.ACK=3,e.ERROR=4,e.BINARY_EVENT=5,e.BINARY_ACK=6,e.Encoder=r,e.Decoder=a;var g=e.ERROR+'"encode error"';r.prototype.encode=function(t,n){if(f("encoding packet %j",t),e.BINARY_EVENT===t.type||e.BINARY_ACK===t.type)s(t,n);else{var r=o(t);n([r])}},l(a.prototype),a.prototype.add=function(t){var n;if("string"==typeof t)n=c(t),e.BINARY_EVENT===n.type||e.BINARY_ACK===n.type?(this.reconstructor=new u(n),0===this.reconstructor.reconPack.attachments&&this.emit("decoded",n)):this.emit("decoded",n);else{if(!m(t)&&!t.base64)throw new Error("Unknown type: "+t);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");n=this.reconstructor.takeBinaryData(t),n&&(this.reconstructor=null,this.emit("decoded",n))}},a.prototype.destroy=function(){this.reconstructor&&this.reconstructor.finishedReconstruction()},u.prototype.takeBinaryData=function(t){if(this.buffers.push(t),this.buffers.length===this.reconPack.attachments){var e=d.reconstructPacket(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null},u.prototype.finishedReconstruction=function(){this.reconPack=null,this.buffers=[]}},function(t,e,n){function r(t){if(t)return o(t)}function o(t){for(var e in r.prototype)t[e]=r.prototype[e];return t}t.exports=r,r.prototype.on=r.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},r.prototype.once=function(t,e){function n(){this.off(t,n),e.apply(this,arguments)}return n.fn=e,this.on(t,n),this},r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n=this._callbacks["$"+t];if(!n)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var r,o=0;o0&&!this.encoding){var t=this.packetBuffer.shift();this.packet(t)}},r.prototype.cleanup=function(){h("cleanup");for(var t=this.subs.length,e=0;e=this._reconnectionAttempts)h("reconnect failed"),this.backoff.reset(),this.emitAll("reconnect_failed"),this.reconnecting=!1;else{var e=this.backoff.duration();h("will wait %dms before reconnect attempt",e),this.reconnecting=!0;var n=setTimeout(function(){t.skipReconnect||(h("attempting reconnect"),t.emitAll("reconnect_attempt",t.backoff.attempts),t.emitAll("reconnecting",t.backoff.attempts),t.skipReconnect||t.open(function(e){e?(h("reconnect attempt error"),t.reconnecting=!1,t.reconnect(),t.emitAll("reconnect_error",e.data)):(h("reconnect success"),t.onreconnect())}))},e);this.subs.push({destroy:function(){clearTimeout(n)}})}},r.prototype.onreconnect=function(){var t=this.backoff.attempts;this.reconnecting=!1,this.backoff.reset(),this.updateSocketIds(),this.emitAll("reconnect",t)}},function(t,e,n){t.exports=n(14),t.exports.parser=n(21)},function(t,e,n){function r(t,e){return this instanceof r?(e=e||{},t&&"object"==typeof t&&(e=t,t=null),t?(t=u(t),e.hostname=t.host,e.secure="https"===t.protocol||"wss"===t.protocol,e.port=t.port,t.query&&(e.query=t.query)):e.host&&(e.hostname=u(e.host).host),this.secure=null!=e.secure?e.secure:"undefined"!=typeof location&&"https:"===location.protocol,e.hostname&&!e.port&&(e.port=this.secure?"443":"80"),this.agent=e.agent||!1,this.hostname=e.hostname||("undefined"!=typeof location?location.hostname:"localhost"),this.port=e.port||("undefined"!=typeof location&&location.port?location.port:this.secure?443:80),this.query=e.query||{},"string"==typeof this.query&&(this.query=h.decode(this.query)),this.upgrade=!1!==e.upgrade,this.path=(e.path||"/engine.io").replace(/\/$/,"")+"/",this.forceJSONP=!!e.forceJSONP,this.jsonp=!1!==e.jsonp,this.forceBase64=!!e.forceBase64,this.enablesXDR=!!e.enablesXDR,this.timestampParam=e.timestampParam||"t",this.timestampRequests=e.timestampRequests,this.transports=e.transports||["polling","websocket"],this.transportOptions=e.transportOptions||{},this.readyState="",this.writeBuffer=[],this.prevBufferLen=0,this.policyPort=e.policyPort||843,this.rememberUpgrade=e.rememberUpgrade||!1,this.binaryType=null,this.onlyBinaryUpgrades=e.onlyBinaryUpgrades,this.perMessageDeflate=!1!==e.perMessageDeflate&&(e.perMessageDeflate||{}),!0===this.perMessageDeflate&&(this.perMessageDeflate={}),this.perMessageDeflate&&null==this.perMessageDeflate.threshold&&(this.perMessageDeflate.threshold=1024),this.pfx=e.pfx||null,this.key=e.key||null,this.passphrase=e.passphrase||null,this.cert=e.cert||null,this.ca=e.ca||null,this.ciphers=e.ciphers||null,this.rejectUnauthorized=void 0===e.rejectUnauthorized||e.rejectUnauthorized,this.forceNode=!!e.forceNode,this.isReactNative="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase(),("undefined"==typeof self||this.isReactNative)&&(e.extraHeaders&&Object.keys(e.extraHeaders).length>0&&(this.extraHeaders=e.extraHeaders),e.localAddress&&(this.localAddress=e.localAddress)),this.id=null,this.upgrades=null,this.pingInterval=null,this.pingTimeout=null,this.pingIntervalTimer=null,this.pingTimeoutTimer=null,void this.open()):new r(t,e)}function o(t){var e={};for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}var i=n(15),s=n(8),a=n(3)("engine.io-client:socket"),c=n(35),p=n(21),u=n(2),h=n(29);t.exports=r,r.priorWebsocketSuccess=!1,s(r.prototype),r.protocol=p.protocol,r.Socket=r,r.Transport=n(20),r.transports=n(15),r.parser=n(21),r.prototype.createTransport=function(t){a('creating transport "%s"',t);var e=o(this.query);e.EIO=p.protocol,e.transport=t;var n=this.transportOptions[t]||{};this.id&&(e.sid=this.id);var r=new i[t]({query:e,socket:this,agent:n.agent||this.agent,hostname:n.hostname||this.hostname,port:n.port||this.port,secure:n.secure||this.secure,path:n.path||this.path,forceJSONP:n.forceJSONP||this.forceJSONP,jsonp:n.jsonp||this.jsonp,forceBase64:n.forceBase64||this.forceBase64,enablesXDR:n.enablesXDR||this.enablesXDR,timestampRequests:n.timestampRequests||this.timestampRequests,timestampParam:n.timestampParam||this.timestampParam,policyPort:n.policyPort||this.policyPort,pfx:n.pfx||this.pfx,key:n.key||this.key,passphrase:n.passphrase||this.passphrase,cert:n.cert||this.cert,ca:n.ca||this.ca,ciphers:n.ciphers||this.ciphers,rejectUnauthorized:n.rejectUnauthorized||this.rejectUnauthorized,perMessageDeflate:n.perMessageDeflate||this.perMessageDeflate,extraHeaders:n.extraHeaders||this.extraHeaders,forceNode:n.forceNode||this.forceNode,localAddress:n.localAddress||this.localAddress,requestTimeout:n.requestTimeout||this.requestTimeout,protocols:n.protocols||void 0,isReactNative:this.isReactNative});return r},r.prototype.open=function(){var t;if(this.rememberUpgrade&&r.priorWebsocketSuccess&&this.transports.indexOf("websocket")!==-1)t="websocket";else{if(0===this.transports.length){var e=this;return void setTimeout(function(){e.emit("error","No transports available")},0)}t=this.transports[0]}this.readyState="opening";try{t=this.createTransport(t)}catch(n){return this.transports.shift(),void this.open()}t.open(),this.setTransport(t)},r.prototype.setTransport=function(t){a("setting transport %s",t.name);var e=this;this.transport&&(a("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=t,t.on("drain",function(){e.onDrain()}).on("packet",function(t){e.onPacket(t)}).on("error",function(t){e.onError(t)}).on("close",function(){e.onClose("transport close")})},r.prototype.probe=function(t){function e(){if(f.onlyBinaryUpgrades){var e=!this.supportsBinary&&f.transport.supportsBinary;h=h||e}h||(a('probe transport "%s" opened',t),u.send([{type:"ping",data:"probe"}]),u.once("packet",function(e){if(!h)if("pong"===e.type&&"probe"===e.data){if(a('probe transport "%s" pong',t),f.upgrading=!0,f.emit("upgrading",u),!u)return;r.priorWebsocketSuccess="websocket"===u.name,a('pausing current transport "%s"',f.transport.name),f.transport.pause(function(){h||"closed"!==f.readyState&&(a("changing transport and sending upgrade packet"),p(),f.setTransport(u),u.send([{type:"upgrade"}]),f.emit("upgrade",u),u=null,f.upgrading=!1,f.flush())})}else{a('probe transport "%s" failed',t);var n=new Error("probe error");n.transport=u.name,f.emit("upgradeError",n)}}))}function n(){h||(h=!0,p(),u.close(),u=null)}function o(e){var r=new Error("probe error: "+e);r.transport=u.name,n(),a('probe transport "%s" failed because of error: %s',t,e),f.emit("upgradeError",r)}function i(){o("transport closed")}function s(){o("socket closed")}function c(t){u&&t.name!==u.name&&(a('"%s" works - aborting "%s"',t.name,u.name),n())}function p(){u.removeListener("open",e),u.removeListener("error",o),u.removeListener("close",i),f.removeListener("close",s),f.removeListener("upgrading",c)}a('probing transport "%s"',t);var u=this.createTransport(t,{probe:1}),h=!1,f=this;r.priorWebsocketSuccess=!1,u.once("open",e),u.once("error",o),u.once("close",i),this.once("close",s),this.once("upgrading",c),u.open()},r.prototype.onOpen=function(){if(a("socket open"),this.readyState="open",r.priorWebsocketSuccess="websocket"===this.transport.name,this.emit("open"),this.flush(),"open"===this.readyState&&this.upgrade&&this.transport.pause){a("starting upgrade probes");for(var t=0,e=this.upgrades.length;t1?{type:b[o],data:t.substring(1)}:{type:b[o]}:w}var i=new Uint8Array(t),o=i[0],s=f(t,1);return k&&"blob"===n&&(s=new k([s])),{type:b[o],data:s}},e.decodeBase64Packet=function(t,e){var n=b[t.charAt(0)];if(!p)return{type:n,data:{base64:!0,data:t.substr(1)}};var r=p.decode(t.substr(1));return"blob"===e&&k&&(r=new k([r])),{type:n,data:r}},e.encodePayload=function(t,n,r){function o(t){return t.length+":"+t}function i(t,r){e.encodePacket(t,!!s&&n,!1,function(t){r(null,o(t))})}"function"==typeof n&&(r=n,n=null);var s=h(t);return n&&s?k&&!g?e.encodePayloadAsBlob(t,r):e.encodePayloadAsArrayBuffer(t,r):t.length?void c(t,i,function(t,e){return r(e.join(""))}):r("0:")},e.decodePayload=function(t,n,r){if("string"!=typeof t)return e.decodePayloadAsBinary(t,n,r);"function"==typeof n&&(r=n,n=null);var o;if(""===t)return r(w,0,1);for(var i,s,a="",c=0,p=t.length;c0;){for(var s=new Uint8Array(o),a=0===s[0],c="",p=1;255!==s[p];p++){if(c.length>310)return r(w,0,1);c+=s[p]}o=f(o,2+c.length),c=parseInt(c);var u=f(o,0,c);if(a)try{u=String.fromCharCode.apply(null,new Uint8Array(u))}catch(h){var l=new Uint8Array(u);u="";for(var p=0;pr&&(n=r),e>=r||e>=n||0===r)return new ArrayBuffer(0);for(var o=new Uint8Array(t),i=new Uint8Array(n-e),s=e,a=0;s=55296&&e<=56319&&o65535&&(e-=65536,o+=d(e>>>10&1023|55296),e=56320|1023&e),o+=d(e);return o}function o(t,e){if(t>=55296&&t<=57343){if(e)throw Error("Lone surrogate U+"+t.toString(16).toUpperCase()+" is not a scalar value");return!1}return!0}function i(t,e){return d(t>>e&63|128)}function s(t,e){if(0==(4294967168&t))return d(t);var n="";return 0==(4294965248&t)?n=d(t>>6&31|192):0==(4294901760&t)?(o(t,e)||(t=65533),n=d(t>>12&15|224),n+=i(t,6)):0==(4292870144&t)&&(n=d(t>>18&7|240),n+=i(t,12),n+=i(t,6)),n+=d(63&t|128)}function a(t,e){e=e||{};for(var r,o=!1!==e.strict,i=n(t),a=i.length,c=-1,p="";++c=f)throw Error("Invalid byte index");var t=255&h[l];if(l++,128==(192&t))return 63&t;throw Error("Invalid continuation byte")}function p(t){var e,n,r,i,s;if(l>f)throw Error("Invalid byte index");if(l==f)return!1;if(e=255&h[l],l++,0==(128&e))return e;if(192==(224&e)){if(n=c(),s=(31&e)<<6|n,s>=128)return s;throw Error("Invalid continuation byte")}if(224==(240&e)){if(n=c(),r=c(),s=(15&e)<<12|n<<6|r,s>=2048)return o(s,t)?s:65533;throw Error("Invalid continuation byte")}if(240==(248&e)&&(n=c(),r=c(),i=c(),s=(7&e)<<18|n<<12|r<<6|i,s>=65536&&s<=1114111))return s;throw Error("Invalid UTF-8 detected")}function u(t,e){e=e||{};var o=!1!==e.strict;h=n(t),f=h.length,l=0;for(var i,s=[];(i=p(o))!==!1;)s.push(i);return r(s)}/*! https://mths.be/utf8js v2.1.2 by @mathias */ 8 | var h,f,l,d=String.fromCharCode;t.exports={version:"2.1.2",encode:a,decode:u}},function(t,e){!function(){"use strict";for(var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n=new Uint8Array(256),r=0;r>2],i+=t[(3&r[n])<<4|r[n+1]>>4],i+=t[(15&r[n+1])<<2|r[n+2]>>6],i+=t[63&r[n+2]];return o%3===2?i=i.substring(0,i.length-1)+"=":o%3===1&&(i=i.substring(0,i.length-2)+"=="),i},e.decode=function(t){var e,r,o,i,s,a=.75*t.length,c=t.length,p=0;"="===t[t.length-1]&&(a--,"="===t[t.length-2]&&a--);var u=new ArrayBuffer(a),h=new Uint8Array(u);for(e=0;e>4,h[p++]=(15&o)<<4|i>>2,h[p++]=(3&i)<<6|63&s;return u}}()},function(t,e){function n(t){return t.map(function(t){if(t.buffer instanceof ArrayBuffer){var e=t.buffer;if(t.byteLength!==e.byteLength){var n=new Uint8Array(t.byteLength);n.set(new Uint8Array(e,t.byteOffset,t.byteLength)),e=n.buffer}return e}return t})}function r(t,e){e=e||{};var r=new i;return n(t).forEach(function(t){r.append(t)}),e.type?r.getBlob(e.type):r.getBlob()}function o(t,e){return new Blob(n(t),e||{})}var i="undefined"!=typeof i?i:"undefined"!=typeof WebKitBlobBuilder?WebKitBlobBuilder:"undefined"!=typeof MSBlobBuilder?MSBlobBuilder:"undefined"!=typeof MozBlobBuilder&&MozBlobBuilder,s=function(){try{var t=new Blob(["hi"]);return 2===t.size}catch(e){return!1}}(),a=s&&function(){try{var t=new Blob([new Uint8Array([1,2])]);return 2===t.size}catch(e){return!1}}(),c=i&&i.prototype.append&&i.prototype.getBlob;"undefined"!=typeof Blob&&(r.prototype=Blob.prototype,o.prototype=Blob.prototype),t.exports=function(){return s?a?Blob:o:c?r:void 0}()},function(t,e){e.encode=function(t){var e="";for(var n in t)t.hasOwnProperty(n)&&(e.length&&(e+="&"),e+=encodeURIComponent(n)+"="+encodeURIComponent(t[n]));return e},e.decode=function(t){for(var e={},n=t.split("&"),r=0,o=n.length;r0);return e}function r(t){var e=0;for(u=0;u';i=document.createElement(e)}catch(t){i=document.createElement("iframe"),i.name=o.iframeId,i.src="javascript:0"}i.id=o.iframeId,o.form.appendChild(i),o.iframe=i}var o=this;if(!this.form){var i,s=document.createElement("form"),a=document.createElement("textarea"),c=this.iframeId="eio_iframe_"+this.index;s.className="socketio",s.style.position="absolute",s.style.top="-1000px",s.style.left="-1000px",s.target=c,s.method="POST",s.setAttribute("accept-charset","utf-8"),a.name="d",s.appendChild(a),document.body.appendChild(s),this.form=s,this.area=a}this.form.action=this.uri(),r(),t=t.replace(u,"\\\n"),this.area.value=t.replace(p,"\\n");try{this.form.submit()}catch(h){}this.iframe.attachEvent?this.iframe.onreadystatechange=function(){"complete"===o.iframe.readyState&&n()}:this.iframe.onload=n}}).call(e,function(){return this}())},function(t,e,n){function r(t){var e=t&&t.forceBase64;e&&(this.supportsBinary=!1),this.perMessageDeflate=t.perMessageDeflate,this.usingBrowserWebSocket=o&&!t.forceNode,this.protocols=t.protocols,this.usingBrowserWebSocket||(l=i),s.call(this,t)}var o,i,s=n(20),a=n(21),c=n(29),p=n(30),u=n(31),h=n(3)("engine.io-client:websocket");if("undefined"==typeof self)try{i=n(34)}catch(f){}else o=self.WebSocket||self.MozWebSocket;var l=o||i;t.exports=r,p(r,s),r.prototype.name="websocket",r.prototype.supportsBinary=!0,r.prototype.doOpen=function(){if(this.check()){var t=this.uri(),e=this.protocols,n={agent:this.agent,perMessageDeflate:this.perMessageDeflate};n.pfx=this.pfx,n.key=this.key,n.passphrase=this.passphrase,n.cert=this.cert,n.ca=this.ca,n.ciphers=this.ciphers,n.rejectUnauthorized=this.rejectUnauthorized,this.extraHeaders&&(n.headers=this.extraHeaders),this.localAddress&&(n.localAddress=this.localAddress);try{this.ws=this.usingBrowserWebSocket&&!this.isReactNative?e?new l(t,e):new l(t):new l(t,e,n)}catch(r){return this.emit("error",r)}void 0===this.ws.binaryType&&(this.supportsBinary=!1),this.ws.supports&&this.ws.supports.binary?(this.supportsBinary=!0,this.ws.binaryType="nodebuffer"):this.ws.binaryType="arraybuffer",this.addEventListeners()}},r.prototype.addEventListeners=function(){var t=this;this.ws.onopen=function(){t.onOpen()},this.ws.onclose=function(){t.onClose()},this.ws.onmessage=function(e){t.onData(e.data)},this.ws.onerror=function(e){t.onError("websocket error",e)}},r.prototype.write=function(t){function e(){n.emit("flush"),setTimeout(function(){n.writable=!0,n.emit("drain")},0)}var n=this;this.writable=!1;for(var r=t.length,o=0,i=r;o0&&t.jitter<=1?t.jitter:0,this.attempts=0}t.exports=n,n.prototype.duration=function(){var t=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var e=Math.random(),n=Math.floor(e*this.jitter*t);t=0==(1&Math.floor(10*e))?t-n:t+n}return 0|Math.min(t,this.max)},n.prototype.reset=function(){this.attempts=0},n.prototype.setMin=function(t){this.ms=t},n.prototype.setMax=function(t){this.max=t},n.prototype.setJitter=function(t){this.jitter=t}}])}); 9 | //# sourceMappingURL=socket.io.js.map -------------------------------------------------------------------------------- /scripts/vivagraph.min.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;"undefined"!=typeof window?n=window:"undefined"!=typeof global?n=global:"undefined"!=typeof self&&(n=self),n.Viva=e()}}(function(){return function e(n,t,r){function o(a,u){if(!t[a]){if(!n[a]){var s="function"==typeof require&&require;if(!u&&s)return s(a,!0);if(i)return i(a,!0);var f=new Error("Cannot find module '"+a+"'");throw f.code="MODULE_NOT_FOUND",f}var c=t[a]={exports:{}};n[a][0].call(c.exports,function(e){var t=n[a][1][e];return o(t?t:e)},c,c.exports,e,n,t,r)}return t[a].exports}for(var i="function"==typeof require&&require,a=0;a=0==m>=4?null:(f=u-i,d=o-a,p=a*i-o*u,v=f*e+d*n+p,h=f*t+d*r+p,0!==v&&0!==h&&v>=0==h>=0?null:(y=s*d-f*c,0===y?null:(x=y<0?-y/2:y/2,x=0,w=c*p-d*l,b.x=(w<0?w-x:w+x)/y,w=f*l-s*p,b.y=(w<0?w-x:w+x)/y,b)))}n.exports=r},{}],4:[function(e,n,t){n.exports.degree=e("./src/degree.js"),n.exports.betweenness=e("./src/betweenness.js"),n.exports.closeness=e("./src/closeness.js"),n.exports.eccentricity=e("./src/eccentricity.js")},{"./src/betweenness.js":5,"./src/closeness.js":6,"./src/degree.js":7,"./src/eccentricity.js":8}],5:[function(e,n,t){function r(e,n){function t(e){h[e]/=2}function r(e){h[e.id]=0}function o(e){s=e.id,u(s),i()}function i(){for(e.forEachNode(a);c.length;){for(var n=c.pop(),t=(1+v[n])/p[n],r=d[n],o=0;o0?f[a]=(n-1)/t:f[a]=0}function i(t){function r(e){var n=e.id;s[n]=-1}function o(e){var n=e.id;s[n]===-1&&(s[n]=s[i]+1,u.push(n))}for(e.forEachNode(r),s[t]=0,u.push(t);u.length;){var i=u.shift();e.forEachLinkedNode(i,o,n)}}var a,u=[],s=Object.create(null),f=Object.create(null);return e.forEachNode(t),e.forEachNode(r),f}n.exports=r},{}],7:[function(e,n,t){function r(e,n){function t(n){var t=e.getLinks(n.id);u[n.id]=r(t,n.id)}var r,u=Object.create(null);if(n=(n||"both").toLowerCase(),"both"===n||"inout"===n)r=a;else if("in"===n)r=o;else{if("out"!==n)throw new Error("Expected centrality degree kind is: in, out or both");r=i}return e.forEachNode(t),u}function o(e,n){var t=0;if(!e)return t;for(var r=0;r1&&(o=Array.prototype.splice.call(arguments,1));for(var i=0;i0&&i.addLink(a,r-1+o*e),o>0&&i.addLink(a,r+(o-1)*e)}return i}function s(e,t,r){if(e<1||t<1||r<1)throw new Error("Invalid number of nodes in grid3 graph");var o,i,a,u=n();if(1===e&&1===t&&1===r)return u.addNode(0),u;for(a=0;a0&&u.addLink(f,o-1+i*e+s),i>0&&u.addLink(f,o+(i-1)*e+s),a>0&&u.addLink(f,o+i*e+(a-1)*e*t)}return u}function f(e){if(e<0)throw new Error("Invalid number of nodes in balanced tree");var t,r=n(),o=Math.pow(2,e);for(0===e&&r.addNode(1),t=1;t= 0");var t,r=n();for(t=0;t0&&o.addLink(i*t,i*t-1);return o.addLink(0,o.getNodesCount()-1),o}function l(t,r,o,i){if(r>=t)throw new Error("Choose smaller `k`. It cannot be larger than number of nodes `n`");var a,u,s=e("ngraph.random").random(i||42),f=n();for(a=0;a=1||0===e);return n*Math.sqrt(-2*Math.log(e)/e)}function a(){var e=this.seed;return e=e+2127912214+(e<<12)&4294967295,e=4294967295&(3345072700^e^e>>>19),e=e+374761393+(e<<5)&4294967295,e=4294967295&(e+3550635116^e<<9),e=e+4251993797+(e<<3)&4294967295,e=4294967295&(3042594569^e^e>>>16),this.seed=e,(268435455&e)/268435456}function u(e){return Math.floor(this.nextDouble()*e)}function s(e,n){function t(){var n,t,r;for(n=e.length-1;n>0;--n)t=i.next(n+1),r=e[t],e[t]=e[n],e[n]=r;return e}function o(n){var t,r,o;for(t=e.length-1;t>0;--t)r=i.next(t+1),o=e[r],e[r]=e[t],e[t]=o,n(o);e.length&&n(e[0])}var i=n||r();if("function"!=typeof i.next)throw new Error("customRandom does not match expected API: next() function is missing");return{forEach:o,shuffle:t}}n.exports=r,n.exports.random=r,n.exports.randomIterator=s,o.prototype.next=u,o.prototype.nextDouble=a,o.prototype.uniform=a,o.prototype.gaussian=i},{}],16:[function(e,n,t){function r(e){function n(){function e(){return q.beginUpdate=F=k,q.endUpdate=G=P,B=t,O=r,q.on=n,n.apply(q,arguments)}var n=q.on;q.on=e}function t(e,n){R.push({link:e,changeType:n})}function r(e,n){R.push({node:e,changeType:n})}function c(e,n){if(void 0===e)throw new Error("Invalid node identifier");F();var t=d(e);return t?(t.data=n,O(t,"update")):(t=new i(e,n),S++,O(t,"add")),I[e]=t,G(),t}function d(e){return I[e]}function l(e){var n=d(e);if(!n)return!1;F();var t=n.links;if(t){n.links=null;for(var r=0;r=0&&t.links.splice(n,1)),r&&(n=o(e,r.links),n>=0&&r.links.splice(n,1)),B(e,"remove"),G(),!0}function y(e,n){var t,r=d(e);if(!r||!r.links)return null;for(t=0;t0&&(q.fire("changed",R),R.length=0)}function j(){return Object.keys?A:_}function A(e){if("function"==typeof e)for(var n=Object.keys(I),t=0;t=0?i:-1,o);return v.push(a),a},getTotalMovement:function(){return w},removeSpring:function(e){if(e){var n=v.indexOf(e);return n>-1?(v.splice(n,1),!0):void 0}},getBestNewBodyPosition:function(e){return g.getBestNewPosition(e)},getBBox:function(){return x&&(g.update(),x=!1),g.box},invalidateBBox:function(){x=!0},gravity:function(e){return void 0!==e?(n.gravity=e,h.options({gravity:e}),this):n.gravity},theta:function(e){return void 0!==e?(n.theta=e,h.options({theta:e}),this):n.theta}};return o(n,b),a(b),b}n.exports=r},{"./lib/bounds":20,"./lib/createBody":21,"./lib/dragForce":22,"./lib/eulerIntegrator":23,"./lib/spring":24,"./lib/springForce":25,"ngraph.events":9,"ngraph.expose":10,"ngraph.merge":17,"ngraph.quadtreebh":26}],20:[function(e,n,t){n.exports=function(n,t){function r(){var e=n.length;if(0!==e){for(var t=Number.MAX_VALUE,r=Number.MAX_VALUE,o=Number.MIN_VALUE,a=Number.MIN_VALUE;e--;){var u=n[e];u.isPinned?(u.pos.x=u.prevPos.x,u.pos.y=u.prevPos.y):(u.prevPos.x=u.pos.x,u.prevPos.y=u.pos.y),u.pos.xo&&(o=u.pos.x),u.pos.ya&&(a=u.pos.y)}i.x1=t,i.x2=o,i.y1=r,i.y2=a}}var o=e("ngraph.random").random(42),i={x1:0,y1:0,x2:0,y2:0};return{box:i,update:r,reset:function(){i.x1=i.y1=0,i.x2=i.y2=0},getBestNewPosition:function(e){var n=i,r=0,a=0;if(e.length){for(var u=0;u1&&(s.velocity.x=c/l,s.velocity.y=d/l),r=n*s.velocity.x,i=n*s.velocity.y,s.pos.x+=r,s.pos.y+=i,o+=Math.abs(r),a+=Math.abs(i)}return(o*o+a*a)/u}n.exports=r},{}],24:[function(e,n,t){function r(e,n,t,r,o){this.from=e,this.to=n,this.length=t,this.coeff=r,this.weight="number"==typeof o?o:1}n.exports=r},{}],25:[function(e,n,t){n.exports=function(n){var t=e("ngraph.merge"),r=e("ngraph.random").random(42),o=e("ngraph.expose");n=t(n,{springCoeff:2e-4,springLength:80});var i={update:function(e){var t=e.from,o=e.to,i=e.length<0?n.springLength:e.length,a=o.pos.x-t.pos.x,u=o.pos.y-t.pos.y,s=Math.sqrt(a*a+u*u);0===s&&(a=(r.nextDouble()-.5)/50,u=(r.nextDouble()-.5)/50,s=Math.sqrt(a*a+u*u));var f=s-i,c=(!e.coeff||e.coeff<0?n.springCoeff:e.coeff)*f/s*e.weight;t.force.x+=c*a,t.force.y+=c*u,o.force.x-=c*a,o.force.y-=c*u}};return o(n,i,["springCoeff","springLength"]),i}},{"ngraph.expose":10,"ngraph.merge":17,"ngraph.random":30}],26:[function(e,n,t){function r(e,n){return 0===n?e.quad0:1===n?e.quad1:2===n?e.quad2:3===n?e.quad3:null}function o(e,n,t){0===n?e.quad0=t:1===n?e.quad1=t:2===n?e.quad2=t:3===n&&(e.quad3=t)}n.exports=function(n){function t(){var e=g[m];return e?(e.quad0=null,e.quad1=null,e.quad2=null,e.quad3=null,e.body=null,e.mass=e.massX=e.massY=0,e.left=e.right=e.top=e.bottom=0):(e=new f,g[m]=e),++m,e}function i(e){var n,t,r,o,i=p,a=0,u=0,f=1,c=0,d=1;for(i[0]=y;f;){var v=i[c],g=v.body;f-=1,c+=1;var m=g!==e;g&&m?(t=g.pos.x-e.pos.x,r=g.pos.y-e.pos.y,o=Math.sqrt(t*t+r*r),0===o&&(t=(s.nextDouble()-.5)/50,r=(s.nextDouble()-.5)/50,o=Math.sqrt(t*t+r*r)),n=l*g.mass*e.mass/(o*o*o),a+=n*t,u+=n*r):m&&(t=v.massX/v.mass-e.pos.x,r=v.massY/v.mass-e.pos.y,o=Math.sqrt(t*t+r*r),0===o&&(t=(s.nextDouble()-.5)/50,r=(s.nextDouble()-.5)/50,o=Math.sqrt(t*t+r*r)),(v.right-v.left)/oi&&(i=f),ca&&(a=c)}var d=i-r,l=a-o;for(d>l?a=o+d:i=r+l,m=0,y=t(),y.left=r,y.right=i,y.top=o,y.bottom=a,n=s-1,n>=0&&(y.body=e[n]);n--;)u(e[n],y)}function u(e){for(v.reset(),v.push(y,e);!v.isEmpty();){var n=v.pop(),i=n.node,a=n.body;if(i.body){var u=i.body;if(i.body=null,d(u.pos,a.pos)){var f=3;do{var c=s.nextDouble(),l=(i.right-i.left)*c,p=(i.bottom-i.top)*c;u.pos.x=i.left+l,u.pos.y=i.top+p,f-=1}while(f>0&&d(u.pos,a.pos));if(0===f&&d(u.pos,a.pos))return}v.push(i,u),v.push(i,a)}else{var h=a.pos.x,g=a.pos.y;i.mass=i.mass+a.mass,i.massX=i.massX+a.mass*h,i.massY=i.massY+a.mass*g;var m=0,x=i.left,w=(i.right+x)/2,b=i.top,E=(i.bottom+b)/2;h>w&&(m+=1,x=w,w=i.right),g>E&&(m+=2,b=E,E=i.bottom);var L=r(i,m);L?v.push(L,a):(L=t(),L.left=x,L.top=b,L.right=w,L.bottom=E,L.body=a,o(i,m,L))}}}n=n||{},n.gravity="number"==typeof n.gravity?n.gravity:-1,n.theta="number"==typeof n.theta?n.theta:.8;var s=e("ngraph.random").random(1984),f=e("./node"),c=e("./insertStack"),d=e("./isSamePosition"),l=n.gravity,p=[],v=new c,h=n.theta,g=[],m=0,y=t();return{insertBodies:a,getRoot:function(){return y},updateBodyForce:i,options:function(e){return e?("number"==typeof e.gravity&&(l=e.gravity),"number"==typeof e.theta&&(h=e.theta),this):{gravity:l,theta:h}}}}},{"./insertStack":27,"./isSamePosition":28,"./node":29,"ngraph.random":30}],27:[function(e,n,t){function r(){this.stack=[],this.popIdx=0}function o(e,n){this.node=e,this.body=n}n.exports=r,r.prototype={isEmpty:function(){return 0===this.popIdx},push:function(e,n){var t=this.stack[this.popIdx];t?(t.node=e,t.body=n):this.stack[this.popIdx]=new o(e,n),++this.popIdx},pop:function(){if(this.popIdx>0)return this.stack[--this.popIdx]},reset:function(){this.popIdx=0}}},{}],28:[function(e,n,t){n.exports=function(e,n){var t=Math.abs(e.x-n.x),r=Math.abs(e.y-n.y);return t<1e-8&&r<1e-8}},{}],29:[function(e,n,t){n.exports=function(){this.body=null,this.quad0=null,this.quad1=null,this.quad2=null,this.quad3=null,this.mass=0,this.massX=0,this.massY=0,this.left=0,this.top=0,this.bottom=0,this.right=0}},{}],30:[function(e,n,t){function r(e){var n="number"==typeof e?e:+new Date,t=function(){return n=n+2127912214+(n<<12)&4294967295,n=4294967295&(3345072700^n^n>>>19),n=n+374761393+(n<<5)&4294967295,n=4294967295&(n+3550635116^n<<9),n=n+4251993797+(n<<3)&4294967295,n=4294967295&(3042594569^n^n>>>16),(268435455&n)/268435456};return{next:function(e){return Math.floor(t()*e)},nextDouble:function(){return t()}}}function o(e,n){var t=n||r();if("function"!=typeof t.next)throw new Error("customRandom does not match expected API: next() function is missing");return{forEach:function(n){var r,o,i;for(r=e.length-1;r>0;--r)o=t.next(r+1),i=e[o],e[o]=e[r],e[r]=i,n(i);e.length&&n(e[0])},shuffle:function(){var n,r,o;for(n=e.length-1;n>0;--n)r=t.next(n+1),o=e[r],e[r]=e[n],e[n]=o;return e}}}n.exports={random:r,randomIterator:o}},{}],31:[function(e,n,t){function r(e,n,t){function r(e){u.nodes.push(s(e))}function o(e){u.links.push(f(e))}function i(e){var n={id:e.id};return void 0!==e.data&&(n.data=e.data),n}function a(e){var n={fromId:e.fromId,toId:e.toId};return void 0!==e.data&&(n.data=e.data),n}var u={nodes:[],links:[]},s=n||i,f=t||a;return e.forEachNode(r),e.forEachLink(o),JSON.stringify(u)}n.exports=r},{}],32:[function(e,n,t){function r(e,n){var t=o(e);if(void 0===n)return t;for(var r=Object.keys(n),i=0;iv&&(r=1),u(e,r,{x:e.touches[0].clientX,y:e.touches[0].clientY}),v=t,m(e),y(e)}},j=function(e){p=!1,o.off("touchmove",P),o.off("touchend",j),o.off("touchcancel",j),c=null,r&&r(e)},A=function(e,t){m(e),y(e),d=t.clientX,l=t.clientY,c=e.target||e.srcElement,n&&n(e,{x:d,y:l}),p||(p=!0,o.on("touchmove",P),o.on("touchend",j),o.on("touchcancel",j))},_=function(e){return 1===e.touches.length?A(e,e.touches[0]):void(2===e.touches.length&&(m(e),y(e),v=k(e.touches[0],e.touches[1])))};return e.addEventListener("mousedown",b),e.addEventListener("touchstart",_),{onStart:function(e){return n=e,this},onDrag:function(e){return t=e,this},onStop:function(e){return r=e,this},onScroll:function(e){return N(e),this},release:function(){e.removeEventListener("mousedown",b),e.removeEventListener("touchstart",_),o.off("mousemove",w),o.off("mouseup",E),o.off("touchmove",P),o.off("touchend",j),o.off("touchcancel",j),N(null)}}}n.exports=r;var o=e("../Utils/documentEvents.js"),i=e("../Utils/browserInfo.js"),a=e("../Utils/findElementPosition.js")},{"../Utils/browserInfo.js":43,"../Utils/documentEvents.js":44,"../Utils/findElementPosition.js":45}],40:[function(e,n,t){function r(e,n){var t=o(n),r=null,i={},a={x:0,y:0};return t.mouseDown(function(e,n){r=e,a.x=n.clientX,a.y=n.clientY,t.mouseCapture(r);var o=i[e.id];return o&&o.onStart&&o.onStart(n,a),!0}).mouseUp(function(e){t.releaseMouseCapture(r),r=null;var n=i[e.id];return n&&n.onStop&&n.onStop(),!0}).mouseMove(function(e,n){if(r){var t=i[r.id];return t&&t.onDrag&&t.onDrag(n,{x:n.clientX-a.x,y:n.clientY-a.y}),a.x=n.clientX,a.y=n.clientY,!0}}),{bindDragNDrop:function(e,n){i[e.id]=n,n||delete i[e.id]}}}n.exports=r;var o=e("../WebGL/webglInputEvents.js")},{"../WebGL/webglInputEvents.js":61}],41:[function(e,n,t){function r(e,n){function t(e){return d[e]}n=o(n,{maxX:1024,maxY:1024,seed:"Deterministic randomness made me do this"});var r=i(n.seed),u=new a(Number.MAX_VALUE,Number.MAX_VALUE,Number.MIN_VALUE,Number.MIN_VALUE),s={},f=function(e){return{x:r.next(n.maxX),y:r.next(n.maxY)}},c=function(e,n){e.xn.x2&&(n.x2=e.x),e.yn.y2&&(n.y2=e.y)},d="function"==typeof Object.create?Object.create(null):{},l=function(e){d[e.id]=f(e),c(d[e.id],u)},p=function(){0!==e.getNodesCount()&&(u.x1=Number.MAX_VALUE,u.y1=Number.MAX_VALUE,u.x2=Number.MIN_VALUE,u.y2=Number.MIN_VALUE,e.forEachNode(l))},v=function(e){s[e.id]=e},h=function(e){for(var n=0;n=0:"boolean"!=typeof q||q}function r(){G=G||window.document.body,O=O||i(e,{springLength:80,springCoeff:2e-4}),F=F||a(e,{container:G}),n.hasOwnProperty("renderLinks")||(n.renderLinks=!0),n.prerender=n.prerender||0,U=(F.inputManager||s)(e,F)}function l(){F.beginRender(),n.renderLinks&&F.renderLinks(),F.renderNodes(),F.endRender()}function p(){return X=O.step()&&!V,l(),!X}function v(e){R||(R=void 0!==e?f(function(){if(e-=1,e<0){var n=!1;return n}return p()},M):f(p,M))}function h(){W||(X=!1,R.restart())}function g(){if("number"==typeof n.prerender&&n.prerender>0)for(var e=0;e0?n.insertBefore(r,n.firstChild):n.appendChild(r),r},releaseLink:function(e){var t=d[e.id];t&&(n.removeChild(t),delete d[e.id])},addNode:function(e,t){var r=l(e);if(r)return r.position=t,r.node=e,c[e.id]=r,n.appendChild(r),r},releaseNode:function(e){var t=c[e.id];t&&(n.removeChild(t),delete c[e.id])},renderNodes:function(){for(var e in c)if(c.hasOwnProperty(e)){var n=c[e];m.x=n.position.x,m.y=n.position.y,p(n,m,n.node)}},renderLinks:function(){for(var e in d)if(d.hasOwnProperty(e)){var n=d[e];y.x=n.position.from.x,y.y=n.position.from.y,x.x=n.position.to.x,x.y=n.position.to.y,h(n,y,x,n.link)}},getGraphicsRoot:function(e){return"function"==typeof e&&(t?e(t):r=e),t},getSvgRoot:function(){return t}};return i(b),b}n.exports=r;var o=e("simplesvg"),i=e("ngraph.events"),a=e("../Input/domInputManager.js")},{"../Input/domInputManager.js":38,"ngraph.events":9,simplesvg:32}],54:[function(e,n,t){function r(e){e=c(e,{enableBlending:!0,preserveDrawingBuffer:!1,clearColor:!1,clearColorValue:{r:1,g:1,b:1,a:1}});var n,t,r,d,l,p,v,h,g=0,m=0,y=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],x=[],w=[],b={},E={},L=i(),N=a(),k=function(e){return u()},P=function(e){return s(3014898687)},j=function(){L.updateTransform(y),N.updateTransform(y)},A=function(){y=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]},_=function(){n&&t&&(d=t.width=Math.max(n.offsetWidth,1),l=t.height=Math.max(n.offsetHeight,1),r&&r.viewport(0,0,d,l),L&&L.updateSize(d/2,l/2),N&&N.updateSize(d/2,l/2))},I=function(e){e.fire("rescaled")};t=window.document.createElement("canvas");var T={getLinkUI:function(e){return E[e]},getNodeUI:function(e){return b[e]},node:function(e){if("function"==typeof e)return k=e,this},link:function(e){if("function"==typeof e)return P=e,this},placeNode:function(e){return p=e,this},placeLink:function(e){return v=e,this},inputManager:o,beginRender:function(){},endRender:function(){m>0&&L.render(),g>0&&N.render()},bringLinkToFront:function(e){var n,t,r=L.getFrontLinkId();L.bringToFront(e),r>e.id&&(n=e.id,t=w[r],w[r]=w[n],w[r].id=r,w[n]=t,w[n].id=n)},graphCenterChanged:function(e,n){y[12]=2*e/d-1,y[13]=1-2*n/l,j()},addLink:function(e,n){var t=m++,r=P(e);return r.id=t,r.pos=n,L.createLink(r),w[t]=r,E[e.id]=r,r},addNode:function(e,n){var t=g++,r=k(e);return r.id=t,r.position=n,r.node=e,N.createNode(r),x[t]=r,b[e.id]=r,r},translateRel:function(e,n){y[12]+=2*y[0]*e/d/y[0],y[13]-=2*y[5]*n/l/y[5],j()},scale:function(e,n){var t=2*n.x/d-1,r=1-2*n.y/l;return t-=y[12],r-=y[13],y[12]+=t*(1-e),y[13]+=r*(1-e),y[0]*=e,y[5]*=e,j(),I(this),y[0]},resetScale:function(){return A(),r&&(_(),j()),this},updateSize:_,init:function(o){var i={};if(e.preserveDrawingBuffer&&(i.preserveDrawingBuffer=!0),n=o,_(),A(),n.appendChild(t),r=t.getContext("experimental-webgl",i),!r){var a="Could not initialize WebGL. Seems like the browser doesn't support it.";throw window.alert(a),a}if(e.enableBlending&&(r.blendFunc(r.SRC_ALPHA,r.ONE_MINUS_SRC_ALPHA),r.enable(r.BLEND)),e.clearColor){var u=e.clearColorValue;r.clearColor(u.r,u.g,u.b,u.a),this.beginRender=function(){r.clear(r.COLOR_BUFFER_BIT)}}L.load(r),L.updateSize(d/2,l/2),N.load(r),N.updateSize(d/2,l/2),j(),"function"==typeof h&&h(t)},release:function(e){t&&e&&e.removeChild(t)},isSupported:function(){var e=window.document.createElement("canvas"),n=e&&e.getContext&&e.getContext("experimental-webgl");return n},releaseLink:function(e){m>0&&(m-=1);var n=E[e.id];delete E[e.id],L.removeLink(n);var t=n.id;if(t0&&(g-=1);var n=b[e.id];delete b[e.id],N.removeNode(n);var t=n.id;if(te.length){var r=new Float32Array(e.length*t*2);return r.set(e),r}return e}function a(n,t){for(var r={},o=0;o=w.length&&s();var i=w[r.textureNumber];i.ctx.drawImage(n,r.col*g,r.row*g,g,g),b[e]=n.src,y[n.src]=o,i.isDirty=!0,t(o)}function c(n){var t=n/e<<0,r=n%e,o=r/h<<0,i=r%h;return{textureNumber:t,row:o,col:i}}function d(){E.isDirty=!0,x=0,v=null}function l(){v&&(window.clearTimeout(v),x+=1,v=null),x>10?d():v=window.setTimeout(d,400)}function p(e,n){var t=w[e.textureNumber].canvas,r=w[n.textureNumber].ctx,o=n.col*g,i=n.row*g;r.drawImage(t,e.col*g,e.row*g,g,g,o,i,g,g),w[e.textureNumber].isDirty=!0,w[n.textureNumber].isDirty=!0}var v,h=Math.sqrt(e||1024)<<0,g=h,m=1,y={},x=0,w=[],b=[];if(!o(e))throw"Tiles per texture should be power of two.";var E={isDirty:!1,clearDirty:n,remove:t,getTextures:r,getCoordinates:a,load:u};return E}function o(e){return 0===(e&e-1)}var i=e("./texture.js");n.exports=r},{"./texture.js":56}],59:[function(e,n,t){function r(e,n){return{_texture:0,_offset:0,size:"number"==typeof e?e:32,src:n}}n.exports=r},{}],60:[function(e,n,t){function r(){function e(e,n){e.nativeObject&&g.deleteTexture(e.nativeObject);var t=g.createTexture();g.activeTexture(g["TEXTURE"+n]),g.bindTexture(g.TEXTURE_2D,t),g.texImage2D(g.TEXTURE_2D,0,g.RGBA,g.RGBA,g.UNSIGNED_BYTE,e.canvas),g.texParameteri(g.TEXTURE_2D,g.TEXTURE_MAG_FILTER,g.LINEAR),g.texParameteri(g.TEXTURE_2D,g.TEXTURE_MIN_FILTER,g.LINEAR_MIPMAP_NEAREST),g.generateMipmap(g.TEXTURE_2D),g.uniform1i(x["sampler"+n],n),e.nativeObject=t}function n(){if(v.isDirty){var n,t=v.getTextures();for(n=0;n0&&(A-=1),e.id0&&(e.src&&v.remove(e.src),y.copyArrayPart(_,e.id*N,A*N,N))}function c(e,n){n._offset=e._offset}function d(e){L=!0,E=e}function l(e,n){w=e,b=n,L=!0}function p(){g.useProgram(h),g.bindBuffer(g.ARRAY_BUFFER,m),g.bufferData(g.ARRAY_BUFFER,_,g.DYNAMIC_DRAW),L&&(L=!1,g.uniformMatrix4fv(x.transform,!1,E),g.uniform2f(x.screenSize,w,b)),g.vertexAttribPointer(x.vertexPos,2,g.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,0),g.vertexAttribPointer(x.customAttributes,1,g.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,8),n(),g.drawArrays(g.TRIANGLES,0,6*A)}var v,h,g,m,y,x,w,b,E,L,N=18,k=o(),P=i(),j=1024,A=0,_=new Float32Array(64);return{load:t,position:r,createNode:s,removeNode:f,replaceProperties:c,updateTransform:d,updateSize:l,render:p}}function o(){return["precision mediump float;","varying vec4 color;","varying vec3 vTextureCoord;","uniform sampler2D u_sampler0;","uniform sampler2D u_sampler1;","uniform sampler2D u_sampler2;","uniform sampler2D u_sampler3;","void main(void) {"," if (vTextureCoord.z == 0.) {"," gl_FragColor = texture2D(u_sampler0, vTextureCoord.xy);"," } else if (vTextureCoord.z == 1.) {"," gl_FragColor = texture2D(u_sampler1, vTextureCoord.xy);"," } else if (vTextureCoord.z == 2.) {"," gl_FragColor = texture2D(u_sampler2, vTextureCoord.xy);"," } else if (vTextureCoord.z == 3.) {"," gl_FragColor = texture2D(u_sampler3, vTextureCoord.xy);"," } else { gl_FragColor = vec4(0, 1, 0, 1); }","}"].join("\n")}function i(){return["attribute vec2 a_vertexPos;","attribute float a_customAttributes;","uniform vec2 u_screenSize;","uniform mat4 u_transform;","uniform float u_tilesPerTexture;","varying vec3 vTextureCoord;","void main(void) {"," gl_Position = u_transform * vec4(a_vertexPos/u_screenSize, 0, 1);","float corner = mod(a_customAttributes, 4.);","float tileIndex = mod(floor(a_customAttributes / 4.), u_tilesPerTexture);","float tilesPerRow = sqrt(u_tilesPerTexture);","float tileSize = 1./tilesPerRow;","float tileColumn = mod(tileIndex, tilesPerRow);","float tileRow = floor(tileIndex/tilesPerRow);","if(corner == 0.0) {"," vTextureCoord.xy = vec2(0, 1);","} else if(corner == 1.0) {"," vTextureCoord.xy = vec2(1, 1);","} else if(corner == 2.0) {"," vTextureCoord.xy = vec2(0, 0);","} else {"," vTextureCoord.xy = vec2(1, 0);","}","vTextureCoord *= tileSize;","vTextureCoord.x += tileColumn * tileSize;","vTextureCoord.y += tileRow * tileSize;","vTextureCoord.z = floor(floor(a_customAttributes / 4.)/u_tilesPerTexture);","}"].join("\n")}var a=e("./webglAtlas.js"),u=e("./webgl.js");n.exports=r},{"./webgl.js":57,"./webglAtlas.js":58}],61:[function(e,n,t){function r(e){function n(){x=null}function t(e){x=e}function r(e){return"function"==typeof e&&P.push(e),A}function i(e){return"function"==typeof e&&k.push(e),A}function a(e){return"function"==typeof e&&N.push(e),A}function u(e){return"function"==typeof e&&L.push(e),A}function s(e){return"function"==typeof e&&E.push(e),A}function f(e){return"function"==typeof e&&b.push(e),A}function c(e){return"function"==typeof e&&w.push(e),A}function d(e,n,t){if(e&&e.size){var r=e.position,o=e.size;return r.x-og.byteLength){var e=new ArrayBuffer(2*g.byteLength),n=new Float32Array(e),t=new Uint32Array(e);t.set(y),m=n,y=t,g=e}};return{load:function(a){n=a,r=o(a),e=r.createProgram(v,p),n.useProgram(e),i=r.getLocations(e,["a_vertexPos","a_color","u_screenSize","u_transform"]),n.enableVertexAttribArray(i.vertexPos),n.enableVertexAttribArray(i.color),t=n.createBuffer()},position:function(e,n,t){var r=e.id,o=r*d;m[o]=n.x,m[o+1]=n.y,y[o+2]=e.color,m[o+3]=t.x,m[o+4]=t.y,y[o+5]=e.color},createLink:function(e){x(),h+=1,a=e.id},removeLink:function(e){h>0&&(h-=1),e.id0&&r.copyArrayPart(y,e.id*d,h*d,d)},updateTransform:function(e){c=!0,f=e},updateSize:function(e,n){u=e,s=n,c=!0},render:function(){n.useProgram(e),n.bindBuffer(n.ARRAY_BUFFER,t),n.bufferData(n.ARRAY_BUFFER,g,n.DYNAMIC_DRAW),c&&(c=!1,n.uniformMatrix4fv(i.transform,!1,f),n.uniform2f(i.screenSize,u,s)),n.vertexAttribPointer(i.vertexPos,2,n.FLOAT,!1,3*Float32Array.BYTES_PER_ELEMENT,0),n.vertexAttribPointer(i.color,4,n.UNSIGNED_BYTE,!0,3*Float32Array.BYTES_PER_ELEMENT,8),n.drawArrays(n.LINES,0,2*h),a=h-1},bringToFront:function(e){a>e.id&&r.swapArrayPart(m,e.id*d,a*d,d),a>0&&(a-=1)},getFrontLinkId:function(){return a}}}var o=e("./webgl.js");n.exports=r},{"./webgl.js":57}],64:[function(e,n,t){function r(){function e(){if((P+1)*w>=L.byteLength){var e=new ArrayBuffer(2*L.byteLength),n=new Float32Array(e),t=new Uint32Array(e);t.set(k),N=n,k=t,L=e}}function n(e){d=e,v=o(e),c=v.createProgram(E,b),d.useProgram(c),p=v.getLocations(c,["a_vertexPos","a_color","u_screenSize","u_transform"]), 3 | d.enableVertexAttribArray(p.vertexPos),d.enableVertexAttribArray(p.color),l=d.createBuffer()}function t(e,n){var t=e.id;N[t*x]=n.x,N[t*x+1]=-n.y,N[t*x+2]=e.size,k[t*x+3]=e.color}function r(e){y=!0,m=e}function i(e,n){h=e,g=n,y=!0}function a(e){P>0&&(P-=1),e.id0&&v.copyArrayPart(k,e.id*x,P*x,x)}function u(){e(),P+=1}function s(){}function f(){d.useProgram(c),d.bindBuffer(d.ARRAY_BUFFER,l),d.bufferData(d.ARRAY_BUFFER,L,d.DYNAMIC_DRAW),y&&(y=!1,d.uniformMatrix4fv(p.transform,!1,m),d.uniform2f(p.screenSize,h,g)),d.vertexAttribPointer(p.vertexPos,3,d.FLOAT,!1,x*Float32Array.BYTES_PER_ELEMENT,0),d.vertexAttribPointer(p.color,4,d.UNSIGNED_BYTE,!0,x*Float32Array.BYTES_PER_ELEMENT,12),d.drawArrays(d.POINTS,0,P)}var c,d,l,p,v,h,g,m,y,x=4,w=3*Float32Array.BYTES_PER_ELEMENT+Uint32Array.BYTES_PER_ELEMENT,b=["precision mediump float;","varying vec4 color;","void main(void) {"," gl_FragColor = color;","}"].join("\n"),E=["attribute vec3 a_vertexPos;","attribute vec4 a_color;","uniform vec2 u_screenSize;","uniform mat4 u_transform;","varying vec4 color;","void main(void) {"," gl_Position = u_transform * vec4(a_vertexPos.xy/u_screenSize, 0, 1);"," gl_PointSize = a_vertexPos.z * u_transform[0][0];"," color = a_color.abgr;","}"].join("\n"),L=new ArrayBuffer(16*w),N=new Float32Array(L),k=new Uint32Array(L),P=0;return{load:n,position:t,updateTransform:r,updateSize:i,removeNode:a,createNode:u,replaceProperties:s,render:f}}var o=e("./webgl.js");n.exports=r},{"./webgl.js":57}],65:[function(e,n,t){function r(e,n){return{size:"number"==typeof e?e:10,color:o(n)}}var o=e("./parseColor.js");n.exports=r},{"./parseColor.js":55}],66:[function(e,n,t){n.exports="0.8.1"},{}]},{},[1])(1)}); --------------------------------------------------------------------------------