@mbtest/mountebank 2.9.2-beta.9050

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +94 -0
  3. package/bin/mb +136 -0
  4. package/package.json +71 -0
  5. package/releases.json +52 -0
  6. package/src/cli/api.js +112 -0
  7. package/src/cli/cli.js +420 -0
  8. package/src/controllers/configController.js +64 -0
  9. package/src/controllers/feedController.js +115 -0
  10. package/src/controllers/homeController.js +58 -0
  11. package/src/controllers/imposterController.js +328 -0
  12. package/src/controllers/impostersController.js +215 -0
  13. package/src/controllers/logsController.js +52 -0
  14. package/src/models/behaviors.js +553 -0
  15. package/src/models/behaviorsValidator.js +186 -0
  16. package/src/models/compatibility.js +133 -0
  17. package/src/models/dryRunValidator.js +261 -0
  18. package/src/models/filesystemBackedImpostersRepository.js +908 -0
  19. package/src/models/http/baseHttpServer.js +207 -0
  20. package/src/models/http/headersMap.js +87 -0
  21. package/src/models/http/httpProxy.js +230 -0
  22. package/src/models/http/httpRequest.js +82 -0
  23. package/src/models/http/httpServer.js +18 -0
  24. package/src/models/http/index.js +18 -0
  25. package/src/models/https/cert/mb-cert.pem +20 -0
  26. package/src/models/https/cert/mb-csr.pem +16 -0
  27. package/src/models/https/cert/mb-key.pem +27 -0
  28. package/src/models/https/httpsServer.js +42 -0
  29. package/src/models/https/index.js +18 -0
  30. package/src/models/imposter.js +243 -0
  31. package/src/models/imposterPrinter.js +120 -0
  32. package/src/models/impostersRepository.js +49 -0
  33. package/src/models/inMemoryImpostersRepository.js +418 -0
  34. package/src/models/jsonpath.js +44 -0
  35. package/src/models/mbConnection.js +107 -0
  36. package/src/models/predicates.js +438 -0
  37. package/src/models/protocols.js +242 -0
  38. package/src/models/responseResolver.js +398 -0
  39. package/src/models/smtp/index.js +16 -0
  40. package/src/models/smtp/smtpRequest.js +60 -0
  41. package/src/models/smtp/smtpServer.js +109 -0
  42. package/src/models/tcp/index.js +18 -0
  43. package/src/models/tcp/tcpProxy.js +110 -0
  44. package/src/models/tcp/tcpRequest.js +23 -0
  45. package/src/models/tcp/tcpServer.js +156 -0
  46. package/src/models/tcp/tcpValidator.js +19 -0
  47. package/src/models/xpath.js +95 -0
  48. package/src/mountebank.js +245 -0
  49. package/src/public/images/arrow_down.png +0 -0
  50. package/src/public/images/arrow_up.png +0 -0
  51. package/src/public/images/book.jpg +0 -0
  52. package/src/public/images/dataflow.png +0 -0
  53. package/src/public/images/favicon.ico +0 -0
  54. package/src/public/images/forkme_right_orange_ff7600.png +0 -0
  55. package/src/public/images/mountebank.png +0 -0
  56. package/src/public/images/overview.gif +0 -0
  57. package/src/public/images/quote.png +0 -0
  58. package/src/public/images/tw-logo.png +0 -0
  59. package/src/public/scripts/jquery/jquery-3.6.1.min.js +2 -0
  60. package/src/public/scripts/urlHashHandler.js +31 -0
  61. package/src/public/stylesheets/application.css +424 -0
  62. package/src/public/stylesheets/ie.css +14 -0
  63. package/src/public/stylesheets/imposters.css +121 -0
  64. package/src/public/stylesheets/jqueryui/1.10.4/themes/smoothness/jquery-ui.css +1178 -0
  65. package/src/util/combinators.js +68 -0
  66. package/src/util/date.js +51 -0
  67. package/src/util/errors.js +55 -0
  68. package/src/util/helpers.js +131 -0
  69. package/src/util/inherit.js +28 -0
  70. package/src/util/ip.js +54 -0
  71. package/src/util/logger.js +83 -0
  72. package/src/util/middleware.js +256 -0
  73. package/src/util/scopedLogger.js +47 -0
  74. package/src/views/_footer.ejs +20 -0
  75. package/src/views/_header.ejs +113 -0
  76. package/src/views/_imposter.ejs +8 -0
  77. package/src/views/config.ejs +71 -0
  78. package/src/views/docs/api/behaviors/copy.ejs +427 -0
  79. package/src/views/docs/api/behaviors/decorate.ejs +182 -0
  80. package/src/views/docs/api/behaviors/lookup.ejs +220 -0
  81. package/src/views/docs/api/behaviors/shellTransform.ejs +153 -0
  82. package/src/views/docs/api/behaviors/wait.ejs +121 -0
  83. package/src/views/docs/api/behaviors.ejs +141 -0
  84. package/src/views/docs/api/contracts/addStub-description.ejs +10 -0
  85. package/src/views/docs/api/contracts/addStub.ejs +10 -0
  86. package/src/views/docs/api/contracts/config-description.ejs +32 -0
  87. package/src/views/docs/api/contracts/config.ejs +23 -0
  88. package/src/views/docs/api/contracts/home-description.ejs +18 -0
  89. package/src/views/docs/api/contracts/home.ejs +13 -0
  90. package/src/views/docs/api/contracts/imposter-description.ejs +439 -0
  91. package/src/views/docs/api/contracts/imposter.ejs +182 -0
  92. package/src/views/docs/api/contracts/imposters-description.ejs +13 -0
  93. package/src/views/docs/api/contracts/imposters.ejs +13 -0
  94. package/src/views/docs/api/contracts/logs-description.ejs +3 -0
  95. package/src/views/docs/api/contracts/logs.ejs +14 -0
  96. package/src/views/docs/api/contracts/stub-description.ejs +4 -0
  97. package/src/views/docs/api/contracts/stub.ejs +7 -0
  98. package/src/views/docs/api/contracts/stubs-description.ejs +4 -0
  99. package/src/views/docs/api/contracts/stubs.ejs +11 -0
  100. package/src/views/docs/api/contracts.ejs +133 -0
  101. package/src/views/docs/api/errors.ejs +64 -0
  102. package/src/views/docs/api/fault/connectionReset.ejs +31 -0
  103. package/src/views/docs/api/fault/randomDataThenClose.ejs +31 -0
  104. package/src/views/docs/api/faults.ejs +57 -0
  105. package/src/views/docs/api/injection.ejs +426 -0
  106. package/src/views/docs/api/json.ejs +205 -0
  107. package/src/views/docs/api/jsonpath.ejs +210 -0
  108. package/src/views/docs/api/mocks.ejs +130 -0
  109. package/src/views/docs/api/overview.ejs +968 -0
  110. package/src/views/docs/api/predicates/and.ejs +62 -0
  111. package/src/views/docs/api/predicates/contains.ejs +64 -0
  112. package/src/views/docs/api/predicates/deepEquals.ejs +114 -0
  113. package/src/views/docs/api/predicates/endsWith.ejs +66 -0
  114. package/src/views/docs/api/predicates/equals.ejs +125 -0
  115. package/src/views/docs/api/predicates/exists.ejs +118 -0
  116. package/src/views/docs/api/predicates/inject.ejs +67 -0
  117. package/src/views/docs/api/predicates/matches.ejs +66 -0
  118. package/src/views/docs/api/predicates/not.ejs +52 -0
  119. package/src/views/docs/api/predicates/or.ejs +79 -0
  120. package/src/views/docs/api/predicates/startsWith.ejs +62 -0
  121. package/src/views/docs/api/predicates.ejs +382 -0
  122. package/src/views/docs/api/proxies.ejs +191 -0
  123. package/src/views/docs/api/proxy/addDecorateBehavior.ejs +115 -0
  124. package/src/views/docs/api/proxy/addWaitBehavior.ejs +96 -0
  125. package/src/views/docs/api/proxy/injectHeaders.ejs +91 -0
  126. package/src/views/docs/api/proxy/predicateGenerators.ejs +600 -0
  127. package/src/views/docs/api/proxy/proxyModes.ejs +495 -0
  128. package/src/views/docs/api/stubs.ejs +391 -0
  129. package/src/views/docs/api/xpath.ejs +281 -0
  130. package/src/views/docs/cli/configFiles.ejs +133 -0
  131. package/src/views/docs/cli/customFormatters.ejs +53 -0
  132. package/src/views/docs/cli/help.ejs +6 -0
  133. package/src/views/docs/cli/replay.ejs +42 -0
  134. package/src/views/docs/cli/restart.ejs +10 -0
  135. package/src/views/docs/cli/save.ejs +68 -0
  136. package/src/views/docs/cli/start.ejs +234 -0
  137. package/src/views/docs/cli/stop.ejs +32 -0
  138. package/src/views/docs/commandLine.ejs +93 -0
  139. package/src/views/docs/communityExtensions.ejs +233 -0
  140. package/src/views/docs/gettingStarted.ejs +146 -0
  141. package/src/views/docs/mentalModel.ejs +51 -0
  142. package/src/views/docs/protocols/custom.ejs +231 -0
  143. package/src/views/docs/protocols/http.ejs +238 -0
  144. package/src/views/docs/protocols/https.ejs +246 -0
  145. package/src/views/docs/protocols/smtp.ejs +142 -0
  146. package/src/views/docs/protocols/tcp.ejs +431 -0
  147. package/src/views/docs/security.ejs +38 -0
  148. package/src/views/faqs.ejs +65 -0
  149. package/src/views/feed.ejs +33 -0
  150. package/src/views/imposter.ejs +22 -0
  151. package/src/views/imposters.ejs +33 -0
  152. package/src/views/index.ejs +89 -0
  153. package/src/views/license.ejs +30 -0
  154. package/src/views/logs.ejs +77 -0
  155. package/src/views/releases/v1.1.0.ejs +55 -0
  156. package/src/views/releases/v1.1.36.ejs +84 -0
  157. package/src/views/releases/v1.1.72.ejs +92 -0
  158. package/src/views/releases/v1.10.0.ejs +108 -0
  159. package/src/views/releases/v1.11.0.ejs +109 -0
  160. package/src/views/releases/v1.12.0.ejs +96 -0
  161. package/src/views/releases/v1.13.0.ejs +118 -0
  162. package/src/views/releases/v1.14.0.ejs +107 -0
  163. package/src/views/releases/v1.14.1.ejs +94 -0
  164. package/src/views/releases/v1.15.0.ejs +113 -0
  165. package/src/views/releases/v1.16.0.ejs +104 -0
  166. package/src/views/releases/v1.2.0.ejs +78 -0
  167. package/src/views/releases/v1.2.103.ejs +86 -0
  168. package/src/views/releases/v1.2.122.ejs +86 -0
  169. package/src/views/releases/v1.2.30.ejs +84 -0
  170. package/src/views/releases/v1.2.45.ejs +84 -0
  171. package/src/views/releases/v1.2.56.ejs +79 -0
  172. package/src/views/releases/v1.3.0.ejs +86 -0
  173. package/src/views/releases/v1.3.1.ejs +100 -0
  174. package/src/views/releases/v1.4.0.ejs +96 -0
  175. package/src/views/releases/v1.4.1.ejs +103 -0
  176. package/src/views/releases/v1.4.2.ejs +100 -0
  177. package/src/views/releases/v1.4.3.ejs +113 -0
  178. package/src/views/releases/v1.5.0.ejs +104 -0
  179. package/src/views/releases/v1.5.1.ejs +91 -0
  180. package/src/views/releases/v1.6.0.ejs +109 -0
  181. package/src/views/releases/v1.7.0.ejs +113 -0
  182. package/src/views/releases/v1.7.1.ejs +90 -0
  183. package/src/views/releases/v1.7.2.ejs +96 -0
  184. package/src/views/releases/v1.8.0.ejs +121 -0
  185. package/src/views/releases/v1.9.0.ejs +111 -0
  186. package/src/views/releases/v2.0.0.ejs +159 -0
  187. package/src/views/releases/v2.1.0.ejs +121 -0
  188. package/src/views/releases/v2.1.1.ejs +106 -0
  189. package/src/views/releases/v2.1.2.ejs +84 -0
  190. package/src/views/releases/v2.2.0.ejs +115 -0
  191. package/src/views/releases/v2.2.1.ejs +102 -0
  192. package/src/views/releases/v2.3.0.ejs +121 -0
  193. package/src/views/releases/v2.3.1.ejs +100 -0
  194. package/src/views/releases/v2.3.2.ejs +102 -0
  195. package/src/views/releases/v2.3.3.ejs +97 -0
  196. package/src/views/releases/v2.4.0.ejs +114 -0
  197. package/src/views/releases/v2.5.0.ejs +51 -0
  198. package/src/views/releases/v2.6.0.ejs +35 -0
  199. package/src/views/releases/v2.7.0.ejs +32 -0
  200. package/src/views/releases/v2.8.0.ejs +36 -0
  201. package/src/views/releases/v2.8.1.ejs +7 -0
  202. package/src/views/releases/v2.8.2.ejs +26 -0
  203. package/src/views/releases/v2.9.0.ejs +32 -0
  204. package/src/views/releases/v2.9.1.ejs +10 -0
  205. package/src/views/releases.ejs +26 -0
  206. package/src/views/sitemap.ejs +36 -0
  207. package/src/views/support.ejs +14 -0
