m06_task3.js 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. package/.idea/.name +1 -0
  2. package/.idea/inspectionProfiles/Project_Default.xml +10 -0
  3. package/.idea/jsLibraryMappings.xml +6 -0
  4. package/.idea/modules.xml +8 -0
  5. package/.idea/node_lab_6.iml +12 -0
  6. package/06_task2.html +73 -0
  7. package/06_task2.js +52 -0
  8. package/06_task3.js +3 -0
  9. package/06_task4.js +3 -0
  10. package/m06_task3.js +28 -0
  11. package/package/index.js +28 -0
  12. package/package/node_modules/.package-lock.json +31 -0
  13. package/package/node_modules/@types/node/LICENSE +21 -0
  14. package/package/node_modules/@types/node/README.md +16 -0
  15. package/package/node_modules/@types/node/assert/strict.d.ts +8 -0
  16. package/package/node_modules/@types/node/assert.d.ts +961 -0
  17. package/package/node_modules/@types/node/async_hooks.d.ts +501 -0
  18. package/package/node_modules/@types/node/buffer.d.ts +2258 -0
  19. package/package/node_modules/@types/node/child_process.d.ts +1369 -0
  20. package/package/node_modules/@types/node/cluster.d.ts +410 -0
  21. package/package/node_modules/@types/node/console.d.ts +412 -0
  22. package/package/node_modules/@types/node/constants.d.ts +18 -0
  23. package/package/node_modules/@types/node/crypto.d.ts +3964 -0
  24. package/package/node_modules/@types/node/dgram.d.ts +545 -0
  25. package/package/node_modules/@types/node/diagnostics_channel.d.ts +153 -0
  26. package/package/node_modules/@types/node/dns/promises.d.ts +370 -0
  27. package/package/node_modules/@types/node/dns.d.ts +659 -0
  28. package/package/node_modules/@types/node/dom-events.d.ts +126 -0
  29. package/package/node_modules/@types/node/domain.d.ts +170 -0
  30. package/package/node_modules/@types/node/events.d.ts +678 -0
  31. package/package/node_modules/@types/node/fs/promises.d.ts +1138 -0
  32. package/package/node_modules/@types/node/fs.d.ts +3872 -0
  33. package/package/node_modules/@types/node/globals.d.ts +300 -0
  34. package/package/node_modules/@types/node/globals.global.d.ts +1 -0
  35. package/package/node_modules/@types/node/http.d.ts +1614 -0
  36. package/package/node_modules/@types/node/http2.d.ts +2134 -0
  37. package/package/node_modules/@types/node/https.d.ts +541 -0
  38. package/package/node_modules/@types/node/index.d.ts +133 -0
  39. package/package/node_modules/@types/node/inspector.d.ts +2741 -0
  40. package/package/node_modules/@types/node/module.d.ts +114 -0
  41. package/package/node_modules/@types/node/net.d.ts +869 -0
  42. package/package/node_modules/@types/node/os.d.ts +466 -0
  43. package/package/node_modules/@types/node/package.json +232 -0
  44. package/package/node_modules/@types/node/path.d.ts +191 -0
  45. package/package/node_modules/@types/node/perf_hooks.d.ts +625 -0
  46. package/package/node_modules/@types/node/process.d.ts +1482 -0
  47. package/package/node_modules/@types/node/punycode.d.ts +117 -0
  48. package/package/node_modules/@types/node/querystring.d.ts +131 -0
  49. package/package/node_modules/@types/node/readline/promises.d.ts +143 -0
  50. package/package/node_modules/@types/node/readline.d.ts +653 -0
  51. package/package/node_modules/@types/node/repl.d.ts +424 -0
  52. package/package/node_modules/@types/node/stream/consumers.d.ts +12 -0
  53. package/package/node_modules/@types/node/stream/promises.d.ts +42 -0
  54. package/package/node_modules/@types/node/stream/web.d.ts +330 -0
  55. package/package/node_modules/@types/node/stream.d.ts +1340 -0
  56. package/package/node_modules/@types/node/string_decoder.d.ts +67 -0
  57. package/package/node_modules/@types/node/test.d.ts +314 -0
  58. package/package/node_modules/@types/node/timers/promises.d.ts +68 -0
  59. package/package/node_modules/@types/node/timers.d.ts +94 -0
  60. package/package/node_modules/@types/node/tls.d.ts +1028 -0
  61. package/package/node_modules/@types/node/trace_events.d.ts +171 -0
  62. package/package/node_modules/@types/node/ts4.8/assert/strict.d.ts +8 -0
  63. package/package/node_modules/@types/node/ts4.8/assert.d.ts +961 -0
  64. package/package/node_modules/@types/node/ts4.8/async_hooks.d.ts +501 -0
  65. package/package/node_modules/@types/node/ts4.8/buffer.d.ts +2259 -0
  66. package/package/node_modules/@types/node/ts4.8/child_process.d.ts +1369 -0
  67. package/package/node_modules/@types/node/ts4.8/cluster.d.ts +410 -0
  68. package/package/node_modules/@types/node/ts4.8/console.d.ts +412 -0
  69. package/package/node_modules/@types/node/ts4.8/constants.d.ts +18 -0
  70. package/package/node_modules/@types/node/ts4.8/crypto.d.ts +3964 -0
  71. package/package/node_modules/@types/node/ts4.8/dgram.d.ts +545 -0
  72. package/package/node_modules/@types/node/ts4.8/diagnostics_channel.d.ts +153 -0
  73. package/package/node_modules/@types/node/ts4.8/dns/promises.d.ts +370 -0
  74. package/package/node_modules/@types/node/ts4.8/dns.d.ts +659 -0
  75. package/package/node_modules/@types/node/ts4.8/dom-events.d.ts +126 -0
  76. package/package/node_modules/@types/node/ts4.8/domain.d.ts +170 -0
  77. package/package/node_modules/@types/node/ts4.8/events.d.ts +678 -0
  78. package/package/node_modules/@types/node/ts4.8/fs/promises.d.ts +1138 -0
  79. package/package/node_modules/@types/node/ts4.8/fs.d.ts +3872 -0
  80. package/package/node_modules/@types/node/ts4.8/globals.d.ts +294 -0
  81. package/package/node_modules/@types/node/ts4.8/globals.global.d.ts +1 -0
  82. package/package/node_modules/@types/node/ts4.8/http.d.ts +1614 -0
  83. package/package/node_modules/@types/node/ts4.8/http2.d.ts +2134 -0
  84. package/package/node_modules/@types/node/ts4.8/https.d.ts +541 -0
  85. package/package/node_modules/@types/node/ts4.8/index.d.ts +88 -0
  86. package/package/node_modules/@types/node/ts4.8/inspector.d.ts +2741 -0
  87. package/package/node_modules/@types/node/ts4.8/module.d.ts +114 -0
  88. package/package/node_modules/@types/node/ts4.8/net.d.ts +869 -0
  89. package/package/node_modules/@types/node/ts4.8/os.d.ts +466 -0
  90. package/package/node_modules/@types/node/ts4.8/path.d.ts +191 -0
  91. package/package/node_modules/@types/node/ts4.8/perf_hooks.d.ts +625 -0
  92. package/package/node_modules/@types/node/ts4.8/process.d.ts +1482 -0
  93. package/package/node_modules/@types/node/ts4.8/punycode.d.ts +117 -0
  94. package/package/node_modules/@types/node/ts4.8/querystring.d.ts +131 -0
  95. package/package/node_modules/@types/node/ts4.8/readline/promises.d.ts +143 -0
  96. package/package/node_modules/@types/node/ts4.8/readline.d.ts +653 -0
  97. package/package/node_modules/@types/node/ts4.8/repl.d.ts +424 -0
  98. package/package/node_modules/@types/node/ts4.8/stream/consumers.d.ts +12 -0
  99. package/package/node_modules/@types/node/ts4.8/stream/promises.d.ts +42 -0
  100. package/package/node_modules/@types/node/ts4.8/stream/web.d.ts +330 -0
  101. package/package/node_modules/@types/node/ts4.8/stream.d.ts +1340 -0
  102. package/package/node_modules/@types/node/ts4.8/string_decoder.d.ts +67 -0
  103. package/package/node_modules/@types/node/ts4.8/test.d.ts +314 -0
  104. package/package/node_modules/@types/node/ts4.8/timers/promises.d.ts +68 -0
  105. package/package/node_modules/@types/node/ts4.8/timers.d.ts +94 -0
  106. package/package/node_modules/@types/node/ts4.8/tls.d.ts +1028 -0
  107. package/package/node_modules/@types/node/ts4.8/trace_events.d.ts +171 -0
  108. package/package/node_modules/@types/node/ts4.8/tty.d.ts +206 -0
  109. package/package/node_modules/@types/node/ts4.8/url.d.ts +897 -0
  110. package/package/node_modules/@types/node/ts4.8/util.d.ts +1850 -0
  111. package/package/node_modules/@types/node/ts4.8/v8.d.ts +396 -0
  112. package/package/node_modules/@types/node/ts4.8/vm.d.ts +509 -0
  113. package/package/node_modules/@types/node/ts4.8/wasi.d.ts +158 -0
  114. package/package/node_modules/@types/node/ts4.8/worker_threads.d.ts +689 -0
  115. package/package/node_modules/@types/node/ts4.8/zlib.d.ts +517 -0
  116. package/package/node_modules/@types/node/tty.d.ts +206 -0
  117. package/package/node_modules/@types/node/url.d.ts +897 -0
  118. package/package/node_modules/@types/node/util.d.ts +1850 -0
  119. package/package/node_modules/@types/node/v8.d.ts +396 -0
  120. package/package/node_modules/@types/node/vm.d.ts +509 -0
  121. package/package/node_modules/@types/node/wasi.d.ts +158 -0
  122. package/package/node_modules/@types/node/worker_threads.d.ts +689 -0
  123. package/package/node_modules/@types/node/zlib.d.ts +517 -0
  124. package/package/node_modules/@types/nodemailer/LICENSE +21 -0
  125. package/package/node_modules/@types/nodemailer/README.md +16 -0
  126. package/package/node_modules/@types/nodemailer/index.d.ts +83 -0
  127. package/package/node_modules/@types/nodemailer/lib/addressparser/index.d.ts +31 -0
  128. package/package/node_modules/@types/nodemailer/lib/base64/index.d.ts +22 -0
  129. package/package/node_modules/@types/nodemailer/lib/dkim/index.d.ts +45 -0
  130. package/package/node_modules/@types/nodemailer/lib/dkim/message-parser.d.ts +75 -0
  131. package/package/node_modules/@types/nodemailer/lib/dkim/relaxed-body.d.ts +75 -0
  132. package/package/node_modules/@types/nodemailer/lib/dkim/sign.d.ts +11 -0
  133. package/package/node_modules/@types/nodemailer/lib/fetch/cookies.d.ts +54 -0
  134. package/package/node_modules/@types/nodemailer/lib/fetch/index.d.ts +38 -0
  135. package/package/node_modules/@types/nodemailer/lib/json-transport/index.d.ts +50 -0
  136. package/package/node_modules/@types/nodemailer/lib/mail-composer/index.d.ts +25 -0
  137. package/package/node_modules/@types/nodemailer/lib/mailer/index.d.ts +230 -0
  138. package/package/node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts +28 -0
  139. package/package/node_modules/@types/nodemailer/lib/mime-funcs/index.d.ts +87 -0
  140. package/package/node_modules/@types/nodemailer/lib/mime-funcs/mime-types.d.ts +2 -0
  141. package/package/node_modules/@types/nodemailer/lib/mime-node/index.d.ts +137 -0
  142. package/package/node_modules/@types/nodemailer/lib/mime-node/last-newline.d.ts +9 -0
  143. package/package/node_modules/@types/nodemailer/lib/qp/index.d.ts +23 -0
  144. package/package/node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts +53 -0
  145. package/package/node_modules/@types/nodemailer/lib/sendmail-transport/le-unix.d.ts +7 -0
  146. package/package/node_modules/@types/nodemailer/lib/sendmail-transport/le-windows.d.ts +7 -0
  147. package/package/node_modules/@types/nodemailer/lib/ses-transport/index.d.ts +136 -0
  148. package/package/node_modules/@types/nodemailer/lib/shared/index.d.ts +51 -0
  149. package/package/node_modules/@types/nodemailer/lib/smtp-connection/data-stream.d.ts +11 -0
  150. package/package/node_modules/@types/nodemailer/lib/smtp-connection/http-proxy-client.d.ts +11 -0
  151. package/package/node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts +254 -0
  152. package/package/node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts +90 -0
  153. package/package/node_modules/@types/nodemailer/lib/smtp-pool/pool-resource.d.ts +66 -0
  154. package/package/node_modules/@types/nodemailer/lib/smtp-transport/index.d.ts +115 -0
  155. package/package/node_modules/@types/nodemailer/lib/stream-transport/index.d.ts +56 -0
  156. package/package/node_modules/@types/nodemailer/lib/well-known/index.d.ts +6 -0
  157. package/package/node_modules/@types/nodemailer/lib/xoauth2/index.d.ts +110 -0
  158. package/package/node_modules/@types/nodemailer/package.json +37 -0
  159. package/package/node_modules/nodemailer/.gitattributes +6 -0
  160. package/package/node_modules/nodemailer/.prettierrc.js +8 -0
  161. package/package/node_modules/nodemailer/CHANGELOG.md +715 -0
  162. package/package/node_modules/nodemailer/CODE_OF_CONDUCT.md +76 -0
  163. package/package/node_modules/nodemailer/CONTRIBUTING.md +67 -0
  164. package/package/node_modules/nodemailer/LICENSE +16 -0
  165. package/package/node_modules/nodemailer/README.md +93 -0
  166. package/package/node_modules/nodemailer/SECURITY.txt +22 -0
  167. package/package/node_modules/nodemailer/lib/addressparser/index.js +313 -0
  168. package/package/node_modules/nodemailer/lib/base64/index.js +142 -0
  169. package/package/node_modules/nodemailer/lib/dkim/index.js +251 -0
  170. package/package/node_modules/nodemailer/lib/dkim/message-parser.js +155 -0
  171. package/package/node_modules/nodemailer/lib/dkim/relaxed-body.js +154 -0
  172. package/package/node_modules/nodemailer/lib/dkim/sign.js +117 -0
  173. package/package/node_modules/nodemailer/lib/fetch/cookies.js +281 -0
  174. package/package/node_modules/nodemailer/lib/fetch/index.js +269 -0
  175. package/package/node_modules/nodemailer/lib/json-transport/index.js +82 -0
  176. package/package/node_modules/nodemailer/lib/mail-composer/index.js +558 -0
  177. package/package/node_modules/nodemailer/lib/mailer/index.js +427 -0
  178. package/package/node_modules/nodemailer/lib/mailer/mail-message.js +315 -0
  179. package/package/node_modules/nodemailer/lib/mime-funcs/index.js +619 -0
  180. package/package/node_modules/nodemailer/lib/mime-funcs/mime-types.js +2102 -0
  181. package/package/node_modules/nodemailer/lib/mime-node/index.js +1290 -0
  182. package/package/node_modules/nodemailer/lib/mime-node/last-newline.js +33 -0
  183. package/package/node_modules/nodemailer/lib/mime-node/le-unix.js +43 -0
  184. package/package/node_modules/nodemailer/lib/mime-node/le-windows.js +52 -0
  185. package/package/node_modules/nodemailer/lib/nodemailer.js +143 -0
  186. package/package/node_modules/nodemailer/lib/qp/index.js +219 -0
  187. package/package/node_modules/nodemailer/lib/sendmail-transport/index.js +210 -0
  188. package/package/node_modules/nodemailer/lib/ses-transport/index.js +349 -0
  189. package/package/node_modules/nodemailer/lib/shared/index.js +639 -0
  190. package/package/node_modules/nodemailer/lib/smtp-connection/data-stream.js +108 -0
  191. package/package/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +143 -0
  192. package/package/node_modules/nodemailer/lib/smtp-connection/index.js +1786 -0
  193. package/package/node_modules/nodemailer/lib/smtp-pool/index.js +648 -0
  194. package/package/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +253 -0
  195. package/package/node_modules/nodemailer/lib/smtp-transport/index.js +416 -0
  196. package/package/node_modules/nodemailer/lib/stream-transport/index.js +135 -0
  197. package/package/node_modules/nodemailer/lib/well-known/index.js +47 -0
  198. package/package/node_modules/nodemailer/lib/well-known/services.json +286 -0
  199. package/package/node_modules/nodemailer/lib/xoauth2/index.js +376 -0
  200. package/package/node_modules/nodemailer/package.json +46 -0
  201. package/package/node_modules/nodemailer/postinstall.js +101 -0
  202. package/package/package-lock.json +60 -0
  203. package/package/package.json +6 -0
  204. package/package.json +19 -0
