Splits the mocha tests into individual files

This commit is contained in:
Zachary Boyd 2018-09-09 02:59:38 -04:00
parent a74409ddb7
commit 1c29679024
15 changed files with 1391 additions and 998 deletions

View file

@ -5,6 +5,7 @@
### Changes
- All methods now return promises instead of accepting callbacks. Methods now take advantage of async/await to increase readability.
- The `logger` argument to the constructor's of all classes is now optional
- The mocha test has been split into individual files
### Removes
- The `new_ips` and `new_ip_at` TorPool and `new_ip` TorProcess have been removed. Use `new_identites`, `new_identity_at` and `new_identity` instead.

483
package-lock.json generated
View file

@ -16,9 +16,10 @@
"integrity": "sha512-2whhQUfDHRBiZ3L54Ulyl1X+fZWbWabxPYRDAsibgOAtE6adwusD15Xv0Bw/D7cPah35Z/wKTdW3iAKsevw1uw=="
},
"agent-base": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz",
"integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==",
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
"integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
"dev": true,
"requires": {
"es6-promisify": "^5.0.0"
}
@ -64,6 +65,18 @@
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"assertion-error": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true
},
"ast-types": {
"version": "0.11.5",
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.5.tgz",
"integrity": "sha512-oJjo+5e7/vEc2FBK8gUalV0pba4L3VdBIs2EKhOLHLcOd2FgQIVQN9xb0eZ9IjEWyAL7vq6fGJxOvVvdCHNyMw==",
"dev": true
},
"async": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",
@ -147,6 +160,12 @@
"verror": "^1.4.0"
}
},
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
"dev": true
},
"camelcase": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
@ -158,6 +177,26 @@
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true
},
"chai": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz",
"integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=",
"dev": true,
"requires": {
"assertion-error": "^1.0.1",
"check-error": "^1.0.1",
"deep-eql": "^3.0.0",
"get-func-name": "^2.0.0",
"pathval": "^1.0.0",
"type-detect": "^4.0.0"
}
},
"check-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
"dev": true
},
"cheerio": {
"version": "1.0.0-rc.2",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz",
@ -369,6 +408,12 @@
"assert-plus": "^1.0.0"
}
},
"data-uri-to-buffer": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz",
"integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==",
"dev": true
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
@ -383,6 +428,32 @@
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
"deep-eql": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
"dev": true,
"requires": {
"type-detect": "^4.0.0"
}
},
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
"dev": true
},
"degenerator": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz",
"integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=",
"dev": true,
"requires": {
"ast-types": "0.x.x",
"escodegen": "1.x.x",
"esprima": "3.x.x"
}
},
"del": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz",
@ -402,6 +473,12 @@
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
"dev": true
},
"diagnostics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.0.tgz",
@ -487,12 +564,14 @@
"es6-promise": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz",
"integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ=="
"integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==",
"dev": true
},
"es6-promisify": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
"dev": true,
"requires": {
"es6-promise": "^4.0.3"
}
@ -503,6 +582,37 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"escodegen": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz",
"integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==",
"dev": true,
"requires": {
"esprima": "^3.1.3",
"estraverse": "^4.2.0",
"esutils": "^2.0.2",
"optionator": "^0.8.1",
"source-map": "~0.6.1"
}
},
"esprima": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
"integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
"dev": true
},
"estraverse": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
"dev": true
},
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
"dev": true
},
"eventemitter3": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
@ -550,11 +660,23 @@
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
"dev": true
},
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
"fecha": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
"integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg=="
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"dev": true
},
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
@ -603,11 +725,53 @@
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"ftp": {
"version": "0.3.10",
"resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz",
"integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=",
"dev": true,
"requires": {
"readable-stream": "1.1.x",
"xregexp": "2.0.0"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
"dev": true
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"dev": true
}
}
},
"get-caller-file": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
"integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U="
},
"get-func-name": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
"dev": true
},
"get-port": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/get-port/-/get-port-2.1.0.tgz",
@ -621,6 +785,31 @@
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
},
"get-uri": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.2.tgz",
"integrity": "sha512-ZD325dMZOgerGqF/rF6vZXyFGTAay62svjQIT+X/oU2PtxYpFxvSkbsdi+oxIrsNxlZVd4y8wUDqkaExWTI/Cw==",
"dev": true,
"requires": {
"data-uri-to-buffer": "1",
"debug": "2",
"extend": "3",
"file-uri-to-path": "1",
"ftp": "~0.3.10",
"readable-stream": "2"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
}
}
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
@ -745,6 +934,28 @@
"readable-stream": "^2.0.2"
}
},
"http-errors": {
"version": "1.6.3",
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"dev": true,
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.0",
"statuses": ">= 1.4.0 < 2"
}
},
"http-proxy-agent": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
"integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
"dev": true,
"requires": {
"agent-base": "4",
"debug": "3.1.0"
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@ -756,6 +967,25 @@
"sshpk": "^1.7.0"
}
},
"https-proxy-agent": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
"integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
"dev": true,
"requires": {
"agent-base": "^4.1.0",
"debug": "^3.1.0"
}
},
"iconv-lite": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
"dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -788,7 +1018,8 @@
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
"dev": true
},
"ipaddr.js": {
"version": "0.1.9",
@ -940,6 +1171,16 @@
"invert-kv": "^1.0.0"
}
},
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"dev": true,
"requires": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
}
},
"locate-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
@ -1187,6 +1428,12 @@
"integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=",
"optional": true
},
"netmask": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz",
"integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=",
"dev": true
},
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@ -1232,6 +1479,20 @@
"resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz",
"integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4="
},
"optionator": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
"integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
"dev": true,
"requires": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.4",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"wordwrap": "~1.0.0"
}
},
"os-locale": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
@ -1278,6 +1539,47 @@
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
},
"pac-proxy-agent": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-2.0.2.tgz",
"integrity": "sha512-cDNAN1Ehjbf5EHkNY5qnRhGPUCp6SnpyVof5fRzN800QV1Y2OkzbH9rmjZkbBRa8igof903yOnjIl6z0SlAhxA==",
"dev": true,
"requires": {
"agent-base": "^4.2.0",
"debug": "^3.1.0",
"get-uri": "^2.0.0",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.1",
"pac-resolver": "^3.0.0",
"raw-body": "^2.2.0",
"socks-proxy-agent": "^3.0.0"
},
"dependencies": {
"socks-proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz",
"integrity": "sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA==",
"dev": true,
"requires": {
"agent-base": "^4.1.0",
"socks": "^1.1.10"
}
}
}
},
"pac-resolver": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz",
"integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==",
"dev": true,
"requires": {
"co": "^4.6.0",
"degenerator": "^1.0.4",
"ip": "^1.1.5",
"netmask": "^1.0.6",
"thunkify": "^2.1.2"
}
},
"parse5": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
@ -1311,6 +1613,12 @@
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
"integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
},
"pathval": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
"dev": true
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@ -1340,11 +1648,39 @@
"resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz",
"integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE="
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"dev": true
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.0.1.tgz",
"integrity": "sha512-mAZexaz9ZxQhYPWfAjzlrloEjW+JHiBFryE4AJXFDTnaXfmH/FKqC1swTRKuEPbHWz02flQNXFOyDUF7zfEG6A==",
"dev": true,
"requires": {
"agent-base": "^4.2.0",
"debug": "^3.1.0",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.1",
"lru-cache": "^4.1.2",
"pac-proxy-agent": "^2.0.1",
"proxy-from-env": "^1.0.0",
"socks-proxy-agent": "^4.0.1"
}
},
"proxy-from-env": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
"integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=",
"dev": true
},
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
@ -1353,8 +1689,7 @@
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
},
"qs": {
"version": "6.5.2",
@ -1362,6 +1697,18 @@
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
"dev": true
},
"raw-body": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz",
"integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==",
"dev": true,
"requires": {
"bytes": "3.0.0",
"http-errors": "1.6.3",
"iconv-lite": "0.4.23",
"unpipe": "1.0.0"
}
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
@ -1414,6 +1761,25 @@
"uuid": "^3.1.0"
}
},
"request-promise": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
"integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=",
"requires": {
"bluebird": "^3.5.0",
"request-promise-core": "1.1.1",
"stealthy-require": "^1.1.0",
"tough-cookie": ">=2.3.3"
}
},
"request-promise-core": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
"integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
"requires": {
"lodash": "^4.13.1"
}
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@ -1442,6 +1808,12 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"secure-keys": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz",
@ -1457,6 +1829,12 @@
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
"dev": true
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
@ -1488,7 +1866,8 @@
"smart-buffer": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz",
"integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY="
"integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=",
"dev": true
},
"sntp": {
"version": "2.1.0",
@ -1503,18 +1882,38 @@
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz",
"integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=",
"dev": true,
"requires": {
"ip": "^1.1.4",
"smart-buffer": "^1.0.13"
}
},
"socks-proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz",
"integrity": "sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz",
"integrity": "sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw==",
"dev": true,
"requires": {
"agent-base": "^4.1.0",
"socks": "^1.1.10"
"agent-base": "~4.2.0",
"socks": "~2.2.0"
},
"dependencies": {
"smart-buffer": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.1.tgz",
"integrity": "sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg==",
"dev": true
},
"socks": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.2.1.tgz",
"integrity": "sha512-0GabKw7n9mI46vcNrVfs0o6XzWzjVa3h6GaSo2UPxtWAROXUWavfJWh1M4PR5tnE0dcnQXZIDFP4yrAysLze/w==",
"dev": true,
"requires": {
"ip": "^1.1.5",
"smart-buffer": "^4.0.1"
}
}
}
},
"socksv5": {
@ -1541,6 +1940,13 @@
}
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"optional": true
},
"sshpk": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz",
@ -1562,6 +1968,17 @@
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
"dev": true
},
"stealthy-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
@ -1621,11 +2038,16 @@
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-0.0.0.tgz",
"integrity": "sha1-V4+8haapJjbkLdF7QdAhjM6esrM="
},
"thunkify": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz",
"integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=",
"dev": true
},
"tough-cookie": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
"dev": true,
"requires": {
"punycode": "^1.4.1"
}
@ -1651,6 +2073,27 @@
"dev": true,
"optional": true
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"dev": true,
"requires": {
"prelude-ls": "~1.1.2"
}
},
"type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
"dev": true
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
"dev": true
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -1710,6 +2153,12 @@
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-3.2.1.tgz",
"integrity": "sha512-WPqbdAmMK/kfWCWKM2bA1o997wWPZ0jg5NpO8JPqoaDZgCiZnFpIEddcf7Ur4UZV2sYRUdySVBWKx0+gQQ/jrg=="
},
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
@ -1757,6 +2206,12 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xregexp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz",
"integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=",
"dev": true
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",