@@ -0,0 +1,68 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Helpful combinators
5
+ * For the non-pedants, a combinator is basically just a function with no free variables.
6
+ * For the non-pedants, "no free variables" means that the combinator does not have dependencies
7
+ * on things outside the function (e.g. it only depends on the function parameters).
8
+ * A strict definition of combinators requires functions as input parameters, but I loosen that here.
9
+ * That definition really only serves mathematical modeling of state in pure functional terms
10
+ * @module
11
+ */
12
+
13
+ /**
14
+ * Curries a function parameters, which is to say that it returns a function with reduced arity.
15
+ * @example
16
+ * function sum (x, y) { return x + y; }
17
+ * curry(sum, 1)(2); // returns 3
18
+ * curry(sum, 1, 2)(); // returns 3
19
+ * @param {Function} fn - The function to curry
20
+ * @param {...*} args - The arguments to curry
21
+ * @returns {Function}
22
+ */
23
+ function curry (fn) {
24
+ const args = Array.prototype.slice.call(arguments, 1);
25
+ return function () {
26
+ const nextArgs = Array.prototype.slice.call(arguments),
27
+ allArgs = args.concat(nextArgs);
28
+
29
+ return fn.apply(null, allArgs);
30
+ };
31
+ }
32
+
33
+ /**
34
+ * Composes two or more functions
35
+ * @example
36
+ * function increment (i) { return i + 1; }
37
+ * function double (i) { return i * 2; }
38
+ * function triple (i) { return i * 3; }
39
+ * combinators.compose(increment, double, triple)(1); // returns 7
40
+ * @param {...Function} args - The functions to compose
41
+ * @returns {Function} A single function that represents the composition of the functions provided
42
+ */
43
+ function compose () {
44
+ const args = Array.prototype.slice.call(arguments).reverse();
45
+ return obj => args.reduce((result, F) => F(result), obj);
46
+ }
47
+
48
+ module.exports = {
49
+ /**
50
+ * Returns what was passed in unchanged, occasionally useful as the default transformation function
51
+ * to avoid special case logic
52
+ * @param {Object} i - The input
53
+ * @returns {Object} Exactly what was passed in
54
+ */
55
+ identity: i => i,
56
+ /**
57
+ * Ignores its parameters, and instead always returns a constant value
58
+ * @param {Object} k - The constant to return
59
+ * @returns {Function} - A function that will always return the constant
60
+ */
61
+ constant: k => () => k,
62
+ /**
63
+ * A function that does nothing, occasionally useful to avoid special case logic
64
+ */
65
+ noop: () => {},
66
+ compose,
67
+ curry
68
+ };
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ /** @module */
4
+
5
+ function toEpochWithoutTime (text) {
6
+ // be sure to exclude time so we get accurate text
7
+ const dateTextWithoutTime = new Date(Date.parse(text)).toDateString();
8
+ return Date.parse(dateTextWithoutTime);
9
+ }
10
+
11
+ function sameMonth (firstEpoch, secondEpoch) {
12
+ const first = new Date(firstEpoch),
13
+ second = new Date(secondEpoch);
14
+
15
+ return first.getFullYear() === second.getFullYear() && first.getMonth() === second.getMonth();
16
+ }
17
+
18
+ /**
19
+ * Translates the distance between two dates within a month of each other to human readable text
20
+ * @param {string} thenText - The start date
21
+ * @param {string} testNowText - Ignore, used for testing purposes only.
22
+ * @returns {string}
23
+ */
24
+ function howLongAgo (thenText, testNowText) {
25
+ const nowText = testNowText ? testNowText : new Date(Date.now()).toISOString(), // testNow is just for testing purposes
26
+ then = toEpochWithoutTime(thenText),
27
+ now = toEpochWithoutTime(nowText),
28
+ millisecondsInDay = 24 * 60 * 60 * 1000,
29
+ daysAgo = Math.floor((now - then) / millisecondsInDay);
30
+
31
+ if (daysAgo === 0) {
32
+ return 'today';
33
+ }
34
+ else if (daysAgo === 1) {
35
+ return 'yesterday';
36
+ }
37
+ else if (daysAgo < 7) {
38
+ return 'this week';
39
+ }
40
+ else if (daysAgo < 14) {
41
+ return 'last week';
42
+ }
43
+ else if (sameMonth(then, now)) {
44
+ return 'this month';
45
+ }
46
+ else {
47
+ return '';
48
+ }
49
+ }
50
+
51
+ module.exports = { howLongAgo };
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Error types returned by the API
5
+ * @module
6
+ */
7
+ const inherit = require('./inherit.js'),
8
+ helpers = require('./helpers.js');
9
+
10
+ function createError (code, message, options) {
11
+ const result = inherit.from(Error, { code, message });
12
+
13
+ if (options) {
14
+ Object.keys(options).forEach(key => {
15
+ result[key] = options[key];
16
+ });
17
+ }
18
+ return result;
19
+ }
20
+
21
+ function create (code) {
22
+ return (message, options) => createError(code, message, options);
23
+ }
24
+
25
+ function createWithMessage (code, message) {
26
+ return options => createError(code, message, options);
27
+ }
28
+
29
+ // Produces a JSON.stringify-able Error object
30
+ // (because message is on the prototype, it doesn't show by default)
31
+ function details (error) {
32
+ const prototypeProperties = {};
33
+
34
+ ['message', 'name', 'stack'].forEach(key => {
35
+ if (error[key]) {
36
+ prototypeProperties[key] = error[key];
37
+ }
38
+ });
39
+ return helpers.merge(error, prototypeProperties);
40
+ }
41
+
42
+ module.exports = {
43
+ ValidationError: create('bad data'),
44
+ InjectionError: create('invalid injection'),
45
+ ResourceConflictError: create('resource conflict'),
46
+ InsufficientAccessError: createWithMessage('insufficient access', 'Run mb in superuser mode if you want access'),
47
+ InvalidProxyError: create('invalid proxy'),
48
+ MissingResourceError: create('no such resource'),
49
+ InvalidJSONError: createWithMessage('invalid JSON', 'Unable to parse body as JSON'),
50
+ CommunicationError: createWithMessage('communication', 'Error communicating with mountebank'),
51
+ ProtocolError: create('cannot start server'),
52
+ DatabaseError: create('corrupted database'),
53
+ UnauthorizedError: createWithMessage('unauthorized', 'If you set the apiKey option, make sure you are sending the correct apiKey in the x-api-key header.'),
54
+ details
55
+ };
@@ -0,0 +1,131 @@
1
+ 'use strict';
2
+
3
+ /** @module */
4
+
5
+ /**
6
+ * Returns true if obj is a defined value
7
+ * @param {Object} obj - the value to test
8
+ * @returns {boolean}
9
+ */
10
+ function defined (obj) {
11
+ return typeof obj !== 'undefined';
12
+ }
13
+
14
+ /**
15
+ * Returns true if obj is a non-null object
16
+ * Checking for typeof 'object' without checking for nulls
17
+ * is a very common source of bugs
18
+ * @param {Object} obj - the value to test
19
+ * @returns {boolean}
20
+ */
21
+ function isObject (obj) {
22
+ return typeof obj === 'object' && obj !== null;
23
+ }
24
+
25
+ /**
26
+ * Returns the text used for logging purposes related to this socket
27
+ * @param {Object} socket - the socket
28
+ * @returns {string}
29
+ */
30
+ function socketName (socket) {
31
+ let result = socket.remoteAddress;
32
+ if (socket.remotePort) {
33
+ result += `:${socket.remotePort}`;
34
+ }
35
+ return result;
36
+ }
37
+
38
+ /**
39
+ * Returns a deep clone of obj
40
+ * @param {Object} obj - the object to clone
41
+ * @returns {Object}
42
+ */
43
+ function clone (obj) {
44
+ return JSON.parse(JSON.stringify(obj));
45
+ }
46
+
47
+ /**
48
+ * Returns a new object combining the two parameters
49
+ * @param {Object} defaults - The base object
50
+ * @param {Object} overrides - The object to merge from. Where the same property exists in both defaults
51
+ * and overrides, the values for overrides will be used
52
+ * @returns {Object}
53
+ */
54
+ function merge (defaults, overrides) {
55
+ const result = clone(defaults);
56
+ Object.keys(overrides).forEach(key => {
57
+ if (typeof overrides[key] === 'object' && overrides[key] !== null) {
58
+ result[key] = merge(result[key] || {}, overrides[key]);
59
+ }
60
+ else {
61
+ result[key] = overrides[key];
62
+ }
63
+ });
64
+ return result;
65
+ }
66
+
67
+ /**
68
+ * Sets a value of nested key string descriptor inside a Object.
69
+ * It changes the passed object.
70
+ * Ex:
71
+ * let obj = {a: {b:{c:'initial'}}}
72
+ * setNestedKey(obj, ['a', 'b', 'c'], 'changed-value')
73
+ * assert(obj === {a: {b:{c:'changed-value'}}})
74
+ *
75
+ * @param {Object} obj Object to set the nested key
76
+ * @param {Array} path An array to describe the path(Ex: ['a', 'b', 'c'])
77
+ * @param {Object} value Any value
78
+ * @returns {undefined}
79
+ * from https://stackoverflow.com/a/49754647
80
+ */
81
+ function setDeep (obj, path, value) {
82
+ if (path.length === 1) {
83
+ obj[path] = value;
84
+ return;
85
+ }
86
+ setDeep(obj[path[0]], path.slice(1), value);
87
+ }
88
+
89
+ function simulateFault (socket, faultConfig, logger) {
90
+ if (typeof faultConfig === 'undefined') {
91
+ return false;
92
+ }
93
+ if (faultConfig === 'CONNECTION_RESET_BY_PEER') {
94
+ logger.debug('Closing the connection');
95
+ socket.destroy();
96
+ return true;
97
+ }
98
+ else if (faultConfig === 'RANDOM_DATA_THEN_CLOSE') {
99
+ logger.debug('Sending garbage data then closing the connection');
100
+ socket.write(Buffer.from('Htijy%@tWXJ/hQ#[Q:7G@dH4"gu[QaX&', 'utf-8'));
101
+ socket.destroy();
102
+ return true;
103
+ }
104
+ else {
105
+ logger.error('Unexpected fault type [' + faultConfig + '], expected either CONNECTION_RESET_BY_PEER or RANDOM_DATA_THEN_CLOSE');
106
+ return false;
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Remove specific key and value from object
112
+ * @param {Object} obj Object to filter
113
+ * @param {Array|Object|String} filter keys to remove
114
+ * @returns {Object}
115
+ */
116
+
117
+ function objFilter (obj, filter) {
118
+
119
+ if (typeof filter === 'string') {
120
+ delete obj[filter];
121
+ }
122
+ else if (Array.isArray(filter)) {
123
+ filter.filter(keyFilter => obj[keyFilter]).forEach(keyFilter => objFilter(obj, keyFilter));
124
+ }
125
+ else {
126
+ Object.keys(filter).filter(keyFilter => obj[keyFilter]).forEach(keyFilter => objFilter(obj[keyFilter], filter[keyFilter]));
127
+ }
128
+ return obj;
129
+ }
130
+
131
+ module.exports = { defined, isObject, socketName, clone, merge, setDeep, simulateFault, objFilter };
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ /** @module */
4
+
5
+ /**
6
+ * Crockford-style prototypical inheritance, which basically allows me to completely
7
+ * avoid the new and this operators, which I have an unnatural aversion to
8
+ * @param {Object} proto - the object to inherit from
9
+ * @param {Object} [obj] - properties to merge into the newly created object as own properties
10
+ * @returns {Object}
11
+ */
12
+ function from (proto, obj) {
13
+ // allow either inherit.from(EventEmitter) or inherit.from({key: 'value'})
14
+ if (typeof proto === 'function') {
15
+ proto = new proto();
16
+ }
17
+
18
+ obj = obj || {};
19
+ function F () {}
20
+ F.prototype = proto;
21
+ const result = new F();
22
+ Object.keys(obj).forEach(key => {
23
+ result[key] = obj[key];
24
+ });
25
+ return result;
26
+ }
27
+
28
+ module.exports = { from };
package/src/util/ip.js ADDED
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ const os = require('os');
4
+
5
+ function getLocalIPs () {
6
+ const interfaces = os.networkInterfaces(),
7
+ result = [];
8
+
9
+ Object.keys(interfaces).forEach(name => {
10
+ interfaces[name].forEach(ip => {
11
+ if (ip.internal) {
12
+ result.push(ip.address);
13
+ if (ip.family === 'IPv4') {
14
+ // Prefix for IPv4 address mapped to a compliant IPv6 scheme
15
+ result.push(`::ffff:${ip.address}`);
16
+ }
17
+ }
18
+ });
19
+ });
20
+ return result;
21
+ }
22
+
23
+ function ipWithoutZoneId (ip) {
24
+ return ip.replace(/%\w+/, '').toLowerCase();
25
+ }
26
+
27
+ function createIPVerification (options) {
28
+ const allowedIPs = getLocalIPs();
29
+
30
+ if (!options.localOnly) {
31
+ options.ipWhitelist.forEach(ip => { allowedIPs.push(ip.toLowerCase()); });
32
+ }
33
+
34
+ if (allowedIPs.indexOf('*') >= 0) {
35
+ return () => true;
36
+ }
37
+ else {
38
+ return (ip, logger) => {
39
+ if (typeof ip === 'undefined') {
40
+ logger.error('Blocking request because no IP address provided. This is likely a bug in the protocol implementation.');
41
+ return false;
42
+ }
43
+ else {
44
+ const allowed = allowedIPs.some(allowedIP => allowedIP === ipWithoutZoneId(ip));
45
+ if (!allowed) {
46
+ logger.warn(`Blocking incoming connection from ${ip}. Turn off --localOnly or add to --ipWhitelist to allow`);
47
+ }
48
+ return allowed;
49
+ }
50
+ };
51
+ }
52
+ }
53
+
54
+ module.exports = { createIPVerification };
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+ const path = require('path'),
3
+ fs = require('fs-extra'),
4
+ winston = require('winston'),
5
+ scopedLogger = require('./scopedLogger.js');
6
+
7
+ function initializeLogfile (filename) {
8
+ // Ensure new logfile on startup so the /logs only shows for this process
9
+ const extension = path.extname(filename),
10
+ pattern = new RegExp(`${extension}$`),
11
+ newFilename = filename.replace(pattern, `1${extension}`);
12
+
13
+ if (fs.existsSync(filename)) {
14
+ fs.renameSync(filename, newFilename);
15
+ }
16
+ }
17
+
18
+ function logFormat (config) {
19
+ const template = config.replace(/\$/g, '') // prevent injection attacks
20
+ .replace(/%level/g, '${info.level}')
21
+ .replace(/%message/g, '${info.message}')
22
+ .replace(/%timestamp/g, '${info.timestamp}');
23
+
24
+ // eslint-disable-next-line no-new-func
25
+ return new Function('info', `return \`${template}\`;`);
26
+ }
27
+
28
+ function createWinstonFormat (format, config) {
29
+ const formatters = [format.timestamp()];
30
+ if (config.colorize) {
31
+ formatters.push(format.colorize());
32
+ }
33
+ if (config.format === 'json') {
34
+ formatters.push(format.json());
35
+ }
36
+ else if (config.format === 'simple') {
37
+ formatters.push(format.simple());
38
+ }
39
+ else {
40
+ formatters.push(format.printf(logFormat(config.format)));
41
+ }
42
+ return format.combine(...formatters);
43
+ }
44
+
45
+ function createLogger (options) {
46
+ if (!options.log) {
47
+ options.log = { level: 'info' };
48
+ }
49
+ if (!options.log.transports) {
50
+ options.log.transports = {
51
+ file: {
52
+ path: 'mb.log',
53
+ format: 'json'
54
+ }
55
+ };
56
+ }
57
+
58
+ const winstonLogger = winston.createLogger({ level: options.log.level }),
59
+ logger = scopedLogger.create(winstonLogger, `[mb:${options.port}] `),
60
+ consoleConfig = options.log.transports.console,
61
+ fileConfig = options.log.transports.file;
62
+
63
+ if (consoleConfig) {
64
+ winstonLogger.add(new winston.transports.Console({
65
+ format: createWinstonFormat(winston.format, consoleConfig)
66
+ }));
67
+ }
68
+ if (fileConfig) {
69
+ initializeLogfile(fileConfig.path);
70
+ winstonLogger.add(new winston.transports.File({
71
+ filename: fileConfig.path,
72
+ maxsize: '20m',
73
+ maxFiles: 5,
74
+ tailable: true,
75
+ format: createWinstonFormat(winston.format, fileConfig)
76
+ }));
77
+ }
78
+
79
+ return logger;
80
+ }
81
+
82
+ module.exports = { createLogger };
83
+