@@ -0,0 +1,117 @@
1
+ 'use strict';
2
+
3
+ const punycode = require('punycode');
4
+ const mimeFuncs = require('../mime-funcs');
5
+ const crypto = require('crypto');
6
+
7
+ /**
8
+ * Returns DKIM signature header line
9
+ *
10
+ * @param {Object} headers Parsed headers object from MessageParser
11
+ * @param {String} bodyHash Base64 encoded hash of the message
12
+ * @param {Object} options DKIM options
13
+ * @param {String} options.domainName Domain name to be signed for
14
+ * @param {String} options.keySelector DKIM key selector to use
15
+ * @param {String} options.privateKey DKIM private key to use
16
+ * @return {String} Complete header line
17
+ */
18
+
19
+ module.exports = (headers, hashAlgo, bodyHash, options) => {
20
+ options = options || {};
21
+
22
+ // all listed fields from RFC4871 #5.5
23
+ let defaultFieldNames =
24
+ 'From:Sender:Reply-To:Subject:Date:Message-ID:To:' +
25
+ 'Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:' +
26
+ 'Content-Description:Resent-Date:Resent-From:Resent-Sender:' +
27
+ 'Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:' +
28
+ 'List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:' +
29
+ 'List-Owner:List-Archive';
30
+
31
+ let fieldNames = options.headerFieldNames || defaultFieldNames;
32
+
33
+ let canonicalizedHeaderData = relaxedHeaders(headers, fieldNames, options.skipFields);
34
+ let dkimHeader = generateDKIMHeader(options.domainName, options.keySelector, canonicalizedHeaderData.fieldNames, hashAlgo, bodyHash);
35
+
36
+ let signer, signature;
37
+
38
+ canonicalizedHeaderData.headers += 'dkim-signature:' + relaxedHeaderLine(dkimHeader);
39
+
40
+ signer = crypto.createSign(('rsa-' + hashAlgo).toUpperCase());
41
+ signer.update(canonicalizedHeaderData.headers);
42
+ try {
43
+ signature = signer.sign(options.privateKey, 'base64');
44
+ } catch (E) {
45
+ return false;
46
+ }
47
+
48
+ return dkimHeader + signature.replace(/(^.{73}|.{75}(?!\r?\n|\r))/g, '$&\r\n ').trim();
49
+ };
50
+
51
+ module.exports.relaxedHeaders = relaxedHeaders;
52
+
53
+ function generateDKIMHeader(domainName, keySelector, fieldNames, hashAlgo, bodyHash) {
54
+ let dkim = [
55
+ 'v=1',
56
+ 'a=rsa-' + hashAlgo,
57
+ 'c=relaxed/relaxed',
58
+ 'd=' + punycode.toASCII(domainName),
59
+ 'q=dns/txt',
60
+ 's=' + keySelector,
61
+ 'bh=' + bodyHash,
62
+ 'h=' + fieldNames
63
+ ].join('; ');
64
+
65
+ return mimeFuncs.foldLines('DKIM-Signature: ' + dkim, 76) + ';\r\n b=';
66
+ }
67
+
68
+ function relaxedHeaders(headers, fieldNames, skipFields) {
69
+ let includedFields = new Set();
70
+ let skip = new Set();
71
+ let headerFields = new Map();
72
+
73
+ (skipFields || '')
74
+ .toLowerCase()
75
+ .split(':')
76
+ .forEach(field => {
77
+ skip.add(field.trim());
78
+ });
79
+
80
+ (fieldNames || '')
81
+ .toLowerCase()
82
+ .split(':')
83
+ .filter(field => !skip.has(field.trim()))
84
+ .forEach(field => {
85
+ includedFields.add(field.trim());
86
+ });
87
+
88
+ for (let i = headers.length - 1; i >= 0; i--) {
89
+ let line = headers[i];
90
+ // only include the first value from bottom to top
91
+ if (includedFields.has(line.key) && !headerFields.has(line.key)) {
92
+ headerFields.set(line.key, relaxedHeaderLine(line.line));
93
+ }
94
+ }
95
+
96
+ let headersList = [];
97
+ let fields = [];
98
+ includedFields.forEach(field => {
99
+ if (headerFields.has(field)) {
100
+ fields.push(field);
101
+ headersList.push(field + ':' + headerFields.get(field));
102
+ }
103
+ });
104
+
105
+ return {
106
+ headers: headersList.join('\r\n') + '\r\n',
107
+ fieldNames: fields.join(':')
108
+ };
109
+ }
110
+
111
+ function relaxedHeaderLine(line) {
112
+ return line
113
+ .substr(line.indexOf(':') + 1)
114
+ .replace(/\r?\n/g, '')
115
+ .replace(/\s+/g, ' ')
116
+ .trim();
117
+ }
@@ -0,0 +1,281 @@
1
+ 'use strict';
2
+
3
+ // module to handle cookies
4
+
5
+ const urllib = require('url');
6
+
7
+ const SESSION_TIMEOUT = 1800; // 30 min
8
+
9
+ /**
10
+ * Creates a biskviit cookie jar for managing cookie values in memory
11
+ *
12
+ * @constructor
13
+ * @param {Object} [options] Optional options object
14
+ */
15
+ class Cookies {
16
+ constructor(options) {
17
+ this.options = options || {};
18
+ this.cookies = [];
19
+ }
20
+
21
+ /**
22
+ * Stores a cookie string to the cookie storage
23
+ *
24
+ * @param {String} cookieStr Value from the 'Set-Cookie:' header
25
+ * @param {String} url Current URL
26
+ */
27
+ set(cookieStr, url) {
28
+ let urlparts = urllib.parse(url || '');
29
+ let cookie = this.parse(cookieStr);
30
+ let domain;
31
+
32
+ if (cookie.domain) {
33
+ domain = cookie.domain.replace(/^\./, '');
34
+
35
+ // do not allow cross origin cookies
36
+ if (
37
+ // can't be valid if the requested domain is shorter than current hostname
38
+ urlparts.hostname.length < domain.length ||
39
+ // prefix domains with dot to be sure that partial matches are not used
40
+ ('.' + urlparts.hostname).substr(-domain.length + 1) !== '.' + domain
41
+ ) {
42
+ cookie.domain = urlparts.hostname;
43
+ }
44
+ } else {
45
+ cookie.domain = urlparts.hostname;
46
+ }
47
+
48
+ if (!cookie.path) {
49
+ cookie.path = this.getPath(urlparts.pathname);
50
+ }
51
+
52
+ // if no expire date, then use sessionTimeout value
53
+ if (!cookie.expires) {
54
+ cookie.expires = new Date(Date.now() + (Number(this.options.sessionTimeout || SESSION_TIMEOUT) || SESSION_TIMEOUT) * 1000);
55
+ }
56
+
57
+ return this.add(cookie);
58
+ }
59
+
60
+ /**
61
+ * Returns cookie string for the 'Cookie:' header.
62
+ *
63
+ * @param {String} url URL to check for
64
+ * @returns {String} Cookie header or empty string if no matches were found
65
+ */
66
+ get(url) {
67
+ return this.list(url)
68
+ .map(cookie => cookie.name + '=' + cookie.value)
69
+ .join('; ');
70
+ }
71
+
72
+ /**
73
+ * Lists all valied cookie objects for the specified URL
74
+ *
75
+ * @param {String} url URL to check for
76
+ * @returns {Array} An array of cookie objects
77
+ */
78
+ list(url) {
79
+ let result = [];
80
+ let i;
81
+ let cookie;
82
+
83
+ for (i = this.cookies.length - 1; i >= 0; i--) {
84
+ cookie = this.cookies[i];
85
+
86
+ if (this.isExpired(cookie)) {
87
+ this.cookies.splice(i, i);
88
+ continue;
89
+ }
90
+
91
+ if (this.match(cookie, url)) {
92
+ result.unshift(cookie);
93
+ }
94
+ }
95
+
96
+ return result;
97
+ }
98
+
99
+ /**
100
+ * Parses cookie string from the 'Set-Cookie:' header
101
+ *
102
+ * @param {String} cookieStr String from the 'Set-Cookie:' header
103
+ * @returns {Object} Cookie object
104
+ */
105
+ parse(cookieStr) {
106
+ let cookie = {};
107
+
108
+ (cookieStr || '')
109
+ .toString()
110
+ .split(';')
111
+ .forEach(cookiePart => {
112
+ let valueParts = cookiePart.split('=');
113
+ let key = valueParts.shift().trim().toLowerCase();
114
+ let value = valueParts.join('=').trim();
115
+ let domain;
116
+
117
+ if (!key) {
118
+ // skip empty parts
119
+ return;
120
+ }
121
+
122
+ switch (key) {
123
+ case 'expires':
124
+ value = new Date(value);
125
+ // ignore date if can not parse it
126
+ if (value.toString() !== 'Invalid Date') {
127
+ cookie.expires = value;
128
+ }
129
+ break;
130
+
131
+ case 'path':
132
+ cookie.path = value;
133
+ break;
134
+
135
+ case 'domain':
136
+ domain = value.toLowerCase();
137
+ if (domain.length && domain.charAt(0) !== '.') {
138
+ domain = '.' + domain; // ensure preceeding dot for user set domains
139
+ }
140
+ cookie.domain = domain;
141
+ break;
142
+
143
+ case 'max-age':
144
+ cookie.expires = new Date(Date.now() + (Number(value) || 0) * 1000);
145
+ break;
146
+
147
+ case 'secure':
148
+ cookie.secure = true;
149
+ break;
150
+
151
+ case 'httponly':
152
+ cookie.httponly = true;
153
+ break;
154
+
155
+ default:
156
+ if (!cookie.name) {
157
+ cookie.name = key;
158
+ cookie.value = value;
159
+ }
160
+ }
161
+ });
162
+
163
+ return cookie;
164
+ }
165
+
166
+ /**
167
+ * Checks if a cookie object is valid for a specified URL
168
+ *
169
+ * @param {Object} cookie Cookie object
170
+ * @param {String} url URL to check for
171
+ * @returns {Boolean} true if cookie is valid for specifiec URL
172
+ */
173
+ match(cookie, url) {
174
+ let urlparts = urllib.parse(url || '');
175
+
176
+ // check if hostname matches
177
+ // .foo.com also matches subdomains, foo.com does not
178
+ if (
179
+ urlparts.hostname !== cookie.domain &&
180
+ (cookie.domain.charAt(0) !== '.' || ('.' + urlparts.hostname).substr(-cookie.domain.length) !== cookie.domain)
181
+ ) {
182
+ return false;
183
+ }
184
+
185
+ // check if path matches
186
+ let path = this.getPath(urlparts.pathname);
187
+ if (path.substr(0, cookie.path.length) !== cookie.path) {
188
+ return false;
189
+ }
190
+
191
+ // check secure argument
192
+ if (cookie.secure && urlparts.protocol !== 'https:') {
193
+ return false;
194
+ }
195
+
196
+ return true;
197
+ }
198
+
199
+ /**
200
+ * Adds (or updates/removes if needed) a cookie object to the cookie storage
201
+ *
202
+ * @param {Object} cookie Cookie value to be stored
203
+ */
204
+ add(cookie) {
205
+ let i;
206
+ let len;
207
+
208
+ // nothing to do here
209
+ if (!cookie || !cookie.name) {
210
+ return false;
211
+ }
212
+
213
+ // overwrite if has same params
214
+ for (i = 0, len = this.cookies.length; i < len; i++) {
215
+ if (this.compare(this.cookies[i], cookie)) {
216
+ // check if the cookie needs to be removed instead
217
+ if (this.isExpired(cookie)) {
218
+ this.cookies.splice(i, 1); // remove expired/unset cookie
219
+ return false;
220
+ }
221
+
222
+ this.cookies[i] = cookie;
223
+ return true;
224
+ }
225
+ }
226
+
227
+ // add as new if not already expired
228
+ if (!this.isExpired(cookie)) {
229
+ this.cookies.push(cookie);
230
+ }
231
+
232
+ return true;
233
+ }
234
+
235
+ /**
236
+ * Checks if two cookie objects are the same
237
+ *
238
+ * @param {Object} a Cookie to check against
239
+ * @param {Object} b Cookie to check against
240
+ * @returns {Boolean} True, if the cookies are the same
241
+ */
242
+ compare(a, b) {
243
+ return a.name === b.name && a.path === b.path && a.domain === b.domain && a.secure === b.secure && a.httponly === a.httponly;
244
+ }
245
+
246
+ /**
247
+ * Checks if a cookie is expired
248
+ *
249
+ * @param {Object} cookie Cookie object to check against
250
+ * @returns {Boolean} True, if the cookie is expired
251
+ */
252
+ isExpired(cookie) {
253
+ return (cookie.expires && cookie.expires < new Date()) || !cookie.value;
254
+ }
255
+
256
+ /**
257
+ * Returns normalized cookie path for an URL path argument
258
+ *
259
+ * @param {String} pathname
260
+ * @returns {String} Normalized path
261
+ */
262
+ getPath(pathname) {
263
+ let path = (pathname || '/').split('/');
264
+ path.pop(); // remove filename part
265
+ path = path.join('/').trim();
266
+
267
+ // ensure path prefix /
268
+ if (path.charAt(0) !== '/') {
269
+ path = '/' + path;
270
+ }
271
+
272
+ // ensure path suffix /
273
+ if (path.substr(-1) !== '/') {
274
+ path += '/';
275
+ }
276
+
277
+ return path;
278
+ }
279
+ }
280
+
281
+ module.exports = Cookies;
@@ -0,0 +1,269 @@
1
+ 'use strict';
2
+
3
+ const http = require('http');
4
+ const https = require('https');
5
+ const urllib = require('url');
6
+ const zlib = require('zlib');
7
+ const PassThrough = require('stream').PassThrough;
8
+ const Cookies = require('./cookies');
9
+ const packageData = require('../../package.json');
10
+
11
+ const MAX_REDIRECTS = 5;
12
+
13
+ module.exports = function (url, options) {
14
+ return nmfetch(url, options);
15
+ };
16
+
17
+ module.exports.Cookies = Cookies;
18
+
19
+ function nmfetch(url, options) {
20
+ options = options || {};
21
+
22
+ options.fetchRes = options.fetchRes || new PassThrough();
23
+ options.cookies = options.cookies || new Cookies();
24
+ options.redirects = options.redirects || 0;
25
+ options.maxRedirects = isNaN(options.maxRedirects) ? MAX_REDIRECTS : options.maxRedirects;
26
+
27
+ if (options.cookie) {
28
+ [].concat(options.cookie || []).forEach(cookie => {
29
+ options.cookies.set(cookie, url);
30
+ });
31
+ options.cookie = false;
32
+ }
33
+
34
+ let fetchRes = options.fetchRes;
35
+ let parsed = urllib.parse(url);
36
+ let method = (options.method || '').toString().trim().toUpperCase() || 'GET';
37
+ let finished = false;
38
+ let cookies;
39
+ let body;
40
+
41
+ let handler = parsed.protocol === 'https:' ? https : http;
42
+
43
+ let headers = {
44
+ 'accept-encoding': 'gzip,deflate',
45
+ 'user-agent': 'nodemailer/' + packageData.version
46
+ };
47
+
48
+ Object.keys(options.headers || {}).forEach(key => {
49
+ headers[key.toLowerCase().trim()] = options.headers[key];
50
+ });
51
+
52
+ if (options.userAgent) {
53
+ headers['user-agent'] = options.userAgent;
54
+ }
55
+
56
+ if (parsed.auth) {
57
+ headers.Authorization = 'Basic ' + Buffer.from(parsed.auth).toString('base64');
58
+ }
59
+
60
+ if ((cookies = options.cookies.get(url))) {
61
+ headers.cookie = cookies;
62
+ }
63
+
64
+ if (options.body) {
65
+ if (options.contentType !== false) {
66
+ headers['Content-Type'] = options.contentType || 'application/x-www-form-urlencoded';
67
+ }
68
+
69
+ if (typeof options.body.pipe === 'function') {
70
+ // it's a stream
71
+ headers['Transfer-Encoding'] = 'chunked';
72
+ body = options.body;
73
+ body.on('error', err => {
74
+ if (finished) {
75
+ return;
76
+ }
77
+ finished = true;
78
+ err.type = 'FETCH';
79
+ err.sourceUrl = url;
80
+ fetchRes.emit('error', err);
81
+ });
82
+ } else {
83
+ if (options.body instanceof Buffer) {
84
+ body = options.body;
85
+ } else if (typeof options.body === 'object') {
86
+ try {
87
+ // encodeURIComponent can fail on invalid input (partial emoji etc.)
88
+ body = Buffer.from(
89
+ Object.keys(options.body)
90
+ .map(key => {
91
+ let value = options.body[key].toString().trim();
92
+ return encodeURIComponent(key) + '=' + encodeURIComponent(value);
93
+ })
94
+ .join('&')
95
+ );
96
+ } catch (E) {
97
+ if (finished) {
98
+ return;
99
+ }
100
+ finished = true;
101
+ E.type = 'FETCH';
102
+ E.sourceUrl = url;
103
+ fetchRes.emit('error', E);
104
+ return;
105
+ }
106
+ } else {
107
+ body = Buffer.from(options.body.toString().trim());
108
+ }
109
+
110
+ headers['Content-Type'] = options.contentType || 'application/x-www-form-urlencoded';
111
+ headers['Content-Length'] = body.length;
112
+ }
113
+ // if method is not provided, use POST instead of GET
114
+ method = (options.method || '').toString().trim().toUpperCase() || 'POST';
115
+ }
116
+
117
+ let req;
118
+ let reqOptions = {
119
+ method,
120
+ host: parsed.hostname,
121
+ path: parsed.path,
122
+ port: parsed.port ? parsed.port : parsed.protocol === 'https:' ? 443 : 80,
123
+ headers,
124
+ rejectUnauthorized: false,
125
+ agent: false
126
+ };
127
+
128
+ if (options.tls) {
129
+ Object.keys(options.tls).forEach(key => {
130
+ reqOptions[key] = options.tls[key];
131
+ });
132
+ }
133
+
134
+ try {
135
+ req = handler.request(reqOptions);
136
+ } catch (E) {
137
+ finished = true;
138
+ setImmediate(() => {
139
+ E.type = 'FETCH';
140
+ E.sourceUrl = url;
141
+ fetchRes.emit('error', E);
142
+ });
143
+ return fetchRes;
144
+ }
145
+
146
+ if (options.timeout) {
147
+ req.setTimeout(options.timeout, () => {
148
+ if (finished) {
149
+ return;
150
+ }
151
+ finished = true;
152
+ req.abort();
153
+ let err = new Error('Request Timeout');
154
+ err.type = 'FETCH';
155
+ err.sourceUrl = url;
156
+ fetchRes.emit('error', err);
157
+ });
158
+ }
159
+
160
+ req.on('error', err => {
161
+ if (finished) {
162
+ return;
163
+ }
164
+ finished = true;
165
+ err.type = 'FETCH';
166
+ err.sourceUrl = url;
167
+ fetchRes.emit('error', err);
168
+ });
169
+
170
+ req.on('response', res => {
171
+ let inflate;
172
+
173
+ if (finished) {
174
+ return;
175
+ }
176
+
177
+ switch (res.headers['content-encoding']) {
178
+ case 'gzip':
179
+ case 'deflate':
180
+ inflate = zlib.createUnzip();
181
+ break;
182
+ }
183
+
184
+ if (res.headers['set-cookie']) {
185
+ [].concat(res.headers['set-cookie'] || []).forEach(cookie => {
186
+ options.cookies.set(cookie, url);
187
+ });
188
+ }
189
+
190
+ if ([301, 302, 303, 307, 308].includes(res.statusCode) && res.headers.location) {
191
+ // redirect
192
+ options.redirects++;
193
+ if (options.redirects > options.maxRedirects) {
194
+ finished = true;
195
+ let err = new Error('Maximum redirect count exceeded');
196
+ err.type = 'FETCH';
197
+ err.sourceUrl = url;
198
+ fetchRes.emit('error', err);
199
+ req.abort();
200
+ return;
201
+ }
202
+ // redirect does not include POST body
203
+ options.method = 'GET';
204
+ options.body = false;
205
+ return nmfetch(urllib.resolve(url, res.headers.location), options);
206
+ }
207
+
208
+ fetchRes.statusCode = res.statusCode;
209
+ fetchRes.headers = res.headers;
210
+
211
+ if (res.statusCode >= 300 && !options.allowErrorResponse) {
212
+ finished = true;
213
+ let err = new Error('Invalid status code ' + res.statusCode);
214
+ err.type = 'FETCH';
215
+ err.sourceUrl = url;
216
+ fetchRes.emit('error', err);
217
+ req.abort();
218
+ return;
219
+ }
220
+
221
+ res.on('error', err => {
222
+ if (finished) {
223
+ return;
224
+ }
225
+ finished = true;
226
+ err.type = 'FETCH';
227
+ err.sourceUrl = url;
228
+ fetchRes.emit('error', err);
229
+ req.abort();
230
+ });
231
+
232
+ if (inflate) {
233
+ res.pipe(inflate).pipe(fetchRes);
234
+ inflate.on('error', err => {
235
+ if (finished) {
236
+ return;
237
+ }
238
+ finished = true;
239
+ err.type = 'FETCH';
240
+ err.sourceUrl = url;
241
+ fetchRes.emit('error', err);
242
+ req.abort();
243
+ });
244
+ } else {
245
+ res.pipe(fetchRes);
246
+ }
247
+ });
248
+
249
+ setImmediate(() => {
250
+ if (body) {
251
+ try {
252
+ if (typeof body.pipe === 'function') {
253
+ return body.pipe(req);
254
+ } else {
255
+ req.write(body);
256
+ }
257
+ } catch (err) {
258
+ finished = true;
259
+ err.type = 'FETCH';
260
+ err.sourceUrl = url;
261
+ fetchRes.emit('error', err);
262
+ return;
263
+ }
264
+ }
265
+ req.end();
266
+ });
267
+
268
+ return fetchRes;
269
+ }