View file

@ -11,12 +11,15 @@
},
"scripts": {
"start": "bin/tor-router -s -d -j 1",
"test": "mocha --exit test/test.js",
"test": "mocha --exit test/index.js",
"debug": "node --inspect-brk bin/tor-router"
},
"devDependencies": {
"chai": "^4.1.2",
"mocha": "^5.2.0",
"request": "^2.79.0"
"proxy-agent": "^3.0.1",
"request": "^2.79.0",
"request-promise": "^4.2.2"
},
"dependencies": {
"async": "^2.1.4",
@ -32,7 +35,6 @@
"native-dns": "git+https://github.com/znetstar/node-dns.git",
"nconf": "^0.10.0",
"shelljs": "^0.8.2",
"socks-proxy-agent": "^3.0.1",
"socksv5": "git+https://github.com/lee-elenbaas/socksv5.git",
"temp": "^0.8.3",
"winston": "^3.0.0-rc5",

View file

@ -110,7 +110,7 @@ class ControlServer {
server.expose('signalInstanceByName', this.torPool.signal_by_name.bind(this.torPool));
}
listen(port) {
async listen(port) {
this.tcpTransport = new rpc.tcpTransport({ port });
this.tcpTransport.listen(this.server);
}

View file

@ -1,4 +1,6 @@
module.exports = require('winston').createLogger({
const winston = require('winston');
module.exports = winston.createLogger({
level: 'info',
format: winston.format.simple(),
silent: true,

64
test/ControlServer.js Normal file
View file

@ -0,0 +1,64 @@
const _ = require('lodash');
const assert = require('chai').assert;
const rpc = require('jrpc2');
const Promise = require('bluebird');
const nconf = require('nconf');
const logger = require('../src/winston-silent-logger');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
const { ControlServer } = require('../');
let controlServer = new ControlServer(logger, nconf);
let controlPort;
describe('ControlServer', function () {
describe('#listen(port)', function () {
it('should bind to a given port', async function () {
controlPort = await getPort();
await controlServer.listen(controlPort);
});
});
describe('#createTorPool(options)', function () {
it('should create a TorPool with a given configuration', function () {
let torPool = controlServer.createTorPool({ ProtocolWarnings: 1 });
assert.ok((controlServer.torPool instanceof (TorRouter.TorPool)));
assert.equal(1, torPool.default_tor_config.ProtocolWarnings);
});
});
describe('#createSOCKSServer(port)', function () {
it('should create a SOCKS Server', async function () {
let port = await getPort();
controlServer.createSOCKSServer(port);
assert.instanceOf(controlServer.socksServer, SOCKSServer);
});
});
describe('#createDNSServer(port)', function () {
it('should create a DNS Server', async function () {
let port = await getPort();
controlServer.createDNSServer(port);
assert.instanceOf(controlServer.dnsServer, DNSServer);
});
});
describe('#createHTTPServer(port)', function () {
it('should create a HTTP Server', async function () {
let port = await getPort();
controlServer.createHTTPServer(port);
assert.instanceOf(controlServer.httpServer, HTTPServer);
});
});
describe('#close()', function () {
it('should close the RPC Server', function () {
controlServer.close();
});
});
after('shutdown tor pool', async function () {
await controlServer.torPool.exit();
});
});
require('./RPCServer');

53
test/DNSServer.js Normal file
View file

@ -0,0 +1,53 @@
const nconf = require('nconf');
const getPort = require('get-port');
const dns = require('native-dns');
const logger = require('../src/winston-silent-logger');
const { TorPool, DNSServer } = require('../');
const { WAIT_FOR_CREATE } = require('./constants');
let dnsServerTorPool;
let dnsServer;
describe('DNSServer', function () {
dnsServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
dnsServer = new DNSServer(dnsServerTorPool, {}, 10000, logger);
let dnsPort;
before('start up server', async function (){
this.timeout(WAIT_FOR_CREATE);
await dnsServerTorPool.create(1);
dnsPort = await getPort();
dnsServer.serve(dnsPort);
});
describe('#handle_dns_request(req, res)', function () {
it('should service a request for example.com', function (done) {
this.timeout(10000);
let req = dns.Request({
question: dns.Question({
name: 'example.com',
type: 'A'
}),
server: { address: '127.0.0.1', port: dnsPort, type: 'udp' },
timeout: 1000,
});
req.on('timeout', function () {
done(new Error('Connection timed out'));
});
req.on('message', function () {
done();
});
req.send();
});
});
after('shutdown tor pool', async function () {
await dnsServerTorPool.exit();
});
});

53
test/HTTPServer.js Normal file
View file

@ -0,0 +1,53 @@
const nconf = require('nconf');
const request = require('request-promise');
const getPort = require('get-port');
const ProxyAgent = require('proxy-agent');
const logger = require('../src/winston-silent-logger');
const { TorPool, HTTPServer } = require('../');
const { WAIT_FOR_CREATE, PAGE_LOAD_TIME } = require('./constants');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
let httpServerTorPool;
let httpServer;
describe('HTTPServer', function () {
httpServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
httpServer = new HTTPServer(httpServerTorPool, logger);
let httpPort;
before('start up server', async function (){
this.timeout(WAIT_FOR_CREATE);
await httpServerTorPool.create(1);
httpPort = await getPort();
httpServer.listen(httpPort);
});
describe('#handle_http_connections(req, res)', function () {
it('should service a request for example.com', async function () {
this.timeout(PAGE_LOAD_TIME);
await request({
url: 'http://example.com',
agent: new ProxyAgent(`http://localhost:${httpPort}`)
});
});
});
describe('#handle_connect_connections(req, inbound_socket, head)', function () {
it('should service a request for example.com', async function () {
this.timeout(PAGE_LOAD_TIME);
await request({
url: 'https://example.com',
agent: new ProxyAgent(`http://localhost:${httpPort}`)
});
});
});
after('shutdown tor pool', async function () {
await httpServerTorPool.exit();
});
});

349
test/RPCServer.js Normal file
View file

@ -0,0 +1,349 @@
const _ = require('lodash');
const assert = require('chai').assert;
const rpc = require('jrpc2');
const Promise = require('bluebird');
const nconf = require('nconf');
const rpc = require('jrpc2');
const logger = require('../src/winston-silent-logger');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
const { ControlServer } = require('../');
let rpcControlServer = new ControlServer(logger, nconf);
let rpcControlPort;
let rpcClient;
describe('ControlServer - RPC', function () {
before('setup control server', async function () {
rpcControlPort = await getPort();
await rpcControlServer.listen(rpcControlPort);
rpcClient = new rpc.Client(new rpc.tcpTransport({ port: rpcControlPort, hostname: 'localhost' }));
Promise.promisifyAll(rpcClient);
});
describe('#createInstances(number_of_instances)', function () {
this.timeout(WAIT_FOR_CREATE*2);
it('should create an instance', async function () {
await rpcClient.invokeAsync('createInstances', [2]);
});
});
describe('#queryInstances()', function () {
this.timeout(3000);
it('should return a list of instances', async function () {
let raw = await rpcClient.invokeAsync('queryInstances', []);
var instances = JSON.parse(raw).result;
assert.isArray(instances, 'Did not return an array');
assert.isNotEmpty(instances);
assert.isTrue(instances.every((instance) => ( typeof(instance.name) !== 'undefined' ) && ( instance.name !== null )));
});
});
describe('#addInstances(definitions)', function () {
this.timeout(WAIT_FOR_CREATE);
it("should add an instance based on a defintion", async function () {
var def = {
Name: 'instance-1'
};
await rpcClient.invokeAsync('addInstances', [ [ def ] ]);
});
it("tor pool should now contain and instance that has the same name as the name specified in the defintion", function () {
assert.ok(rpcControlServer.torPool.instance_by_name('instance-1'));
});
});
describe('#queryInstanceByName(instance_name)', function () {
this.timeout(3000);
it('should return a single instance by name', async function () {
let raw = await rpcClient.invokeAsync('queryInstanceByName', ['instance-1']);
var instance = JSON.parse(raw).result;
assert.isOk(instance);
});
});
describe('#queryInstanceAt(index)', function () {
this.timeout(3000);
it('should return a single instance by index', async function () {
let raw = await rpcClient.invokeAsync('queryInstanceAt', [0]);
var instance = JSON.parse(raw).result;
assert.isOk(instance);
});
});
describe('#newIdentites()', function () {
this.timeout(3000);
it('should request new identities for all instances', async function () {
await rpcClient.invokeAsync('newIdentites', []);
});
});
describe('#newIdentityByName(instance_name)', function () {
this.timeout(3000);
it('should request new identities for all instances', async function () {
await rpcClient.invokeAsync('newIdentityByName', ['instance-1']);
});
});
describe('#newIdentityAt(index)', function () {
this.timeout(3000);
it('should request new identities for all instances', async function () {
await rpcClient.invokeAsync('newIdentityAt', [0]);
});
});
describe("#setTorConfig(config_object)", function () {
this.timeout(3000);
it('should set several config variables on all instances', async function () {
await rpcClient.invokeAsync('setTorConfig', [ { TestSocks: 1, ProtocolWarnings: 1 } ]);
});
it('all instances should have the modified variables', async function() {
await Promise.all(rpcControlServer.torPool.instances.map(async (instance) => {
let var1 = await instance.get_config('TestSocks');
let var2 = await instance.get_config('ProtocolWarnings');
assert.equal(var1, 1);
assert.equal(var2, 1);
}));
});
after('unset config variables', async function () {
await rpcControlServer.torPool.set_config_all('TestSocks', 0);
await rpcControlServer.torPool.set_config_all('ProtocolWarnings', 0);
});
});
describe('#setDefaultTorConfig(object)', function () {
it('should set the default config of new instances', async function () {
this.timeout(3000);
await rpcClient.invokeAsync('setDefaultTorConfig', [ { TestSocks: 1 } ]);
});
it('a new instance should be created with the modified property', async function () {
this.timeout(WAIT_FOR_CREATE);
await rpcControlServer.torPool.create_instance({ Name: 'config-test' });
let value = await rpcControlServer.torPool.instance_by_name('config-test').get_config('TestSocks');
assert.equal(value, 1);
});
after('remove instance', async function () {
this.timeout(10000);
nconf.set('torConfig', {});
await rpcControlServer.torPool.remove_by_name('config-test');
});
});
describe('#getDefaultTorConfig()', function () {
before('set tor config', function () {
nconf.set('torConfig', { TestSocks: 1 });
});
it('should return a tor config with a modified property', async function () {
this.timeout(3000);
let raw = await rpcClient.invokeAsync('getDefaultTorConfig', [ { } ]);
let config = JSON.parse(raw).result;
assert.equal(config.TestSocks, 1);
});
after('unset property', function () {
nconf.set('torConfig', {});
});
});
describe('#getLoadBalanceMethod()', function () {
this.timeout(3000);
before(function () {
rpcControlServer.torPool.load_balance_method = 'round_robin';
});
it('should return the current load balance method', async function () {
let raw = await rpcClient.invokeAsync('getLoadBalanceMethod', []);
let lb_method = JSON.parse(raw).result;
assert.equal(lb_method, 'round_robin');
});
});
describe('#setLoadBalanceMethod(load_balance_method)', function () {
this.timeout(3000);
it('should set the load balance method', async function () {
await rpcClient.invokeAsync('setLoadBalanceMethod', ['weighted']);
});
it('the load balance method should be changed', function () {
assert.equal(rpcControlServer.torPool.load_balance_method, 'weighted');
});
after(function () {
rpcControlServer.torPool.load_balance_method = 'round_robin';
});
});
describe("#getInstanceConfigByName(instance_name)", function () {
this.timeout(3000);
before('set config property', async function () {
await rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 1);
});
it('should retrieve the property from the tor instance', async function (done) {
let raw = await rpcClient.invokeAsync('getInstanceConfigByName', ['instance-1']);
let value = JSON.parse(raw).result;
assert.equal(value, 1);
});
after('unset config property', async function () {
await rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0);
});
});
describe("#getInstanceConfigAt(index)", function () {
this.timeout(3000);
before('set config property', async function () {
await rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 1);
});
it('should retrieve the property from the tor instance', async function () {
let raw = await rpcClient.invokeAsync('getInstanceConfigByName', [0]);
let value = JSON.parse(raw).result;
assert.equal(value, 1);
});
after('unset config property', async function () {
await rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0);
});
});
describe("#setInstanceConfigByName(instance_name)", function () {
this.timeout(3000);
before('set config property', async function () {
await rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0);
});
it('should set the property for the tor instance', async function () {
await rpcClient.invokeAsync('setInstanceConfigByName', ['instance-1', 'TestSocks', 1]);
});
it('tor instance should have the modified property', async function () {
let value = await rpcControlServer.torPool.instance_by_name('instance-1').get_config('TestSocks');
assert.equal(value, 1);
});
after('unset config property', async function () {
await rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0);
});
});
describe("#setInstanceConfigAt(index)", function () {
this.timeout(3000);
before('set config property', async function () {
await rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0);
});
it('should set the property for the tor instance', async function () {
await rpcClient.invokeAsync('setInstanceConfigAt', [0, 'TestSocks', 1]);
});
it('tor instance should have the modified property', async function () {
let value = await rpcControlServer.torPool.instance_at(0).get_config('TestSocks');
assert.equal(value, 1);
});
after('unset config property', async function () {
await rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0);
});
});
describe('#signalAllInstances(signal)', function () {
this.timeout(3000);
it('should signal to all interfaces', async function () {
await rpcClient.invokeAsync('signalAllInstances', [ 'DEBUG' ]);
});
});
describe('#signalInstanceAt(signal)', function () {
this.timeout(3000);
it('should signal to all interfaces', async function () {
await rpcClient.invokeAsync('signalInstanceAt', [ 0, 'DEBUG' ]);
});
});
describe('#signalAllInstances(signal)', function () {
this.timeout(3000);
it('should signal to all interfaces', async function () {
await rpcClient.invokeAsync('signalInstanceByName', [ 'instance-1', 'DEBUG' ]);
});
});
describe("#nextInstance()", function () {
this.timeout(3000);
let instance_name;
it('should rotate the 0th item in the instances array', async function () {
instance_name = rpcControlServer.torPool.instances[0].instance_name;
await rpcClient.invokeAsync('nextInstance', []);
});
it('0th item in the instances array should be different after nextInstance is called', function () {
assert.notEqual(rpcControlServer.torPool.instances[0].instance_name, instance_name);
});
});
var instance_num1, instance_num2, i_num;
describe('#removeInstanceAt(index)', function () {
this.timeout(10000);
it("should remove an instance at the position specified", async function () {
instance_num1 = rpcControlServer.torPool.instances.length;
await rpcClient.invokeAsync('removeInstanceAt', [0]);
});
it('the tor pool should contain one instance fewer', function () {
assert.equal(rpcControlServer.torPool.instances.length, (instance_num1 - 1));
});
});
describe('#removeInstanceByName(instance_name)', function () {
this.timeout(10000);
it("should remove an instance at the position specified", async function () {
instance_num2 = rpcControlServer.torPool.instances.length;
await rpcClient.invokeAsync('removeInstanceByName', [ "instance-1" ]);
});
it('the tor pool should contain one instance fewer', function () {
assert.equal(rpcControlServer.torPool.instances.length, (instance_num2 - 1));
});
});
describe('#closeInstances()', function () {
this.timeout(10000);
it('should shutdown all instances', async function () {
instance_num = rpcControlServer.torPool.instances.length;
await rpcClient.invokeAsync('closeInstances', [ ]);
});
it('no instances should be present in the pool', function () {
assert.equal(rpcControlServer.torPool.instances.length, 0);
assert.notEqual(rpcControlServer.torPool.instances.length, instance_num);
});
});
after('shutdown tor pool', async function () {
this.timeout(10000);
await rpcControlServer.torPool.exit();
});
});

42
test/SOCKSServer.js Normal file
View file

@ -0,0 +1,42 @@
const nconf = require('nconf');
const request = require('request-promise');
const getPort = require('get-port');
const ProxyAgent = require('proxy-agent');
const logger = require('../src/winston-silent-logger');
const { TorPool, SOCKSServer } = require('../');
const { WAIT_FOR_CREATE, PAGE_LOAD_TIME } = require('./constants');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
let socksServerTorPool;
let socksServer;
describe('SOCKSServer', function () {
socksServerTorPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
socksServer = new SOCKSServer(socksServerTorPool, logger);
let socksPort;
before('start up server', async function (){
this.timeout(WAIT_FOR_CREATE);
await socksServerTorPool.create(1);
socksPort = await getPort();
socksServer.listen(socksPort);
});
describe('#handleConnection(socket)', function () {
it('should service a request for example.com', async function () {
this.timeout(PAGE_LOAD_TIME);
await request({
url: 'http://example.com',
agent: new ProxyAgent(`socks://localhost:${socksPort}`)
});
});
});
after('shutdown tor pool', async function () {
await socksServerTorPool.exit();
});
});

259
test/TorPool.js Normal file
View file

@ -0,0 +1,259 @@
const nconf = require('nconf');
const assert = require('chai').assert;
const Promise = require('bluebird');
const _ = require('lodash');
const { TorPool } = require('../');
const { WAIT_FOR_CREATE } = require('./constants');
const logger = require('../src/winston-silent-logger');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
let torPool;
describe('TorPool', function () {
torPool = new TorPool(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
describe('#create_instance(instance_defintion)', function () {
let instance_defintion = {
Name: 'instance-1',
Config: {
ProtocolWarnings: 1
}
};
it('should create one tor instance based on the provided definition', async function () {
this.timeout(WAIT_FOR_CREATE);
await torPool.create_instance(instance_defintion);
});
it('one instance should exist in the instances collection', function () {
assert.equal(1, torPool.instances.length);
});
it('the created instance should have the defintion properties as the input definition', function () {
assert.deepEqual(instance_defintion, torPool.instances[0].definition);
});
it('the created instance should have the same config properties specified in the definiton', async function () {
let value = await torPool.instances[0].get_config('ProtocolWarnings');
assert.equal(value, instance_defintion.Config.ProtocolWarnings);
});
after('shutdown tor pool', async function () {
torPool.exit();
});
});
describe('#add(instance_defintions)', function () {
var instance_defintions = [
{ Name: 'instance-1', Config: { ProtocolWarnings: 1} },
{ Name: 'instance-2', Config: { ProtocolWarnings: 1 } }
];
it('should create instances from several instance definitions', async function () {
this.timeout(WAIT_FOR_CREATE*2);
await torPool.add(instance_defintions)
});
it('2 instances should exist in the pool', function () {
assert.equal(2, torPool.instances.length);
});
it('the created instances should have the same defintion properties as the input definitions', function () {
assert.deepEqual(instance_defintions, torPool.instances.map((instance) => {
let def_clone = _.cloneDeep(instance.definition);
delete def_clone.Config.DataDirectory;
return def_clone;
}).sort(function(a,b) {return (a.Name > b.Name) ? 1 : ((b.Name > a.Name) ? -1 : 0);}));
});
it('the created instances should have the same config properties specified in the definiton', async function (done) {
this.timeout(10000);
let values = await Promise.all(torPool.instances.map((instance) => instance.get_config('ProtocolWarnings')));
assert.isTrue( values.every((value) => value === 1) );
});
after('shutdown tor pool', async function () {
await torPool.exit();
});
});
describe('#create(number_of_instances)', function () {
torPool.default_tor_config = { TestSocks: 1 };
it('should create 2 instances with the default config', async function () {
this.timeout(WAIT_FOR_CREATE*2);
await torPool.create(2);
});
it('2 instances should exist in the pool', function () {
assert.equal(2, torPool.instances.length);
});
it('the created instances should have the same config properties specified in the default config', async function () {
this.timeout(10000);
let values = await Promise.all(torPool.instances.map((instance) => instance.get_config('ProtocolWarnings')));
assert.isTrue( values.every((value) => value === 1) );
});
after('shutdown tor pool', async function () {
torPool.default_tor_config = {};
await torPool.exit(done);
});
});
describe('#next()', function () {
before('create tor instances', async function () {
this.timeout(WAIT_FOR_CREATE * 3);
await torPool.add([
{
Name: 'instance-1',
Weight: 50
},
{
Name: 'instance-2',
Weight: 25
},
{
Name: 'instance-3',
Weight: 2
}
]);
});
it('result of next should be different if run twice', function () {
var t1 = torPool.next().instance_name;
var t2 = torPool.next().instance_name;
assert.notEqual(t1, t2);
});
});
describe('#instance_by_name(instance_name)', function () {
it('should retrieve instance by name', function () {
assert.ok(torPool.instance_by_name('instance-1'));
});
});
describe('#remove_by_name(instance_name)', function () {
this.timeout(5000);
it('should remove instance by name', async function () {
await torPool.remove_by_name('instance-3');
});
});
describe('#instance_at(index)', function () {
this.timeout(5000);
it('should retrieve an instance by id', function () {
assert.ok(torPool.instance_at(0));
});
});
describe('#remove_at(index)', function () {
this.timeout(5000);
it('should remove an instance by id', async function () {
await torPool.remove_at(1);
});
});
describe('#new_identites()', function () {
this.timeout(5000);
it('should signal to retrieve a new identity to all instances', async function () {
await torPool.new_identites();
});
});
describe('#new_identity_at(index)', function () {
this.timeout(5000);
it('should signal to retrieve a new identity identified by index', async function () {
await torPool.new_identity_at(0);
});
});
describe('#new_identity_by_name(instance_name)', function () {
this.timeout(5000);
it('should signal to retrieve a new identity identified by name', async function () {
await torPool.new_identity_by_name('instance-1');
});
});
describe('#set_config_all(keyword, value)', function () {
it('should set configuration on all active instances', async function () {
this.timeout(5000);
await torPool.set_config_all('TestSocks', 1);
});
it('all instances should contain the same changed configuration', async function () {
this.timeout(5000);
let values = await Promise.all(torPool.instances.map((instance) => instance.get_config('TestSocks')));
assert.isTrue( values.every((value) => value === 1) );
});
after('unset config options', async function () {
await torPool.set_config_all('TestSocks', 0);
});
});
describe('#set_config_by_name(name, keyword, value)', function () {
this.timeout(5000);
it('should set a configuration property of an instance identified by name', async function () {
await torPool.set_config_by_name('instance-1', 'ProtocolWarnings', 1);
});
});
describe('#get_config_by_name(name, keyword)', function () {
this.timeout(5000);
it('should get retrieve the configuration of an instance identified by name', async function () {
let value = await torPool.get_config_by_name('instance-1', 'ProtocolWarnings');
assert.equal(value, 1);
});
});
describe('#set_config_at(index, keyword, value)', function () {
this.timeout(5000);
it('should set a configuration property of an instance identified by index', async function () {
await torPool.set_config_at(0, 'ProtocolWarnings', 0);
});
});
describe('#get_config_at(index, keyword)', function () {
this.timeout(5000);
it('should get retrieve the configuration of an instance identified by name', async function () {
let value = await torPool.get_config_at(0, 'ProtocolWarnings');
assert.equal(value, 0);
});
});
describe('#signal_all(signal)', function () {
this.timeout(5000);
it('should send a signal to all instances', async function () {
await torPool.signal_all('DEBUG');
});
});
describe('#signal_by_name(name, signal)', async function () {
this.timeout(5000);
it('should send a signal to an instance identified by name', async function () {
await torPool.signal_by_name('instance-1', 'DEBUG');
});
});
describe('#signal_at(index, signal)', function () {
this.timeout(5000);
it('should send a signal to an instance identified by index', async function () {
await torPool.signal_at(0, 'DEBUG');
});
});
after('shutdown tor pool', async function () {
await torPool.exit();
});
});

80
test/TorProcess.js Normal file
View file

@ -0,0 +1,80 @@
const nconf = require('nconf');
const assert = require('chai').assert;
const { TorProcess } = require('../');
const { WAIT_FOR_CREATE } = require('./constants');
const logger = require('../src/winston-silent-logger');
require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
describe('TorProcess', function () {
let tor = new TorProcess(nconf.get('torPath'), { DataDirectory: nconf.get('parentDataDirectory'), ProtocolWarnings: 0 }, null, logger);
describe('#create()', function () {
this.timeout(WAIT_FOR_CREATE);
it('should create the child process', async function () {
await tor.create();
});
it('should signal when it is listening on the control port', function (done) {
if (tor.control_port_listening)
return done();
tor.once('control_listen', done);
});
it('should signal when connected to the control port', function (done) {
if (tor.control_port_connected)
return done();
tor.once('controller_ready', done);
});
it('should signal when it is listening on the socks port', function (done) {
if (tor.socks_port_listening)
return done();
tor.once('socks_listen', done);
});
it('should signal when it is listening on the dns port', function (done) {
if (tor.dns_port_listening)
return done();
tor.once('dns_listen', done);
});
it('should signal when bootstrapped', function (done) {
tor.once('error', done);
if (tor.bootstrapped)
return done();
tor.once('ready', done);
});
});
describe('#set_config(keyword, value)', function () {
it('should set sample configuration option via the control protocol', async function () {
await tor.set_config('ProtocolWarnings', 1);
});
});
describe('#get_config(keyword, value)', function () {
it('should retrieve sample configuration option via the control protocol', async function () {
let value = await tor.get_config('ProtocolWarnings');
assert.equal(value, 1);
});
});
describe('#new_identity()', function () {
it('should use a new identity', async function () {
await tor.new_identity();
});
});
describe('#signal()', function () {
it('should send a signal via the control protocol', async function () {
await tor.signal('DEBUG');
});
});
after('shutdown tor', async function () {
await tor.exit();
});
});

4
test/constants.js Normal file
View file

@ -0,0 +1,4 @@
module.exports = {
WAIT_FOR_CREATE: 120000,
PAGE_LOAD_TIME: 60000
};

8
test/index.js Normal file
View file

@ -0,0 +1,8 @@
describe("TorRouter", function () {
require('./TorProcess');
require('./TorPool');
require('./SOCKSServer');
require('./HTTPServer');
require('./DNSServer');
require('./ControlServer');
});

View file

@ -1,979 +0,0 @@
const SocksAgent = require('socks-proxy-agent');
const request = require('request');
const async = require('async');
const TorRouter = require('../');
const getPort = require('get-port');
const dns = require('native-dns');
const _ = require('lodash');
const assert = require('assert');
const winston = require('winston');
const del = require('del');
const rpc = require('jrpc2');
const fs = require('fs');
const colors = require('mocha/lib/reporters/base').colors;
const nconf = require('nconf');
nconf = require(`${__dirname}/../src/nconf_load_env.js`)(nconf);
nconf.defaults(require(`${__dirname}/../src/default_config.js`));
const logger = require('../src/winston-silent-logger');
const WAIT_FOR_CREATE = 120000;
const PAGE_LOAD_TIME = 60000;
describe('TorProcess', function () {
var tor = new (TorRouter.TorProcess)(nconf.get('torPath'), { DataDirectory: nconf.get('parentDataDirectory'), ProtocolWarnings: 0 }, null, logger);
describe('#create()', function () {
this.timeout(WAIT_FOR_CREATE);
it('should create the child process', function (done) {
tor.create(done);
});
it('should signal when it is listening on the control port', function (done) {
if (tor.control_port_listening)
return done();
tor.once('control_listen', done);
});
it('should signal when connected to the control port', function (done) {
if (tor.control_port_connected)
return done();
tor.once('controller_ready', done);
});
it('should signal when it is listening on the socks port', function (done) {
if (tor.socks_port_listening)
return done();
tor.once('socks_listen', done);
});
it('should signal when it is listening on the dns port', function (done) {
if (tor.dns_port_listening)
return done();
tor.once('dns_listen', done);
});
it('should signal when bootstrapped', function (done) {
tor.once('error', done);
if (tor.bootstrapped)
return done();
tor.once('ready', done);
});
});
describe('#set_config(keyword, value)', function () {
it('should set sample configuration option via the control protocol', function (done) {
tor.set_config('ProtocolWarnings', 1, done);
});
});
describe('#get_config(keyword, value)', function () {
it('should retrieve sample configuration option via the control protocol', function (done) {
tor.get_config('ProtocolWarnings', function (error, value) {
done(error, (value == 1));
});
});
});
describe('#new_identity()', function () {
it('should use a new identity', function (done) {
tor.new_identity(done);
});
});
describe('#signal()', function () {
it('should send a signal via the control protocol', function (done) {
tor.signal('DEBUG', done);
});
});
after('shutdown tor', function (done) {
tor.exit(done);
});
});
var torPool;
describe('TorPool', function () {
torPool = new (TorRouter.TorPool)(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
describe('#create_instance(instance_defintion)', function () {
var instance_defintion = {
Name: 'instance-1',
Config: {
ProtocolWarnings: 1
}
};
it('should create one tor instance based on the provided definition', function (done) {
this.timeout(WAIT_FOR_CREATE);
torPool.create_instance(instance_defintion, (err, _instance) => {
done(err);
});
});
it('one instance should exist in the instances collection', function () {
assert.equal(1, torPool.instances.length);
});
it('the created instance should have the defintion properties as the input definition', function () {
assert.deepEqual(instance_defintion, torPool.instances[0].definition);
});
it('the created instance should have the same config properties specified in the definiton', function (done) {
torPool.instances[0].get_config('ProtocolWarnings', (err, v) => {
if (err)
return done(err);
done(null, (v === instance_defintion.Config.ProtocolWarnings));
});
});
after('shutdown tor pool', function (done) {
torPool.exit(done);
});
});
describe('#add(instance_defintions)', function () {
var instance_defintions = [
{ Name: 'instance-1', Config: { ProtocolWarnings: 1} },
{ Name: 'instance-2', Config: { ProtocolWarnings: 1 } }
];
it('should create instances from several instance definitions', function (done) {
this.timeout(WAIT_FOR_CREATE*2);
torPool.add(instance_defintions, function (error) {
done(error)
});
});
it('2 instances should exist in the pool', function () {
assert.equal(2, torPool.instances.length);
});
it('the created instances should have the same defintion properties as the input definitions', function () {
assert.deepEqual(instance_defintions, torPool.instances.map((i) => {
let def_clone = _.extend({}, i.definition);
delete def_clone.Config.DataDirectory;
return def_clone;
}).sort(function(a,b) {return (a.Name > b.Name) ? 1 : ((b.Name > a.Name) ? -1 : 0);}));
});
it('the created instances should have the same config properties specified in the definiton', function (done) {
this.timeout(10000);
async.map(torPool.instances, function grabConfig(instance, next) {
instance.get_config('ProtocolWarnings', next);
}, function (err, values) {
if (err) return done(err);
done(null, values.every((v) => v === 1));
});
});
after('shutdown tor pool', function (done) {
torPool.exit(done);
});
});
describe('#create(number_of_instances)', function () {
torPool.default_tor_config = { TestSocks: 1 };
it('should create 2 instances with the default config', function (done) {
this.timeout(WAIT_FOR_CREATE*2);
torPool.create(2, done);
});
it('2 instances should exist in the pool', function () {
assert.equal(2, torPool.instances.length);
});
it('the created instances should have the same config properties specified in the default config', function (done) {
this.timeout(10000);
async.map(torPool.instances, function grabConfig(instance, next) {
instance.get_config('ProtocolWarnings', next);
}, function (err, values) {
if (err) return done(err);
done(null, values.every((v) => v === 1));
});
});
after('shutdown tor pool', function (done) {
torPool.default_tor_config = {};
torPool.exit(done);
});
});
describe('#next()', function () {
before('create tor instances', function (done) {
this.timeout(WAIT_FOR_CREATE * 3);
torPool.add([
{
Name: 'instance-1',
Weight: 50
},
{
Name: 'instance-2',
Weight: 25
},
{
Name: 'instance-3',
Weight: 2
}
], done);
});
it('result of next should be different if run twice', function () {
var t1 = torPool.next().instance_name;
var t2 = torPool.next().instance_name;
assert.notEqual(t1, t2);
});
});
describe('#instance_by_name(instance_name)', function () {
it('should retrieve instance by name', function () {
assert.ok(torPool.instance_by_name('instance-1'));
});
});
describe('#remove_by_name(instance_name)', function () {
this.timeout(5000);
it('should remove instance by name', function (done) {
torPool.remove_by_name('instance-3', done);
});
});
describe('#instance_at(index)', function () {
this.timeout(5000);
it('should retrieve an instance by id', function () {
assert.ok(torPool.instance_at(0));
});
});
describe('#remove_at(index)', function () {
this.timeout(5000);
it('should remove an instance by id', function (done) {
torPool.remove_at(1, done);
});
});
describe('#new_identites()', function () {
this.timeout(5000);
it('should signal to retrieve a new identity to all instances', function (done) {
torPool.new_identites(done);
});
});
describe('#new_identity_at(index)', function () {
this.timeout(5000);
it('should signal to retrieve a new identity identified by index', function (done) {
torPool.new_identity_at(0, done);
});
});
describe('#new_identity_by_name(instance_name)', function () {
this.timeout(5000);
it('should signal to retrieve a new identity identified by name', function (done) {
torPool.new_identity_by_name('instance-1', done);
});
});
describe('#set_config_all(keyword, value)', function () {
it('should set configuration on all active instances', function (done) {
this.timeout(5000);
torPool.set_config_all('TestSocks', 1, done);
});
it('all instances should contain the same changed configuration', function (done) {
this.timeout(5000);
async.map(torPool.instances, (instance, next) => {
instance.get_config('TestSocks', next);
}, function (error, results) {
if (error) return done(error);
done(null, results.every((r) => r === 1));
});
});
after('unset config options', function (done) {
torPool.set_config_all('TestSocks', 0, done);
});
});
describe('#set_config_by_name(name, keyword, value)', function () {
this.timeout(5000);
it('should set a configuration property of an instance identified by name', function (done) {
torPool.set_config_by_name('instance-1', 'ProtocolWarnings', 1, done);
});
});
describe('#get_config_by_name(name, keyword)', function () {
this.timeout(5000);
it('should get retrieve the configuration of an instance identified by name', function (done) {
torPool.get_config_by_name('instance-1', 'ProtocolWarnings', (error, value) => {
if (error) return done(error);
done(null, (value === 1));
});
});
});
describe('#set_config_at(index, keyword, value)', function () {
this.timeout(5000);
it('should set a configuration property of an instance identified by index', function (done) {
torPool.set_config_at(0, 'ProtocolWarnings', 0, done);
});
});
describe('#get_config_at(index, keyword)', function () {
this.timeout(5000);
it('should get retrieve the configuration of an instance identified by name', function (done) {
torPool.get_config_at(0, 'ProtocolWarnings', (error, value) => {
if (error) return done(error);
done(null, (value === 0));
});
});
});
describe('#signal_all(signal)', function () {
this.timeout(5000);
it('should send a signal to all instances', function (done) {
torPool.signal_all('DEBUG', done);
});
});
describe('#signal_by_name(name, signal)', function () {
this.timeout(5000);
it('should send a signal to an instance identified by name', function (done) {
torPool.signal_by_name('instance-1', 'DEBUG', done);
});
});
describe('#signal_at(index, signal)', function () {
this.timeout(5000);
it('should send a signal to an instance identified by index', function (done) {
torPool.signal_at(0, 'DEBUG', done);
});
});
after('shutdown tor pool', function (done) {
torPool.exit(done);
});
});
var socksServerTorPool;
var socksServer;
describe('SOCKSServer', function () {
socksServerTorPool = new (TorRouter.TorPool)(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
socksServer = new (TorRouter.SOCKSServer)(socksServerTorPool, logger);
var socksPort;
before('start up server', function (done){
this.timeout(WAIT_FOR_CREATE);
async.waterfall([
(callback) => { socksServerTorPool.create(1, callback); },
(callback) => { getPort().then((port) => callback(null, port)); },
(port, callback) => {
socksPort = port;
socksServer.listen(port);
callback();
}
], done);
});
describe('#handleConnection(socket)', function () {
it('should service a request for example.com', function (done) {
this.timeout(PAGE_LOAD_TIME);
var req = request({
url: 'http://example.com',
agent: new SocksAgent(`socks://localhost:${socksPort}`)
});
req.on('error', function (error) {
done(error);
});
req.on('response', function (res) {
done();
})
});
});
after('shutdown tor pool', function (done) {
socksServerTorPool.exit(done);
});
});
var httpServerTorPool;
var httpServer;
describe('HTTPServer', function () {
httpServerTorPool = new (TorRouter.TorPool)(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
httpServer = new (TorRouter.HTTPServer)(httpServerTorPool, logger);
var httpPort;
before('start up server', function (done){
this.timeout(WAIT_FOR_CREATE);
async.waterfall([
(callback) => { httpServerTorPool.create(1, callback); },
(callback) => { getPort().then((port) => callback(null, port)); },
(port, callback) => {
httpPort = port;
httpServer.listen(port);
callback();
}
], done);
});
describe('#handle_http_connections(req, res)', function () {
it('should service a request for example.com', function (done) {
this.timeout(PAGE_LOAD_TIME);
var req = request({
url: 'http://example.com',
proxy: `http://localhost:${httpPort}`
});
req.on('error', function (error) {
done(error);
});
req.on('response', function (res) {
done();
});
});
});
describe('#handle_connect_connections(req, inbound_socket, head)', function () {
it('should service a request for example.com', function (done) {
this.timeout(PAGE_LOAD_TIME);
var req = request({
url: 'https://example.com',
proxy: `http://localhost:${httpPort}`
});
req.on('error', function (error) {
done(error);
});
req.on('response', function (res) {
done();
});
});
});
after('shutdown tor pool', function (done) {
httpServerTorPool.exit(done);
});
});
var dnsServerTorPool;
var dnsServer;
describe('DNSServer', function () {
dnsServerTorPool = new (TorRouter.TorPool)(nconf.get('torPath'), {}, nconf.get('parentDataDirectory'), 'round_robin', null, logger);
dnsServer = new (TorRouter.DNSServer)(dnsServerTorPool, {}, 10000, logger);
var dnsPort;
before('start up server', function (done){
this.timeout(WAIT_FOR_CREATE);
async.waterfall([
(callback) => { dnsServerTorPool.create(1, callback); },
(callback) => { getPort().then((port) => callback(null, port)); },
(port, callback) => {
dnsPort = port;
dnsServer.serve(port);
callback();
}
], done);
});
describe('#handle_dns_request(req, res)', function () {
it('should service a request for example.com', function (done) {
this.timeout(10000);
var req = dns.Request({
question: dns.Question({
name: 'example.com',
type: 'A'
}),
server: { address: '127.0.0.1', port: dnsPort, type: 'udp' },
timeout: 1000,
});
req.on('timeout', function () {
done(new Error('Connection timed out'));
});
req.on('message', function () {
done();
});
req.send();
});
});
after('shutdown tor pool', function (done) {
dnsServerTorPool.exit(done);
});
});
var controlServer = new (TorRouter.ControlServer)(logger, nconf);
var controlPort;
describe('ControlServer', function () {
describe('#listen(port)', function () {
it('should bind to a given port', function (done) {
getPort().then((port) => {
controlPort = port;
controlServer.listen(port, done);
});
});
});
describe('#createTorPool(options)', function () {
it('should create a TorPool with a given configuration', function () {
let torPool = controlServer.createTorPool({ ProtocolWarnings: 1 });
assert.ok((controlServer.torPool instanceof (TorRouter.TorPool)));
assert.equal(1, torPool.default_tor_config.ProtocolWarnings);
});
});
describe('#createSOCKSServer(port)', function () {
it('should create a SOCKS Server', function (done) {
getPort().then((port) => {
controlServer.createSOCKSServer(port);
done(null, (
(controlServer.socksServer instanceof (TorRouter.SOCKSServer))
));
});
});
});
describe('#createDNSServer(port)', function () {
it('should create a DNS Server', function (done) {
getPort().then((port) => {
controlServer.createDNSServer(port);
done(null, (
(controlServer.dnsServer instanceof (TorRouter.DNSServer))
));
});
});
});
describe('#createHTTPServer(port)', function () {
it('should create a HTTP Server', function (done) {
getPort().then((port) => {
controlServer.createHTTPServer(port);
done(null, (
(controlServer.httpServer instanceof (TorRouter.HTTPServer))
));
});
});
});
describe('#close()', function () {
it('should close the RPC Server', function () {
controlServer.close();
});
});
after('shutdown tor pool', function (done) {
controlServer.torPool.exit(done);
});
});
var rpcControlServer = new (TorRouter.ControlServer)(logger, nconf);
var rpcControlPort;
var rpcClient;
describe('ControlServer - RPC', function () {
before('setup control server', function (done) {
async.waterfall([
(callback) => { getPort().then((port) => callback(null, port)); },
(port, callback) => { rpcControlPort = port; rpcControlServer.listen(port, callback); },
(callback) => {
rpcClient = new rpc.Client(new rpc.tcpTransport({ port: rpcControlPort, hostname: 'localhost' }));
return callback();
}
], done);
});
describe('#createInstances(number_of_instances)', function () {
this.timeout(WAIT_FOR_CREATE*2);
it('should create an instance', function (done) {
rpcClient.invoke('createInstances', [2], function (error) {
if (error)
return done(error);
done();
});
});
});
describe('#queryInstances()', function () {
this.timeout(3000);
it('should return a list of instances', function (done) {
rpcClient.invoke('queryInstances', [], function (error, raw) {
if (error)
return done(error);
var instances = JSON.parse(raw).result;
if (!Array.isArray(instances))
done(new Error('Did not return an array'));
done(null, (instances.every((i) => (typeof(i.name) !== 'undefined') && (i.name !== null)) && instances.length));
});
});
});
describe('#addInstances(definitions)', function () {
this.timeout(WAIT_FOR_CREATE);
it("should add an instance based on a defintion", function (done) {
var def = {
Name: 'instance-1'
};
rpcClient.invoke('addInstances', [ [ def ] ], done);
});
it("tor pool should now contain and instance that has the same name as the name specified in the defintion", function () {
assert.ok(rpcControlServer.torPool.instance_by_name('instance-1'));
});
});
describe('#queryInstanceByName(instance_name)', function () {
this.timeout(3000);
it('should return a single instance', function (done) {
rpcClient.invoke('queryInstanceByName', ['instance-1'], function (error, raw) {
if (error)
return done(error);
var instance = JSON.parse(raw).result;
done(null, (typeof(instance.name) !== undefined) && (instance.name !== null));
});
});
});
describe('#queryInstanceAt(index)', function () {
this.timeout(3000);
it('should return a single instance', function (done) {
rpcClient.invoke('queryInstanceAt', [0], function (error, raw) {
if (error)
return done(error);
var instance = JSON.parse(raw).result;
done(null, (typeof(instance.name) !== undefined) && (instance.name !== null));
});
});
});
describe('#newIdentites()', function () {
this.timeout(3000);
it('should request new identities for all instances', function (done) {
rpcClient.invoke('newIdentites', [], done);
});
});
describe('#newIdentityByName(instance_name)', function () {
this.timeout(3000);
it('should request new identities for all instances', function (done) {
rpcClient.invoke('newIdentityByName', ['instance-1'], done);
});
});
describe('#newIdentityAt(index)', function () {
this.timeout(3000);
it('should request new identities for all instances', function (done) {
rpcClient.invoke('newIdentityAt', [0], done);
});
});
describe("#setTorConfig(config_object)", function () {
this.timeout(3000);
it('should set several config variables on all instances', function (done) {
rpcClient.invoke('setTorConfig', [ { TestSocks: 1, ProtocolWarnings: 1 } ], done);
});
it('all instances should have the modified variables', function(done) {
async.map(rpcControlServer.torPool.instances, (instance, next) => {
async.series([
(cb) => { instance.get_config('TestSocks', next); },
(cb) => { instance.get_config('ProtocolWarnings', next); }
], next);
}, (error, results) => {
if (error) return done(error);
done(null, results.every((i) => i[0] === 1 && i[1] === 1));
});
});
after('unset config variables', function (done) {
async.series([
(cb) => { rpcControlServer.torPool.set_config_all('TestSocks', 0, cb); },
(cb) => { rpcControlServer.torPool.set_config_all('ProtocolWarnings', 0, cb); }
], done);
});
});
describe('#setDefaultTorConfig(object)', function () {
it('should set the default config of new instances', function (done) {
this.timeout(3000);
rpcClient.invoke('setDefaultTorConfig', [ { TestSocks: 1 } ], done);
});
it('a new instance should be created with the modified property', function (done) {
this.timeout(WAIT_FOR_CREATE);
rpcControlServer.torPool.create_instance({ Name: 'config-test' }, (err) => {
if (err) return done(err);
rpcControlServer.torPool.instance_by_name('config-test').get_config('TestSocks', (err, val) => {
if (err) return done(err);
done(null, val === 1);
});
});
});
after('remove instance', function (done) {
this.timeout(10000);
nconf.set('torConfig', {});
rpcControlServer.torPool.remove_by_name('config-test', done);
});
});
describe('#getDefaultTorConfig()', function () {
before('set tor config', function () {
nconf.set('torConfig', { TestSocks: 1 });
});
it('should return a tor config with a modified property', function (done) {
this.timeout(3000);
rpcClient.invoke('getDefaultTorConfig', [ { } ], function (error, raw) {
if (error) return done(error);
var config = JSON.parse(raw).result;
done(null, (config.TestSocks === 1))
});
});
after('unset property', function () {
nconf.set('torConfig', {});
});
});
describe('#getLoadBalanceMethod()', function () {
this.timeout(3000);
before(function () {
rpcControlServer.torPool.load_balance_method = 'round_robin';
});
it('should return the current load balance method', function (done) {
rpcClient.invoke('getLoadBalanceMethod', [], function (error, raw) {
if (error) return done(error);
var lb_method = JSON.parse(raw).result;
done(null, (lb_method === 'round_robin'));
});
});
});
describe('#setLoadBalanceMethod(load_balance_method)', function () {
this.timeout(3000);
it('should set the load balance method', function (done) {
rpcClient.invoke('setLoadBalanceMethod', ['weighted'], function (error) {
return done(error);
});
});
it('the load balance method should be changed', function () {
assert.equal(rpcControlServer.torPool.load_balance_method, 'weighted');
});
after(function () {
rpcControlServer.torPool.load_balance_method = 'round_robin';
});
});
describe("#getInstanceConfigByName(instance_name)", function () {
this.timeout(3000);
before('set config property', function (done) {
rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 1, done);
});
it('should retrieve the property from the tor instance', function (done) {
rpcClient.invoke('getInstanceConfigByName', ['instance-1'], function (error, raw) {
if (error) return done(error);
var value = JSON.parse(raw).result;
done(null, value === 1);
});
});
after('unset config property', function (done) {
rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0, done);
});
});
describe("#getInstanceConfigAt(index)", function () {
this.timeout(3000);
before('set config property', function (done) {
rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 1, done);
});
it('should retrieve the property from the tor instance', function (done) {
rpcClient.invoke('getInstanceConfigByName', [0], function (error, raw) {
if (error) return done(error);
var value = JSON.parse(raw).result;
done(null, value === 1);
});
});
after('unset config property', function (done) {
rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0, done);
});
});
describe("#setInstanceConfigByName(instance_name)", function () {
this.timeout(3000);
before('set config property', function (done) {
rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0, done);
});
it('should set the property for the tor instance', function (done) {
rpcClient.invoke('setInstanceConfigByName', ['instance-1', 'TestSocks', 1], function (error, value) {
done(error);
});
});
it('tor instance should have the modified property', function (done) {
rpcControlServer.torPool.instance_by_name('instance-1').get_config('TestSocks', function (error, value) {
if (error) return done(error);
done(null, (value === 1));
});
});
after('unset config property', function (done) {
rpcControlServer.torPool.instance_by_name('instance-1').set_config('TestSocks', 0, done);
});
});
describe("#setInstanceConfigAt(index)", function () {
this.timeout(3000);
before('set config property', function (done) {
rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0, done);
});
it('should set the property for the tor instance', function (done) {
rpcClient.invoke('setInstanceConfigAt', [0, 'TestSocks', 1], function (error, value) {
done(error);
});
});
it('tor instance should have the modified property', function (done) {
rpcControlServer.torPool.instance_at(0).get_config('TestSocks', function (error, value) {
if (error) return done(error);
done(null, (value === 1));
});
});
after('unset config property', function (done) {
rpcControlServer.torPool.instance_at(0).set_config('TestSocks', 0, (err) => {
done(err);
});
});
});
describe('#signalAllInstances(signal)', function () {
this.timeout(3000);
it('should signal to all interfaces', function (done) {
rpcClient.invoke('signalAllInstances', [ 'DEBUG' ], function (error) {
done(error);
});
});
});
describe('#signalInstanceAt(signal)', function () {
this.timeout(3000);
it('should signal to all interfaces', function (done) {
rpcClient.invoke('signalInstanceAt', [ 0, 'DEBUG' ], function (error) {
done(error);
});
});
});
describe('#signalAllInstances(signal)', function () {
this.timeout(3000);
it('should signal to all interfaces', function (done) {
rpcClient.invoke('signalInstanceByName', [ 'instance-1', 'DEBUG' ], function (error) {
done(error);
});
});
});
describe("#nextInstance()", function () {
this.timeout(3000);
var i_name;
it('should rotate the 0th item in the instances array', function (done) {
i_name = rpcControlServer.torPool.instances[0].instance_name;
rpcClient.invoke('nextInstance', [], function (error) {
done(error);
});
});
it('0th item in the instances array should be different after nextInstance is called', function () {
assert.notEqual(rpcControlServer.torPool.instances[0].instance_name, i_name);
});
});
var instance_num1, instance_num2, i_num;
describe('#removeInstanceAt(index)', function () {
this.timeout(10000);
it("should remove an instance at the position specified", function (done) {
instance_num1 = rpcControlServer.torPool.instances.length;
rpcClient.invoke('removeInstanceAt', [0], function (error) {
done(error);
});
});
it('the tor pool should contain one instance fewer', function () {
assert.equal(rpcControlServer.torPool.instances.length, (instance_num1 - 1));
});
});
describe('#removeInstanceByName(instance_name)', function () {
this.timeout(10000);
it("should remove an instance at the position specified", function (done) {
instance_num2 = rpcControlServer.torPool.instances.length;
rpcClient.invoke('removeInstanceByName', [ "instance-1" ], function (error) {
done(error);
});
});
it('the tor pool should contain one instance fewer', function () {
assert.equal(rpcControlServer.torPool.instances.length, (instance_num2 - 1));
});
});
describe('#closeInstances()', function () {
this.timeout(10000);
it('should shutdown all instances', function (done) {
i_num = rpcControlServer.torPool.instances.length;
rpcClient.invoke('closeInstances', [ ], function (error) {
done(error);
});
});
it('no instances should be present in the pool', function () {
assert.equal(rpcControlServer.torPool.instances.length, 0);
assert.notEqual(rpcControlServer.torPool.instances.length, i_num);
});
});
after('shutdown tor pool', function (done) {
this.timeout(10000);
rpcControlServer.torPool.exit(done);
});
});